gcx/backend/services/telemetry-service/src/domain/value-objects/time-window.vo.ts

65 lines
1.9 KiB
TypeScript

/**
* Value Object: TimeWindow
* Encapsulates the concept of a time window used for presence detection.
* The default window is 180 seconds (3 minutes), meaning a user is considered
* "online" if their last heartbeat was within this window.
*/
export class TimeWindow {
/** Default presence detection window: 180 seconds (3 minutes) */
static readonly DEFAULT_SECONDS = 180;
/** Minimum allowed window: 30 seconds */
static readonly MIN_SECONDS = 30;
/** Maximum allowed window: 600 seconds (10 minutes) */
static readonly MAX_SECONDS = 600;
private constructor(private readonly seconds: number) {}
static create(seconds: number = TimeWindow.DEFAULT_SECONDS): TimeWindow {
if (seconds < TimeWindow.MIN_SECONDS) {
throw new Error(`Time window must be at least ${TimeWindow.MIN_SECONDS} seconds, got ${seconds}`);
}
if (seconds > TimeWindow.MAX_SECONDS) {
throw new Error(`Time window must be at most ${TimeWindow.MAX_SECONDS} seconds, got ${seconds}`);
}
if (!Number.isInteger(seconds)) {
throw new Error('Time window must be an integer number of seconds');
}
return new TimeWindow(seconds);
}
/** Create the default 180-second window */
static default(): TimeWindow {
return new TimeWindow(TimeWindow.DEFAULT_SECONDS);
}
/** Get the window duration in seconds */
toSeconds(): number {
return this.seconds;
}
/** Get the window duration in milliseconds */
toMilliseconds(): number {
return this.seconds * 1000;
}
/** Calculate the threshold timestamp (now - window) as Unix epoch seconds */
getThresholdEpoch(): number {
return Math.floor(Date.now() / 1000) - this.seconds;
}
/** Calculate the threshold timestamp as a Date */
getThresholdDate(): Date {
return new Date(Date.now() - this.toMilliseconds());
}
equals(other: TimeWindow): boolean {
return this.seconds === other.seconds;
}
toString(): string {
return `${this.seconds}s`;
}
}