Files
adam-acs/app/domain/commands/command.ts
T
Kevin L'Hereec f9e56c78b1 refactor: migrate all internal imports to package.json subpath aliases
- Add #domain, #protocol, #utils aliases to package.json imports map
- Replace all relative imports (./, ../, ../..) in app/ and
  database/mongo_migrations/ with the corresponding #alias imports,
  eliminating relative path traversal across the codebase
- Remove dead code: ConfigurationVersionModel.findByConfigurationIdentifier
  (unused, superseded by paginateVersions) and unused exception classes
  (NotFoundException, UnprocessableEntityException, DatabaseException)
  from app/exceptions/index.ts, keeping only BadRequestException
- Fix pre-existing syntax error in configuration_version.ts (mismatched
  parenthesis) that broke tsc
- Fix eqeqeq violation in configuration_service.ts and isNaN ->
  Number.isNaN in configuration_engine.ts / cwmp-1-0.ts / exchange_controller.ts
- Fix no-shadow violation in cwmp-1-0.ts EventStruct constructor
- Prettier formatting pass on touched files

Validated: tsc --noEmit clean, eslint app/ clean, full test suite green.
2026-07-22 11:45:14 +02:00

148 lines
3.8 KiB
TypeScript

import { type DeviceId } from '#domain/device/device_id'
import { type ModeType } from '#domain/shared/mode'
import { type ObjectId } from 'mongodb'
export type CommandId = string
export enum CommandType {
SET_PARAMETER_VALUES = 'SET_PARAMETER_VALUES',
GET_PARAMETER_VALUES = 'GET_PARAMETER_VALUES',
GET_PARAMETER_NAMES = 'GET_PARAMETER_NAMES',
SET_PARAMETER_ATTRIBUTES = 'SET_PARAMETER_ATTRIBUTES',
GET_PARAMETER_ATTRIBUTES = 'GET_PARAMETER_ATTRIBUTES',
DOWNLOAD = 'DOWNLOAD',
UPLOAD = 'UPLOAD',
REBOOT = 'REBOOT',
FACTORY_RESET = 'FACTORY_RESET',
SCHEDULE_INFORM = 'SCHEDULE_INFORM',
REFRESH = 'REFRESH',
}
export enum CommandStatus {
PENDING = 'PENDING',
SENT = 'SENT',
WAITING = 'WAITING',
FAILED = 'FAILED',
CANCELLED = 'CANCELLED',
COMPLETED = 'COMPLETED',
}
export enum Priority {
LOW = 0,
NORMAL = 1,
HIGH = 2,
CRITICAL = 3,
}
export type CommandParameters = Record<string, any>
export interface CommandResult {
success: boolean
data?: any
message?: string
timestamp: Date
}
export interface CommandRecord {
_id?: ObjectId
deviceIdentifier: string
mode: ModeType
action: CommandType
parameters: Record<string, any>
status: CommandStatus
createdAt: Date
updatedAt: Date
executedAt?: Date
completedAt?: Date
priority: number
}
export class Command {
private _status: CommandStatus
private _executedAt: Date | null = null
private _result: CommandResult | null = null
private _error: string | null = null
constructor(
public readonly id: CommandId,
public readonly deviceId: DeviceId,
public readonly type: CommandType,
public readonly parameters: CommandParameters = {},
public readonly priority: Priority = Priority.NORMAL,
public readonly createdAt: Date = new Date(),
status: CommandStatus = CommandStatus.PENDING
) {
this._status = status
}
public get status(): CommandStatus {
return this._status
}
public get executedAt(): Date | null {
return this._executedAt
}
public get result(): CommandResult | null {
return this._result
}
public get error(): string | null {
return this._error
}
public markAsSent(): void {
if (this._status !== CommandStatus.PENDING) {
throw new Error(`Cannot mark command as sent. Current status: ${this._status}`)
}
this._status = CommandStatus.SENT
this._executedAt = new Date()
}
public markAsWaiting(): void {
if (this._status !== CommandStatus.SENT) {
throw new Error(`Cannot mark command as waiting. Current status: ${this._status}`)
}
this._status = CommandStatus.WAITING
}
public complete(result: CommandResult): void {
if (![CommandStatus.SENT, CommandStatus.WAITING].includes(this._status)) {
throw new Error(`Cannot complete command. Current status: ${this._status}`)
}
this._status = CommandStatus.COMPLETED
this._result = result
this._executedAt = new Date()
}
public fail(error: string): void {
if (this._status === CommandStatus.COMPLETED) {
throw new Error('Cannot fail a successful command')
}
this._status = CommandStatus.FAILED
this._error = error
this._executedAt = new Date()
}
public cancel(): void {
if ([CommandStatus.COMPLETED, CommandStatus.FAILED].includes(this._status)) {
throw new Error(`Cannot cancel command with status: ${this._status}`)
}
this._status = CommandStatus.CANCELLED
}
public canExecute(): boolean {
return this._status === CommandStatus.PENDING
}
public isCompleted(): boolean {
return [CommandStatus.COMPLETED, CommandStatus.FAILED, CommandStatus.CANCELLED].includes(
this._status
)
}
public hasExpired(timeoutMinutes: number = 30): boolean {
return (Date.now() - this.createdAt.getTime()) / (1000 * 60) > timeoutMinutes
}
}