- 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.
148 lines
3.8 KiB
TypeScript
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
|
|
}
|
|
}
|