secs4js 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE.md +20 -20
  2. package/lib/core/AbstractSecsCommunicator.d.ts.map +1 -1
  3. package/lib/core/AbstractSecsCommunicator.js +9 -6
  4. package/lib/core/AbstractSecsCommunicator.js.map +1 -1
  5. package/lib/core/AbstractSecsMessage.js.map +1 -1
  6. package/lib/core/enums/HsmsSsControlType.js.map +1 -1
  7. package/lib/core/enums/RejectReason.js.map +1 -1
  8. package/lib/core/enums/SecsItemType.js.map +1 -1
  9. package/lib/core/enums/SelectStatus.js.map +1 -1
  10. package/lib/core/secs2item/AbstractSecs2Item.js.map +1 -1
  11. package/lib/core/secs2item/Secs2ItemAscii.js.map +1 -1
  12. package/lib/core/secs2item/Secs2ItemBinary.js.map +1 -1
  13. package/lib/core/secs2item/Secs2ItemBoolean.js.map +1 -1
  14. package/lib/core/secs2item/Secs2ItemFactory.js.map +1 -1
  15. package/lib/core/secs2item/Secs2ItemList.js.map +1 -1
  16. package/lib/core/secs2item/Secs2ItemNumeric.js.map +1 -1
  17. package/lib/core/secs2item/Secs2ItemParser.js.map +1 -1
  18. package/lib/gem/Clock.js.map +1 -1
  19. package/lib/gem/Gem.js.map +1 -1
  20. package/lib/helper/Secs2ItemHelper.js.map +1 -1
  21. package/lib/hsms/HsmsCommunicator.d.ts.map +1 -1
  22. package/lib/hsms/HsmsCommunicator.js +1 -1
  23. package/lib/hsms/HsmsCommunicator.js.map +1 -1
  24. package/lib/hsms/HsmsMessage.js.map +1 -1
  25. package/lib/hsms/HsmsPassiveCommunicator.js.map +1 -1
  26. package/lib/hsms/enums/HsmsControlType.js.map +1 -1
  27. package/lib/hsms/enums/RejectReason.js.map +1 -1
  28. package/lib/hsms/enums/SelectStatus.js.map +1 -1
  29. package/lib/index.d.ts +2 -1
  30. package/lib/index.js +2 -1
  31. package/lib/logging/SecsLogger.d.ts +1 -1
  32. package/lib/logging/SecsLogger.d.ts.map +1 -1
  33. package/lib/logging/SecsLogger.js +20 -9
  34. package/lib/logging/SecsLogger.js.map +1 -1
  35. package/lib/secs1/Secs1Message.js.map +1 -1
  36. package/lib/secs1/Secs1MessageBlock.js.map +1 -1
  37. package/lib/secs1/Secs1SerialCommunicator.js.map +1 -1
  38. package/lib/sml/SmlParser.js.map +1 -1
  39. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"HsmsCommunicator.js","names":[],"sources":["../../src/hsms/HsmsCommunicator.ts"],"sourcesContent":["import { Socket } from \"net\";\nimport {\n\tAbstractSecsCommunicator,\n\tSecsCommunicatorConfig,\n\tSecsCommunicatorEvents,\n} from \"../core/AbstractSecsCommunicator.js\";\nimport { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { HsmsMessage } from \"./HsmsMessage.js\";\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\nimport { SelectStatus } from \"./enums/SelectStatus.js\";\nimport { RejectReason } from \"./enums/RejectReason.js\";\n\nexport enum HsmsState {\n\tNotConnected = \"NotConnected\",\n\tConnected = \"Connected\", // TCP Connected\n\tSelected = \"Selected\", // HSMS Selected\n}\n\n/**\n * @description HsmsCommunicatorConfig is the configuration interface for HsmsCommunicator.\n * @param ip The IP address of the remote device.\n * @param port The port number of the remote device.\n * @param linkTestInterval The interval in milliseconds to send link test messages.\n */\nexport interface HsmsCommunicatorConfig extends SecsCommunicatorConfig {\n\tip: string;\n\tport: number;\n\tlinkTestInterval?: number;\n}\n\nexport interface HsmsCommunicatorEvents extends SecsCommunicatorEvents {\n\tselected: [];\n\tdeselected: [];\n}\n\nexport abstract class HsmsCommunicator extends AbstractSecsCommunicator<HsmsCommunicatorEvents> {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprotected socket: Socket | null = null;\n\tprotected state: HsmsState = HsmsState.NotConnected;\n\tprivate buffer: Buffer = Buffer.alloc(0);\n\tprivate t7Timer: NodeJS.Timeout | null = null;\n\tprivate t8Timer: NodeJS.Timeout | null = null;\n\n\t// T6 Timer (Control Transaction)\n\t// We use the same _transactions map for Control messages if they expect reply\n\n\tpublic get connectionState(): HsmsState {\n\t\treturn this.state;\n\t}\n\n\tconstructor(config: HsmsCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t}\n\n\tprotected override async sendBufferWithLogs(\n\t\tdirection: \"Sent\" | \"Received\",\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): Promise<void> {\n\t\tawait super.sendBufferWithLogs(\n\t\t\tdirection,\n\t\t\tprotocol === \"SECS\" ? \"HSMS\" : protocol,\n\t\t\tbuffer,\n\t\t\t{\n\t\t\t\thsmsState: this.state,\n\t\t\t\t...meta,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected async sendBuffer(buffer: Buffer): Promise<void> {\n\t\tconst socket = this.socket;\n\t\tif (!socket || socket.destroyed) {\n\t\t\tthrow new Error(\"Socket not connected\");\n\t\t}\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsocket.write(buffer, (err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected createMessage(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t): SecsMessage {\n\t\t// For Data messages, pType=0, sType=0 (Data)\n\t\treturn new HsmsMessage(\n\t\t\tstream,\n\t\t\tfunc,\n\t\t\twBit,\n\t\t\tbody,\n\t\t\tsystemBytes,\n\t\t\tthis.deviceId,\n\t\t\t0,\n\t\t\tHsmsControlType.Data,\n\t\t);\n\t}\n\n\tprotected handleSocketEvents(socket: Socket) {\n\t\tthis.socket = socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state, {\n\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\tremotePort: socket.remotePort,\n\t\t});\n\t\tthis.resetT7Timer();\n\t\tthis.emit(\"connected\");\n\n\t\tsocket.on(\"data\", (data) => {\n\t\t\tthis.logger.logBytes(\"Received\", \"HSMS\", data, {\n\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\tchunkLength: data.length,\n\t\t\t});\n\t\t\tthis.buffer = Buffer.concat([this.buffer, data]);\n\t\t\tthis.resetT8Timer();\n\t\t\tthis.processBuffer();\n\t\t\tif (this.buffer.length === 0) {\n\t\t\t\tthis.clearT8Timer();\n\t\t\t}\n\t\t});\n\n\t\tsocket.on(\"close\", () => {\n\t\t\tthis.rejectAllTransactions(new Error(\"Socket closed\"));\n\t\t\tthis.clearT7Timer();\n\t\t\tthis.clearT8Timer();\n\t\t\tthis.buffer = Buffer.alloc(0);\n\t\t\tconst prevState = this.state;\n\t\t\tthis.state = HsmsState.NotConnected;\n\t\t\tthis.logger.logState(\"HSMS\", prevState, this.state, {\n\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\tremotePort: socket.remotePort,\n\t\t\t});\n\t\t\tthis.socket = null;\n\t\t\tthis.emit(\"disconnected\");\n\t\t});\n\n\t\tsocket.on(\"end\", () => {\n\t\t\tif (this.socket && !this.socket.destroyed) {\n\t\t\t\tthis.socket.destroy();\n\t\t\t}\n\t\t});\n\n\t\tsocket.on(\"error\", (err) => {\n\t\t\tthis.emit(\"error\", err);\n\t\t\tif (!socket.destroyed) {\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate resetT7Timer() {\n\t\tthis.clearT7Timer();\n\t\tif (this.timeoutT7 <= 0) return;\n\t\tthis.t7Timer = setTimeout(() => {\n\t\t\tthis.t7Timer = null;\n\t\t\tif (this.state === HsmsState.Selected) return;\n\t\t\tconst socket = this.socket;\n\t\t\tif (socket && !socket.destroyed) {\n\t\t\t\tthis.emit(\"error\", new Error(\"T7 Timeout\"));\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t}, this.timeoutT7 * 1000);\n\t}\n\n\tprivate clearT7Timer() {\n\t\tif (this.t7Timer) {\n\t\t\tclearTimeout(this.t7Timer);\n\t\t\tthis.t7Timer = null;\n\t\t}\n\t}\n\n\tprivate resetT8Timer() {\n\t\tthis.clearT8Timer();\n\t\tif (this.timeoutT8 <= 0) return;\n\t\tthis.t8Timer = setTimeout(() => {\n\t\t\tthis.t8Timer = null;\n\t\t\tconst socket = this.socket;\n\t\t\tif (socket && !socket.destroyed && this.buffer.length > 0) {\n\t\t\t\tthis.emit(\"error\", new Error(\"T8 Timeout\"));\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t}, this.timeoutT8 * 1000);\n\t}\n\n\tprivate clearT8Timer() {\n\t\tif (this.t8Timer) {\n\t\t\tclearTimeout(this.t8Timer);\n\t\t\tthis.t8Timer = null;\n\t\t}\n\t}\n\n\tprivate processBuffer() {\n\t\twhile (true) {\n\t\t\tif (this.buffer.length < 4) return;\n\n\t\t\tconst length = this.buffer.readUInt32BE(0);\n\t\t\tif (length < 10) {\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tthis.emit(\"error\", new Error(\"Receive message size < 10\"));\n\t\t\t\tthis.buffer = Buffer.alloc(0);\n\t\t\t\tif (socket && !socket.destroyed) {\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.buffer.length < 4 + length) return;\n\n\t\t\tconst msgBuffer = this.buffer.subarray(0, 4 + length);\n\t\t\tthis.buffer = this.buffer.subarray(4 + length);\n\n\t\t\ttry {\n\t\t\t\tthis.logger.logBytes(\"Received\", \"HSMS\", msgBuffer, {\n\t\t\t\t\tframeLength: length,\n\t\t\t\t});\n\t\t\t\tconst msg = HsmsMessage.fromBuffer(msgBuffer);\n\t\t\t\tthis.processHsmsMessage(msg);\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tnew Error(`Failed to parse HSMS message: ${err.message}`),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tnew Error(`Failed to parse HSMS message: ${String(err)}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate processHsmsMessage(msg: HsmsMessage) {\n\t\t// Handle Control Messages\n\t\tif (msg.sType !== HsmsControlType.Data) {\n\t\t\tthis.logger.detail.debug(\n\t\t\t\t{\n\t\t\t\t\tprotocol: \"HSMS\",\n\t\t\t\t\tcontrolType: msg.sType,\n\t\t\t\t\tpType: msg.pType,\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t\tdeviceId: msg.deviceId,\n\t\t\t\t},\n\t\t\t\t\"control\",\n\t\t\t);\n\t\t\tthis.handleControlMessage(msg);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle Data Messages\n\t\tif (this.state !== HsmsState.Selected) {\n\t\t\tthis.logger.logSecs2(\"Received\", msg.toSml());\n\t\t\tvoid this.sendReject(msg, RejectReason.NotSelected);\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.handleMessage(msg);\n\t}\n\n\tprivate handleControlMessage(msg: HsmsMessage) {\n\t\tswitch (msg.sType as HsmsControlType) {\n\t\t\tcase HsmsControlType.SelectReq:\n\t\t\t\tthis.handleSelectReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.SelectRsp:\n\t\t\t\tthis.handleSelectRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.DeselectReq:\n\t\t\t\tthis.handleDeselectReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.DeselectRsp:\n\t\t\t\tthis.handleDeselectRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.LinkTestReq:\n\t\t\t\tthis.handleLinkTestReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.LinkTestRsp:\n\t\t\t\tthis.handleLinkTestRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.SeparateReq:\n\t\t\t\tthis.handleSeparateReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.RejectReq:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tvoid this.sendReject(\n\t\t\t\t\tmsg,\n\t\t\t\t\tmsg.pType !== 0\n\t\t\t\t\t\t? RejectReason.NotSupportTypeP\n\t\t\t\t\t\t: RejectReason.NotSupportTypeS,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprotected handleSelectReq(msg: HsmsMessage) {\n\t\t// Subclasses might override, but default behavior:\n\t\t// If already selected, return Actived/AlreadyUsed?\n\t\t// If not, accept.\n\n\t\t// Note: HSMS-SS says only one host.\n\t\tif (this.state === HsmsState.Selected) {\n\t\t\tvoid this.sendSelectRsp(msg, SelectStatus.Actived); // Or AlreadyUsed?\n\t\t} else {\n\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Selected, {\n\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t});\n\t\t\tthis.state = HsmsState.Selected;\n\t\t\tthis.clearT7Timer();\n\t\t\tvoid this.sendSelectRsp(msg, SelectStatus.Success);\n\t\t\tthis.emit(\"selected\");\n\t\t}\n\t}\n\n\tprotected handleSelectRsp(msg: HsmsMessage) {\n\t\t// Check if we are waiting for this.\n\t\t// Usually managed by sendSelectReq promise.\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\t// If status is Success, set state to Selected\n\t\t\t// msg.func holds the status (byte 3) if we mapped it correctly in HsmsMessage.fromBuffer\n\t\t\t// In HsmsMessage.fromBuffer, for Control msg, func = byte 3.\n\t\t\tconst status = msg.func as SelectStatus;\n\t\t\tif (status === SelectStatus.Success || status === SelectStatus.Actived) {\n\t\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Selected, {\n\t\t\t\t\tselectStatus: status,\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t});\n\t\t\t\tthis.state = HsmsState.Selected;\n\t\t\t\tthis.clearT7Timer();\n\t\t\t\tthis.emit(\"selected\");\n\t\t\t}\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleLinkTestReq(msg: HsmsMessage) {\n\t\tvoid this.sendLinkTestRsp(msg);\n\t}\n\n\tprotected handleLinkTestRsp(msg: HsmsMessage) {\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleDeselectReq(msg: HsmsMessage) {\n\t\tif (this.state === HsmsState.Selected) {\n\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Connected, {\n\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t});\n\t\t\tthis.state = HsmsState.Connected;\n\t\t\tthis.resetT7Timer();\n\t\t\tvoid this.sendDeselectRsp(msg, SelectStatus.Success);\n\t\t\tthis.emit(\"deselected\");\n\t\t\treturn;\n\t\t}\n\t\tvoid this.sendDeselectRsp(msg, SelectStatus.NotReady);\n\t}\n\n\tprotected handleDeselectRsp(msg: HsmsMessage) {\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\tconst status = msg.func as SelectStatus;\n\t\t\tif (status === SelectStatus.Success) {\n\t\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Connected, {\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t});\n\t\t\t\tthis.state = HsmsState.Connected;\n\t\t\t\tthis.resetT7Timer();\n\t\t\t\tthis.emit(\"deselected\");\n\t\t\t}\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleSeparateReq(_msg: HsmsMessage) {\n\t\tconst socket = this.socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state);\n\t\tthis.clearT7Timer();\n\t\tif (socket && !socket.destroyed) {\n\t\t\tsocket.destroy();\n\t\t}\n\t}\n\n\t// Helper senders\n\tprotected async sendSelectRsp(req: HsmsMessage, status: number) {\n\t\tconst rsp = HsmsMessage.selectRsp(req, status);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.SelectRsp,\n\t\t\tstatus,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendDeselectRsp(req: HsmsMessage, status: number) {\n\t\tconst rsp = HsmsMessage.deselectRsp(req, status);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.DeselectRsp,\n\t\t\tstatus,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendLinkTestRsp(req: HsmsMessage) {\n\t\tconst rsp = HsmsMessage.linkTestRsp(req);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.LinkTestRsp,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendReject(req: HsmsMessage, reason: RejectReason) {\n\t\tconst rsp = HsmsMessage.rejectReq(req, reason);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.RejectReq,\n\t\t\treason,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\toverride async send(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null = null,\n\t): Promise<SecsMessage | null> {\n\t\tif (this.state !== HsmsState.Selected) {\n\t\t\tthrow new Error(\"HSMS not selected\");\n\t\t}\n\t\treturn super.send(stream, func, wBit, body);\n\t}\n\n\t// Public control methods\n\tpublic async sendSelectReq(): Promise<SelectStatus> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.selectReq(systemBytes);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tif (socket && !socket.destroyed) socket.destroy();\n\t\t\t\treject(new Error(\"T6 Timeout waiting for Select Rsp\"));\n\t\t\t}, this.timeoutT6 * 1000);\n\n\t\t\tthis._transactions.set(systemBytes, {\n\t\t\t\tresolve: (rsp) => {\n\t\t\t\t\tresolve(rsp.func as SelectStatus);\n\t\t\t\t},\n\t\t\t\treject,\n\t\t\t\ttimer,\n\t\t\t});\n\n\t\t\tthis.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\t\tcontrolType: HsmsControlType.SelectReq,\n\t\t\t\tsystemBytes,\n\t\t\t}).catch((err: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async sendLinkTestReq(): Promise<void> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.linkTestReq(systemBytes);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tif (socket && !socket.destroyed) socket.destroy();\n\t\t\t\treject(new Error(\"T6 Timeout waiting for LinkTest Rsp\"));\n\t\t\t}, this.timeoutT6 * 1000);\n\n\t\t\tthis._transactions.set(systemBytes, {\n\t\t\t\tresolve: () => {\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject,\n\t\t\t\ttimer,\n\t\t\t});\n\n\t\t\tthis.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\t\tcontrolType: HsmsControlType.LinkTestReq,\n\t\t\t\tsystemBytes,\n\t\t\t}).catch((err: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async sendSeparateReq(): Promise<void> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.separateReq(systemBytes);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.SeparateReq,\n\t\t\tsystemBytes,\n\t\t});\n\t\tconst socket = this.socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state, { systemBytes });\n\t\tthis.clearT7Timer();\n\t\tif (socket && !socket.destroyed) {\n\t\t\tsocket.destroy();\n\t\t}\n\t}\n\n\tprivate rejectAllTransactions(err: Error) {\n\t\tfor (const [systemBytes, tx] of this._transactions) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\ttx.reject(err);\n\t\t\tthis._transactions.delete(systemBytes);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HsmsCommunicator.js","names":[],"sources":["../../src/hsms/HsmsCommunicator.ts"],"sourcesContent":["import { Socket } from \"net\";\nimport {\n\tAbstractSecsCommunicator,\n\tSecsCommunicatorConfig,\n\tSecsCommunicatorEvents,\n} from \"../core/AbstractSecsCommunicator.js\";\nimport { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { HsmsMessage } from \"./HsmsMessage.js\";\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\nimport { SelectStatus } from \"./enums/SelectStatus.js\";\nimport { RejectReason } from \"./enums/RejectReason.js\";\n\nexport enum HsmsState {\n\tNotConnected = \"NotConnected\",\n\tConnected = \"Connected\", // TCP Connected\n\tSelected = \"Selected\", // HSMS Selected\n}\n\n/**\n * @description HsmsCommunicatorConfig is the configuration interface for HsmsCommunicator.\n * @param ip The IP address of the remote device.\n * @param port The port number of the remote device.\n * @param linkTestInterval The interval in milliseconds to send link test messages.\n */\nexport interface HsmsCommunicatorConfig extends SecsCommunicatorConfig {\n\tip: string;\n\tport: number;\n\tlinkTestInterval?: number;\n}\n\nexport interface HsmsCommunicatorEvents extends SecsCommunicatorEvents {\n\tselected: [];\n\tdeselected: [];\n}\n\nexport abstract class HsmsCommunicator extends AbstractSecsCommunicator<HsmsCommunicatorEvents> {\n\tpublic ip: string;\n\tpublic port: number;\n\n\tprotected socket: Socket | null = null;\n\tprotected state: HsmsState = HsmsState.NotConnected;\n\tprivate buffer: Buffer = Buffer.alloc(0);\n\tprivate t7Timer: NodeJS.Timeout | null = null;\n\tprivate t8Timer: NodeJS.Timeout | null = null;\n\n\t// T6 Timer (Control Transaction)\n\t// We use the same _transactions map for Control messages if they expect reply\n\n\tpublic get connectionState(): HsmsState {\n\t\treturn this.state;\n\t}\n\n\tconstructor(config: HsmsCommunicatorConfig) {\n\t\tsuper(config);\n\t\tthis.ip = config.ip;\n\t\tthis.port = config.port;\n\t}\n\n\tprotected override async sendBufferWithLogs(\n\t\tdirection: \"Sent\" | \"Received\",\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): Promise<void> {\n\t\tawait super.sendBufferWithLogs(\n\t\t\tdirection,\n\t\t\tprotocol === \"SECS\" ? \"HSMS\" : protocol,\n\t\t\tbuffer,\n\t\t\t{\n\t\t\t\thsmsState: this.state,\n\t\t\t\t...meta,\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected async sendBuffer(buffer: Buffer): Promise<void> {\n\t\tconst socket = this.socket;\n\t\tif (!socket || socket.destroyed) {\n\t\t\tthrow new Error(\"Socket not connected\");\n\t\t}\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsocket.write(buffer, (err) => {\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected createMessage(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t): SecsMessage {\n\t\t// For Data messages, pType=0, sType=0 (Data)\n\t\treturn new HsmsMessage(\n\t\t\tstream,\n\t\t\tfunc,\n\t\t\twBit,\n\t\t\tbody,\n\t\t\tsystemBytes,\n\t\t\tthis.deviceId,\n\t\t\t0,\n\t\t\tHsmsControlType.Data,\n\t\t);\n\t}\n\n\tprotected handleSocketEvents(socket: Socket) {\n\t\tthis.socket = socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state, {\n\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\tremotePort: socket.remotePort,\n\t\t});\n\t\tthis.resetT7Timer();\n\t\tthis.emit(\"connected\");\n\n\t\tsocket.on(\"data\", (data) => {\n\t\t\tthis.logger.logBytes(\"Received\", \"HSMS\", data, {\n\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\tremotePort: socket.remotePort,\n\t\t\t\tchunkLength: data.length,\n\t\t\t});\n\t\t\tthis.buffer = Buffer.concat([this.buffer, data]);\n\t\t\tthis.resetT8Timer();\n\t\t\tthis.processBuffer();\n\t\t\tif (this.buffer.length === 0) {\n\t\t\t\tthis.clearT8Timer();\n\t\t\t}\n\t\t});\n\n\t\tsocket.on(\"close\", () => {\n\t\t\tthis.rejectAllTransactions(new Error(\"Socket closed\"));\n\t\t\tthis.clearT7Timer();\n\t\t\tthis.clearT8Timer();\n\t\t\tthis.buffer = Buffer.alloc(0);\n\t\t\tconst prevState = this.state;\n\t\t\tthis.state = HsmsState.NotConnected;\n\t\t\tthis.logger.logState(\"HSMS\", prevState, this.state, {\n\t\t\t\tremoteAddress: socket.remoteAddress,\n\t\t\t\tremotePort: socket.remotePort,\n\t\t\t});\n\t\t\tthis.socket = null;\n\t\t\tthis.emit(\"disconnected\");\n\t\t});\n\n\t\tsocket.on(\"end\", () => {\n\t\t\tif (this.socket && !this.socket.destroyed) {\n\t\t\t\tthis.socket.destroy();\n\t\t\t}\n\t\t});\n\n\t\tsocket.on(\"error\", (err) => {\n\t\t\tthis.emit(\"error\", err);\n\t\t\tif (!socket.destroyed) {\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate resetT7Timer() {\n\t\tthis.clearT7Timer();\n\t\tif (this.timeoutT7 <= 0) return;\n\t\tthis.t7Timer = setTimeout(() => {\n\t\t\tthis.t7Timer = null;\n\t\t\tif (this.state === HsmsState.Selected) return;\n\t\t\tconst socket = this.socket;\n\t\t\tif (socket && !socket.destroyed) {\n\t\t\t\tthis.emit(\"error\", new Error(\"T7 Timeout\"));\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t}, this.timeoutT7 * 1000);\n\t}\n\n\tprivate clearT7Timer() {\n\t\tif (this.t7Timer) {\n\t\t\tclearTimeout(this.t7Timer);\n\t\t\tthis.t7Timer = null;\n\t\t}\n\t}\n\n\tprivate resetT8Timer() {\n\t\tthis.clearT8Timer();\n\t\tif (this.timeoutT8 <= 0) return;\n\t\tthis.t8Timer = setTimeout(() => {\n\t\t\tthis.t8Timer = null;\n\t\t\tconst socket = this.socket;\n\t\t\tif (socket && !socket.destroyed && this.buffer.length > 0) {\n\t\t\t\tthis.emit(\"error\", new Error(\"T8 Timeout\"));\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t}, this.timeoutT8 * 1000);\n\t}\n\n\tprivate clearT8Timer() {\n\t\tif (this.t8Timer) {\n\t\t\tclearTimeout(this.t8Timer);\n\t\t\tthis.t8Timer = null;\n\t\t}\n\t}\n\n\tprivate processBuffer() {\n\t\twhile (true) {\n\t\t\tif (this.buffer.length < 4) return;\n\n\t\t\tconst length = this.buffer.readUInt32BE(0);\n\t\t\tif (length < 10) {\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tthis.emit(\"error\", new Error(\"Receive message size < 10\"));\n\t\t\t\tthis.buffer = Buffer.alloc(0);\n\t\t\t\tif (socket && !socket.destroyed) {\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.buffer.length < 4 + length) return;\n\n\t\t\tconst msgBuffer = this.buffer.subarray(0, 4 + length);\n\t\t\tthis.buffer = this.buffer.subarray(4 + length);\n\n\t\t\ttry {\n\t\t\t\tthis.logger.logBytes(\"Received\", \"HSMS\", msgBuffer, {\n\t\t\t\t\tframeLength: length,\n\t\t\t\t});\n\t\t\t\tconst msg = HsmsMessage.fromBuffer(msgBuffer);\n\t\t\t\tthis.processHsmsMessage(msg);\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tnew Error(`Failed to parse HSMS message: ${err.message}`),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tnew Error(`Failed to parse HSMS message: ${String(err)}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate processHsmsMessage(msg: HsmsMessage) {\n\t\t// Handle Control Messages\n\t\tif (msg.sType !== HsmsControlType.Data) {\n\t\t\tthis.logger.detail.debug(\n\t\t\t\t{\n\t\t\t\t\tprotocol: \"HSMS\",\n\t\t\t\t\tcontrolType: msg.sType,\n\t\t\t\t\tpType: msg.pType,\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t\tdeviceId: msg.deviceId,\n\t\t\t\t},\n\t\t\t\t\"control\",\n\t\t\t);\n\t\t\tthis.handleControlMessage(msg);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle Data Messages\n\t\tif (this.state !== HsmsState.Selected) {\n\t\t\tthis.logger.logSecs2(\n\t\t\t\t\"Received\",\n\t\t\t\tmsg.toSml(),\n\t\t\t\tthis.deviceId,\n\t\t\t\tmsg.systemBytes,\n\t\t\t\tmsg.toBuffer(),\n\t\t\t);\n\t\t\tvoid this.sendReject(msg, RejectReason.NotSelected);\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.handleMessage(msg);\n\t}\n\n\tprivate handleControlMessage(msg: HsmsMessage) {\n\t\tswitch (msg.sType as HsmsControlType) {\n\t\t\tcase HsmsControlType.SelectReq:\n\t\t\t\tthis.handleSelectReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.SelectRsp:\n\t\t\t\tthis.handleSelectRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.DeselectReq:\n\t\t\t\tthis.handleDeselectReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.DeselectRsp:\n\t\t\t\tthis.handleDeselectRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.LinkTestReq:\n\t\t\t\tthis.handleLinkTestReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.LinkTestRsp:\n\t\t\t\tthis.handleLinkTestRsp(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.SeparateReq:\n\t\t\t\tthis.handleSeparateReq(msg);\n\t\t\t\tbreak;\n\t\t\tcase HsmsControlType.RejectReq:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tvoid this.sendReject(\n\t\t\t\t\tmsg,\n\t\t\t\t\tmsg.pType !== 0\n\t\t\t\t\t\t? RejectReason.NotSupportTypeP\n\t\t\t\t\t\t: RejectReason.NotSupportTypeS,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprotected handleSelectReq(msg: HsmsMessage) {\n\t\t// Subclasses might override, but default behavior:\n\t\t// If already selected, return Actived/AlreadyUsed?\n\t\t// If not, accept.\n\n\t\t// Note: HSMS-SS says only one host.\n\t\tif (this.state === HsmsState.Selected) {\n\t\t\tvoid this.sendSelectRsp(msg, SelectStatus.Actived); // Or AlreadyUsed?\n\t\t} else {\n\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Selected, {\n\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t});\n\t\t\tthis.state = HsmsState.Selected;\n\t\t\tthis.clearT7Timer();\n\t\t\tvoid this.sendSelectRsp(msg, SelectStatus.Success);\n\t\t\tthis.emit(\"selected\");\n\t\t}\n\t}\n\n\tprotected handleSelectRsp(msg: HsmsMessage) {\n\t\t// Check if we are waiting for this.\n\t\t// Usually managed by sendSelectReq promise.\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\t// If status is Success, set state to Selected\n\t\t\t// msg.func holds the status (byte 3) if we mapped it correctly in HsmsMessage.fromBuffer\n\t\t\t// In HsmsMessage.fromBuffer, for Control msg, func = byte 3.\n\t\t\tconst status = msg.func as SelectStatus;\n\t\t\tif (status === SelectStatus.Success || status === SelectStatus.Actived) {\n\t\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Selected, {\n\t\t\t\t\tselectStatus: status,\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t});\n\t\t\t\tthis.state = HsmsState.Selected;\n\t\t\t\tthis.clearT7Timer();\n\t\t\t\tthis.emit(\"selected\");\n\t\t\t}\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleLinkTestReq(msg: HsmsMessage) {\n\t\tvoid this.sendLinkTestRsp(msg);\n\t}\n\n\tprotected handleLinkTestRsp(msg: HsmsMessage) {\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleDeselectReq(msg: HsmsMessage) {\n\t\tif (this.state === HsmsState.Selected) {\n\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Connected, {\n\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t});\n\t\t\tthis.state = HsmsState.Connected;\n\t\t\tthis.resetT7Timer();\n\t\t\tvoid this.sendDeselectRsp(msg, SelectStatus.Success);\n\t\t\tthis.emit(\"deselected\");\n\t\t\treturn;\n\t\t}\n\t\tvoid this.sendDeselectRsp(msg, SelectStatus.NotReady);\n\t}\n\n\tprotected handleDeselectRsp(msg: HsmsMessage) {\n\t\tconst tx = this._transactions.get(msg.systemBytes);\n\t\tif (tx) {\n\t\t\tconst status = msg.func as SelectStatus;\n\t\t\tif (status === SelectStatus.Success) {\n\t\t\t\tthis.logger.logState(\"HSMS\", this.state, HsmsState.Connected, {\n\t\t\t\t\tsystemBytes: msg.systemBytes,\n\t\t\t\t});\n\t\t\t\tthis.state = HsmsState.Connected;\n\t\t\t\tthis.resetT7Timer();\n\t\t\t\tthis.emit(\"deselected\");\n\t\t\t}\n\t\t\tclearTimeout(tx.timer);\n\t\t\tthis._transactions.delete(msg.systemBytes);\n\t\t\ttx.resolve(msg);\n\t\t} else {\n\t\t\tvoid this.sendReject(msg, RejectReason.TransactionNotOpen);\n\t\t}\n\t}\n\n\tprotected handleSeparateReq(_msg: HsmsMessage) {\n\t\tconst socket = this.socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state);\n\t\tthis.clearT7Timer();\n\t\tif (socket && !socket.destroyed) {\n\t\t\tsocket.destroy();\n\t\t}\n\t}\n\n\t// Helper senders\n\tprotected async sendSelectRsp(req: HsmsMessage, status: number) {\n\t\tconst rsp = HsmsMessage.selectRsp(req, status);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.SelectRsp,\n\t\t\tstatus,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendDeselectRsp(req: HsmsMessage, status: number) {\n\t\tconst rsp = HsmsMessage.deselectRsp(req, status);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.DeselectRsp,\n\t\t\tstatus,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendLinkTestRsp(req: HsmsMessage) {\n\t\tconst rsp = HsmsMessage.linkTestRsp(req);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.LinkTestRsp,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\tprotected async sendReject(req: HsmsMessage, reason: RejectReason) {\n\t\tconst rsp = HsmsMessage.rejectReq(req, reason);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", rsp.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.RejectReq,\n\t\t\treason,\n\t\t\tsystemBytes: rsp.systemBytes,\n\t\t});\n\t}\n\n\toverride async send(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null = null,\n\t): Promise<SecsMessage | null> {\n\t\tif (this.state !== HsmsState.Selected) {\n\t\t\tthrow new Error(\"HSMS not selected\");\n\t\t}\n\t\treturn super.send(stream, func, wBit, body);\n\t}\n\n\t// Public control methods\n\tpublic async sendSelectReq(): Promise<SelectStatus> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.selectReq(systemBytes);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tif (socket && !socket.destroyed) socket.destroy();\n\t\t\t\treject(new Error(\"T6 Timeout waiting for Select Rsp\"));\n\t\t\t}, this.timeoutT6 * 1000);\n\n\t\t\tthis._transactions.set(systemBytes, {\n\t\t\t\tresolve: (rsp) => {\n\t\t\t\t\tresolve(rsp.func as SelectStatus);\n\t\t\t\t},\n\t\t\t\treject,\n\t\t\t\ttimer,\n\t\t\t});\n\n\t\t\tthis.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\t\tcontrolType: HsmsControlType.SelectReq,\n\t\t\t\tsystemBytes,\n\t\t\t}).catch((err: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async sendLinkTestReq(): Promise<void> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.linkTestReq(systemBytes);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\tconst socket = this.socket;\n\t\t\t\tif (socket && !socket.destroyed) socket.destroy();\n\t\t\t\treject(new Error(\"T6 Timeout waiting for LinkTest Rsp\"));\n\t\t\t}, this.timeoutT6 * 1000);\n\n\t\t\tthis._transactions.set(systemBytes, {\n\t\t\t\tresolve: () => {\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject,\n\t\t\t\ttimer,\n\t\t\t});\n\n\t\t\tthis.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\t\tcontrolType: HsmsControlType.LinkTestReq,\n\t\t\t\tsystemBytes,\n\t\t\t}).catch((err: unknown) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tthis._transactions.delete(systemBytes);\n\t\t\t\treject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async sendSeparateReq(): Promise<void> {\n\t\tconst systemBytes = this.getNextSystemBytes();\n\t\tconst msg = HsmsMessage.separateReq(systemBytes);\n\t\tawait this.sendBufferWithLogs(\"Sent\", \"HSMS\", msg.toBuffer(), {\n\t\t\tcontrolType: HsmsControlType.SeparateReq,\n\t\t\tsystemBytes,\n\t\t});\n\t\tconst socket = this.socket;\n\t\tconst prev = this.state;\n\t\tthis.state = HsmsState.Connected;\n\t\tthis.logger.logState(\"HSMS\", prev, this.state, { systemBytes });\n\t\tthis.clearT7Timer();\n\t\tif (socket && !socket.destroyed) {\n\t\t\tsocket.destroy();\n\t\t}\n\t}\n\n\tprivate rejectAllTransactions(err: Error) {\n\t\tfor (const [systemBytes, tx] of this._transactions) {\n\t\t\tclearTimeout(tx.timer);\n\t\t\ttx.reject(err);\n\t\t\tthis._transactions.delete(systemBytes);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HsmsMessage.js","names":["body: AbstractSecs2Item | null"],"sources":["../../src/hsms/HsmsMessage.ts"],"sourcesContent":["import { SecsMessage } from \"../core/AbstractSecsMessage.js\";\r\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\r\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\r\nimport { RejectReason } from \"./enums/RejectReason.js\";\r\nimport { Secs2ItemParser } from \"../core/secs2item/Secs2ItemParser.js\";\r\n\r\n/**\r\n * @description HsmsMessage is the class that represents an HSMS message.\r\n * @param stream The stream number of the message.\r\n * @param func The function number of the message.\r\n * @param wBit The W-Bit of the message.\r\n * @param body The body of the message.\r\n * @param systemBytes The system bytes of the message.\r\n * @param deviceId The device ID of the message.\r\n * @param pType The P-Type of the message.\r\n * @param sType The S-Type of the message.\r\n */\r\nexport class HsmsMessage extends SecsMessage {\r\n\tconstructor(\r\n\t\tstream: number,\r\n\t\tfunc: number,\r\n\t\twBit: boolean,\r\n\t\tbody: AbstractSecs2Item | null,\r\n\t\tsystemBytes: number,\r\n\t\tdeviceId: number,\r\n\t\tpublic readonly pType = 0,\r\n\t\tpublic readonly sType = 0,\r\n\t) {\r\n\t\tsuper(stream, func, wBit, body, systemBytes, deviceId);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Encodes the message to a buffer (Length + Header + Body).\r\n\t */\r\n\ttoBuffer(): Buffer {\r\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\r\n\t\tconst header = Buffer.alloc(10);\r\n\r\n\t\t// Byte 0-1: Session ID (Device ID) or 0xFFFF\r\n\t\tif (this.isDataMessage()) {\r\n\t\t\theader.writeUInt16BE(this.deviceId, 0);\r\n\t\t} else {\r\n\t\t\theader.writeUInt16BE(0xffff, 0);\r\n\t\t}\r\n\r\n\t\t// Byte 2: Stream / WBit (only for Data)\r\n\t\t// Byte 3: Function (only for Data)\r\n\t\tif (this.isDataMessage()) {\r\n\t\t\tlet b2 = this.stream;\r\n\t\t\tif (this.wBit) {\r\n\t\t\t\tb2 |= 0x80;\r\n\t\t\t}\r\n\t\t\theader.writeUInt8(b2, 2);\r\n\t\t\theader.writeUInt8(this.func, 3);\r\n\t\t} else {\r\n\t\t\t// For control messages, byte 2 and 3 depend on type\r\n\t\t\t// But typically 0 unless SelectStatus/RejectReason\r\n\t\t\t// We will handle specific construction in static methods\r\n\t\t\t// Here we assume pType and sType are set correctly for Control Messages\r\n\t\t\t// Wait, P-Type is Byte 4, S-Type is Byte 5.\r\n\t\t\t// Byte 2 and 3 are 0 for most control messages.\r\n\t\t\t// EXCEPT Select Response (Byte 3 = Status) and Reject (Byte 3 = Reason).\r\n\t\t\t// But those are stored in 'sType' or 'func' or similar?\r\n\t\t\t// In this class, I store pType and sType (Byte 4, 5).\r\n\t\t\t// Where do I store Byte 2 and 3 for Control Messages?\r\n\t\t\t// The Python code:\r\n\t\t\t// Select Response: h10bytes = ... 0x00, select_status ...\r\n\t\t\t// Reject: ... b2, reject_reason ...\r\n\r\n\t\t\t// I should allow passing byte 2 and 3 specifically or handle it via polymorphism.\r\n\t\t\t// To keep it simple, I will use 'stream' and 'func' to hold Byte 2 and 3 for Control Messages too,\r\n\t\t\t// even if they don't mean Stream/Function.\r\n\r\n\t\t\theader.writeUInt8(this.stream, 2);\r\n\t\t\theader.writeUInt8(this.func, 3);\r\n\t\t}\r\n\r\n\t\t// Byte 4: P-Type\r\n\t\theader.writeUInt8(this.pType, 4);\r\n\r\n\t\t// Byte 5: S-Type\r\n\t\theader.writeUInt8(this.sType, 5);\r\n\r\n\t\t// Byte 6-9: System Bytes\r\n\t\theader.writeUInt32BE(this.systemBytes, 6);\r\n\r\n\t\tconst length = header.length + bodyBuffer.length;\r\n\t\tconst lengthBuffer = Buffer.alloc(4);\r\n\t\tlengthBuffer.writeUInt32BE(length, 0);\r\n\r\n\t\treturn Buffer.concat([lengthBuffer, header, bodyBuffer]);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Checks if the message is a data message.\r\n\t * @description data message: deviceId not 0xFF 0xFF and header[4] and header[5] are 0.\r\n\t * @returns True if the message is a data message, false otherwise.\r\n\t */\r\n\tisDataMessage(): boolean {\r\n\t\treturn (this.sType as HsmsControlType) === HsmsControlType.Data;\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates an HsmsMessage from a buffer.\r\n\t * @param buffer The buffer containing the message data.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic fromBuffer(buffer: Buffer): HsmsMessage {\r\n\t\tif (buffer.length < 14) {\r\n\t\t\tthrow new Error(\"Buffer too short for HSMS message\");\r\n\t\t}\r\n\r\n\t\t// Bytes 0-3: Length (ignored here, assumed to be correct or handled by framer)\r\n\t\tconst header = buffer.subarray(4, 14);\r\n\t\tconst bodyBuffer = buffer.subarray(14);\r\n\r\n\t\tconst sessionId = header.readUInt16BE(0);\r\n\t\tconst byte2 = header.readUInt8(2);\r\n\t\tconst byte3 = header.readUInt8(3);\r\n\t\tconst pType = header.readUInt8(4);\r\n\t\tconst sType = header.readUInt8(5);\r\n\t\tconst systemBytes = header.readUInt32BE(6);\r\n\r\n\t\tlet stream = 0;\r\n\t\tlet func = 0;\r\n\t\tlet wBit = false;\r\n\t\tconst deviceId = sessionId;\r\n\t\tlet body: AbstractSecs2Item | null = null;\r\n\r\n\t\tif ((sType as HsmsControlType) === HsmsControlType.Data) {\r\n\t\t\tstream = byte2 & 0x7f;\r\n\t\t\twBit = (byte2 & 0x80) !== 0;\r\n\t\t\tfunc = byte3;\r\n\r\n\t\t\tif (bodyBuffer.length > 0) {\r\n\t\t\t\tconst result = Secs2ItemParser.fromBuffer(bodyBuffer);\r\n\t\t\t\tbody = result.item;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// Control Message\r\n\t\t\t// Mapping Byte 2/3 to stream/func to preserve data (e.g. Select Status)\r\n\t\t\tstream = byte2;\r\n\t\t\tfunc = byte3;\r\n\t\t\t// deviceId is usually ignored or 0xFFFF, but we keep what we read\r\n\t\t}\r\n\r\n\t\treturn new HsmsMessage(\r\n\t\t\tstream,\r\n\t\t\tfunc,\r\n\t\t\twBit,\r\n\t\t\tbody,\r\n\t\t\tsystemBytes,\r\n\t\t\tdeviceId,\r\n\t\t\tpType,\r\n\t\t\tsType,\r\n\t\t);\r\n\t}\r\n\r\n\t// Factory methods for Control Messages\r\n\t/**\r\n\t * @description Creates a Select Request message.\r\n\t * @param systemBytes The system bytes of the message.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic selectReq(systemBytes: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\tsystemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.SelectReq,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Select Response message.\r\n\t * @param req The Select Request message.\r\n\t * @param status The status of the response.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic selectRsp(req: HsmsMessage, status: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\tstatus,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\treq.systemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.SelectRsp,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Deselect Request message.\r\n\t * @param systemBytes The system bytes of the message.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic deselectReq(systemBytes: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\tsystemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.DeselectReq,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Deselect Response message.\r\n\t * @param req The Deselect Request message.\r\n\t * @param status The status of the response.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic deselectRsp(req: HsmsMessage, status: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\tstatus,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\treq.systemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.DeselectRsp,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Link Test Request message.\r\n\t * @param systemBytes The system bytes of the message.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic linkTestReq(systemBytes: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\tsystemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.LinkTestReq,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Link Test Response message.\r\n\t * @param req The Link Test Request message.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic linkTestRsp(req: HsmsMessage): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\treq.systemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.LinkTestRsp,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Reject Request message.\r\n\t * @param req The message that triggered the reject.\r\n\t * @param reason The reason for the reject.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic rejectReq(req: HsmsMessage, reason: RejectReason): HsmsMessage {\r\n\t\t// Byte 2 (Stream) should be the sType of the rejected message if PType is not supported\r\n\t\t// But typically it's just mirroring or specific logic.\r\n\t\t// Python: b2 = h10bytes[4] (PType) if reason == NOT_SUPPORT_TYPE_P else h10bytes[5] (SType)\r\n\t\tconst b2 = reason === RejectReason.NotSupportTypeP ? req.pType : req.sType;\r\n\t\treturn new HsmsMessage(\r\n\t\t\tb2,\r\n\t\t\treason,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\treq.systemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.RejectReq,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Creates a Separate Request message.\r\n\t * @param systemBytes The system bytes of the message.\r\n\t * @returns The HsmsMessage object.\r\n\t */\r\n\tstatic separateReq(systemBytes: number): HsmsMessage {\r\n\t\treturn new HsmsMessage(\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\tfalse,\r\n\t\t\tnull,\r\n\t\t\tsystemBytes,\r\n\t\t\t0xffff,\r\n\t\t\t0,\r\n\t\t\tHsmsControlType.SeparateReq,\r\n\t\t);\r\n\t}\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"HsmsMessage.js","names":["body: AbstractSecs2Item | null"],"sources":["../../src/hsms/HsmsMessage.ts"],"sourcesContent":["import { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\nimport { RejectReason } from \"./enums/RejectReason.js\";\nimport { Secs2ItemParser } from \"../core/secs2item/Secs2ItemParser.js\";\n\n/**\n * @description HsmsMessage is the class that represents an HSMS message.\n * @param stream The stream number of the message.\n * @param func The function number of the message.\n * @param wBit The W-Bit of the message.\n * @param body The body of the message.\n * @param systemBytes The system bytes of the message.\n * @param deviceId The device ID of the message.\n * @param pType The P-Type of the message.\n * @param sType The S-Type of the message.\n */\nexport class HsmsMessage extends SecsMessage {\n\tconstructor(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t\tdeviceId: number,\n\t\tpublic readonly pType = 0,\n\t\tpublic readonly sType = 0,\n\t) {\n\t\tsuper(stream, func, wBit, body, systemBytes, deviceId);\n\t}\n\n\t/**\n\t * @description Encodes the message to a buffer (Length + Header + Body).\n\t */\n\ttoBuffer(): Buffer {\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\n\t\tconst header = Buffer.alloc(10);\n\n\t\t// Byte 0-1: Session ID (Device ID) or 0xFFFF\n\t\tif (this.isDataMessage()) {\n\t\t\theader.writeUInt16BE(this.deviceId, 0);\n\t\t} else {\n\t\t\theader.writeUInt16BE(0xffff, 0);\n\t\t}\n\n\t\t// Byte 2: Stream / WBit (only for Data)\n\t\t// Byte 3: Function (only for Data)\n\t\tif (this.isDataMessage()) {\n\t\t\tlet b2 = this.stream;\n\t\t\tif (this.wBit) {\n\t\t\t\tb2 |= 0x80;\n\t\t\t}\n\t\t\theader.writeUInt8(b2, 2);\n\t\t\theader.writeUInt8(this.func, 3);\n\t\t} else {\n\t\t\t// For control messages, byte 2 and 3 depend on type\n\t\t\t// But typically 0 unless SelectStatus/RejectReason\n\t\t\t// We will handle specific construction in static methods\n\t\t\t// Here we assume pType and sType are set correctly for Control Messages\n\t\t\t// Wait, P-Type is Byte 4, S-Type is Byte 5.\n\t\t\t// Byte 2 and 3 are 0 for most control messages.\n\t\t\t// EXCEPT Select Response (Byte 3 = Status) and Reject (Byte 3 = Reason).\n\t\t\t// But those are stored in 'sType' or 'func' or similar?\n\t\t\t// In this class, I store pType and sType (Byte 4, 5).\n\t\t\t// Where do I store Byte 2 and 3 for Control Messages?\n\t\t\t// The Python code:\n\t\t\t// Select Response: h10bytes = ... 0x00, select_status ...\n\t\t\t// Reject: ... b2, reject_reason ...\n\n\t\t\t// I should allow passing byte 2 and 3 specifically or handle it via polymorphism.\n\t\t\t// To keep it simple, I will use 'stream' and 'func' to hold Byte 2 and 3 for Control Messages too,\n\t\t\t// even if they don't mean Stream/Function.\n\n\t\t\theader.writeUInt8(this.stream, 2);\n\t\t\theader.writeUInt8(this.func, 3);\n\t\t}\n\n\t\t// Byte 4: P-Type\n\t\theader.writeUInt8(this.pType, 4);\n\n\t\t// Byte 5: S-Type\n\t\theader.writeUInt8(this.sType, 5);\n\n\t\t// Byte 6-9: System Bytes\n\t\theader.writeUInt32BE(this.systemBytes, 6);\n\n\t\tconst length = header.length + bodyBuffer.length;\n\t\tconst lengthBuffer = Buffer.alloc(4);\n\t\tlengthBuffer.writeUInt32BE(length, 0);\n\n\t\treturn Buffer.concat([lengthBuffer, header, bodyBuffer]);\n\t}\n\n\t/**\n\t * @description Checks if the message is a data message.\n\t * @description data message: deviceId not 0xFF 0xFF and header[4] and header[5] are 0.\n\t * @returns True if the message is a data message, false otherwise.\n\t */\n\tisDataMessage(): boolean {\n\t\treturn (this.sType as HsmsControlType) === HsmsControlType.Data;\n\t}\n\n\t/**\n\t * @description Creates an HsmsMessage from a buffer.\n\t * @param buffer The buffer containing the message data.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic fromBuffer(buffer: Buffer): HsmsMessage {\n\t\tif (buffer.length < 14) {\n\t\t\tthrow new Error(\"Buffer too short for HSMS message\");\n\t\t}\n\n\t\t// Bytes 0-3: Length (ignored here, assumed to be correct or handled by framer)\n\t\tconst header = buffer.subarray(4, 14);\n\t\tconst bodyBuffer = buffer.subarray(14);\n\n\t\tconst sessionId = header.readUInt16BE(0);\n\t\tconst byte2 = header.readUInt8(2);\n\t\tconst byte3 = header.readUInt8(3);\n\t\tconst pType = header.readUInt8(4);\n\t\tconst sType = header.readUInt8(5);\n\t\tconst systemBytes = header.readUInt32BE(6);\n\n\t\tlet stream = 0;\n\t\tlet func = 0;\n\t\tlet wBit = false;\n\t\tconst deviceId = sessionId;\n\t\tlet body: AbstractSecs2Item | null = null;\n\n\t\tif ((sType as HsmsControlType) === HsmsControlType.Data) {\n\t\t\tstream = byte2 & 0x7f;\n\t\t\twBit = (byte2 & 0x80) !== 0;\n\t\t\tfunc = byte3;\n\n\t\t\tif (bodyBuffer.length > 0) {\n\t\t\t\tconst result = Secs2ItemParser.fromBuffer(bodyBuffer);\n\t\t\t\tbody = result.item;\n\t\t\t}\n\t\t} else {\n\t\t\t// Control Message\n\t\t\t// Mapping Byte 2/3 to stream/func to preserve data (e.g. Select Status)\n\t\t\tstream = byte2;\n\t\t\tfunc = byte3;\n\t\t\t// deviceId is usually ignored or 0xFFFF, but we keep what we read\n\t\t}\n\n\t\treturn new HsmsMessage(\n\t\t\tstream,\n\t\t\tfunc,\n\t\t\twBit,\n\t\t\tbody,\n\t\t\tsystemBytes,\n\t\t\tdeviceId,\n\t\t\tpType,\n\t\t\tsType,\n\t\t);\n\t}\n\n\t// Factory methods for Control Messages\n\t/**\n\t * @description Creates a Select Request message.\n\t * @param systemBytes The system bytes of the message.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic selectReq(systemBytes: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\t0,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\tsystemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.SelectReq,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Select Response message.\n\t * @param req The Select Request message.\n\t * @param status The status of the response.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic selectRsp(req: HsmsMessage, status: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\tstatus,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\treq.systemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.SelectRsp,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Deselect Request message.\n\t * @param systemBytes The system bytes of the message.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic deselectReq(systemBytes: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\t0,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\tsystemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.DeselectReq,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Deselect Response message.\n\t * @param req The Deselect Request message.\n\t * @param status The status of the response.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic deselectRsp(req: HsmsMessage, status: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\tstatus,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\treq.systemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.DeselectRsp,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Link Test Request message.\n\t * @param systemBytes The system bytes of the message.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic linkTestReq(systemBytes: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\t0,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\tsystemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.LinkTestReq,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Link Test Response message.\n\t * @param req The Link Test Request message.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic linkTestRsp(req: HsmsMessage): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\t0,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\treq.systemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.LinkTestRsp,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Reject Request message.\n\t * @param req The message that triggered the reject.\n\t * @param reason The reason for the reject.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic rejectReq(req: HsmsMessage, reason: RejectReason): HsmsMessage {\n\t\t// Byte 2 (Stream) should be the sType of the rejected message if PType is not supported\n\t\t// But typically it's just mirroring or specific logic.\n\t\t// Python: b2 = h10bytes[4] (PType) if reason == NOT_SUPPORT_TYPE_P else h10bytes[5] (SType)\n\t\tconst b2 = reason === RejectReason.NotSupportTypeP ? req.pType : req.sType;\n\t\treturn new HsmsMessage(\n\t\t\tb2,\n\t\t\treason,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\treq.systemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.RejectReq,\n\t\t);\n\t}\n\n\t/**\n\t * @description Creates a Separate Request message.\n\t * @param systemBytes The system bytes of the message.\n\t * @returns The HsmsMessage object.\n\t */\n\tstatic separateReq(systemBytes: number): HsmsMessage {\n\t\treturn new HsmsMessage(\n\t\t\t0,\n\t\t\t0,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t\tsystemBytes,\n\t\t\t0xffff,\n\t\t\t0,\n\t\t\tHsmsControlType.SeparateReq,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HsmsPassiveCommunicator.js","names":["resolveFirstListen: (() => void) | null","t8Timer: NodeJS.Timeout | null","t7Timer: NodeJS.Timeout | null","msg: HsmsMessage"],"sources":["../../src/hsms/HsmsPassiveCommunicator.ts"],"sourcesContent":["import { Server, Socket, createServer } from \"net\";\r\nimport {\r\n\tHsmsCommunicator,\r\n\tHsmsCommunicatorConfig,\r\n\tHsmsState,\r\n} from \"./HsmsCommunicator.js\";\r\nimport { HsmsMessage } from \"./HsmsMessage.js\";\r\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\r\nimport { SelectStatus } from \"./enums/SelectStatus.js\";\r\nimport { RejectReason } from \"./enums/RejectReason.js\";\r\n\r\nexport interface HsmsPassiveCommunicatorConfig extends HsmsCommunicatorConfig {\r\n\ttimeoutRebind?: number;\r\n}\r\n\r\n/**\r\n * @description HsmsPassiveCommunicator is the class that represents an HSMS passive communicator.\r\n */\r\nexport class HsmsPassiveCommunicator extends HsmsCommunicator {\r\n\tprivate server: Server | null = null;\r\n\tprivate shouldStop = false;\r\n\tprivate serverLoopPromise: Promise<void> | null = null;\r\n\tprivate timeoutRebind = 5;\r\n\r\n\tconstructor(config: HsmsPassiveCommunicatorConfig) {\r\n\t\tsuper(config);\r\n\t\tif (config.timeoutRebind !== undefined) {\r\n\t\t\tthis.timeoutRebind = config.timeoutRebind;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @description Opens the passive communicator.\r\n\t */\r\n\tasync open(): Promise<void> {\r\n\t\tif (this.serverLoopPromise) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.shouldStop = false;\r\n\r\n\t\tlet resolveFirstListen: (() => void) | null = null;\r\n\t\tconst firstListen = new Promise<void>((resolve) => {\r\n\t\t\tresolveFirstListen = resolve;\r\n\t\t});\r\n\r\n\t\tthis.serverLoopPromise = this.runServerLoop(() => {\r\n\t\t\tresolveFirstListen?.();\r\n\t\t\tresolveFirstListen = null;\r\n\t\t}).catch((err: unknown) => {\r\n\t\t\tthis.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\r\n\t\t});\r\n\r\n\t\tawait firstListen;\r\n\t}\r\n\r\n\t/**\r\n\t * @description Runs the server loop.\r\n\t * @param onFirstListening The callback function to be called when the first listening is completed.\r\n\t * @returns A Promise that resolves when the server loop is stopped.\r\n\t */\r\n\tprivate async runServerLoop(onFirstListening: () => void): Promise<void> {\r\n\t\tlet first = true;\r\n\t\twhile (!this.shouldStop) {\r\n\t\t\ttry {\r\n\t\t\t\tawait this.listenOnce(first ? onFirstListening : null);\r\n\t\t\t} catch (err) {\r\n\t\t\t\tif (!this.shouldStop) {\r\n\t\t\t\t\tthis.emit(\r\n\t\t\t\t\t\t\"error\",\r\n\t\t\t\t\t\terr instanceof Error ? err : new Error(String(err)),\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\tif (!this.shouldStop) {\r\n\t\t\t\t\tawait new Promise((resolve) =>\r\n\t\t\t\t\t\tsetTimeout(resolve, this.timeoutRebind * 1000),\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfirst = false;\r\n\t\t\tif (this.shouldStop) return;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @description Listens for a single connection.\r\n\t * @param onListening The callback function to be called when the connection is established.\r\n\t * @returns A Promise that resolves when the connection is closed.\r\n\t */\r\n\tprivate async listenOnce(onListening: (() => void) | null): Promise<void> {\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\tconst server = createServer((socket) => {\r\n\t\t\t\tvoid this.handleIncomingSocket(socket);\r\n\t\t\t});\r\n\t\t\tthis.server = server;\r\n\r\n\t\t\tlet hasConnected = false;\r\n\t\t\tlet settled = false;\r\n\r\n\t\t\tconst cleanup = () => {\r\n\t\t\t\tserver.removeListener(\"error\", onServerError);\r\n\t\t\t\tserver.removeListener(\"close\", onServerClose);\r\n\t\t\t\tthis.removeListener(\"connected\", onConnected);\r\n\t\t\t\tthis.removeListener(\"disconnected\", onDisconnected);\r\n\t\t\t};\r\n\r\n\t\t\tconst finish = (err?: Error) => {\r\n\t\t\t\tif (settled) return;\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tif (this.server === server) {\r\n\t\t\t\t\tthis.server = null;\r\n\t\t\t\t}\r\n\t\t\t\tcleanup();\r\n\t\t\t\tif (err) reject(err);\r\n\t\t\t\telse resolve();\r\n\t\t\t};\r\n\r\n\t\t\tconst closeServer = () => {\r\n\t\t\t\tif (settled) return;\r\n\t\t\t\tif (!server.listening) {\r\n\t\t\t\t\tfinish();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tserver.close((err) => {\r\n\t\t\t\t\tif (err) finish(err);\r\n\t\t\t\t\telse finish();\r\n\t\t\t\t});\r\n\t\t\t};\r\n\r\n\t\t\tconst onServerError = (err: Error) => {\r\n\t\t\t\tfinish(err);\r\n\t\t\t};\r\n\r\n\t\t\tconst onServerClose = () => {\r\n\t\t\t\tfinish();\r\n\t\t\t};\r\n\r\n\t\t\tconst onConnected = () => {\r\n\t\t\t\thasConnected = true;\r\n\t\t\t};\r\n\r\n\t\t\tconst onDisconnected = () => {\r\n\t\t\t\tif (!hasConnected) return;\r\n\t\t\t\tcloseServer();\r\n\t\t\t};\r\n\r\n\t\t\tserver.on(\"error\", onServerError);\r\n\t\t\tserver.on(\"close\", onServerClose);\r\n\t\t\tthis.on(\"connected\", onConnected);\r\n\t\t\tthis.on(\"disconnected\", onDisconnected);\r\n\r\n\t\t\tserver.listen(this.port, this.ip, () => {\r\n\t\t\t\tonListening?.();\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * @description Handles an incoming socket connection.\r\n\t * @param socket The socket object representing the incoming connection.\r\n\t * @returns A Promise that resolves when the socket connection is handled.\r\n\t */\r\n\tprivate async handleIncomingSocket(socket: Socket): Promise<void> {\r\n\t\tsocket.setNoDelay(true);\r\n\r\n\t\tif (!this.socket || this.socket.destroyed) {\r\n\t\t\tconst promoted = await this.handleSocketUntilSelected(socket);\r\n\t\t\tif (promoted) return;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tawait this.handleSocketUntilSelected(socket);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Handles a socket connection until it is selected.\r\n\t * @param socket The socket object representing the connection.\r\n\t * @returns A Promise that resolves with a boolean indicating whether the socket was promoted to selected.\r\n\t */\r\n\tprivate async handleSocketUntilSelected(socket: Socket): Promise<boolean> {\r\n\t\tlet buffer = Buffer.alloc(0);\r\n\t\tlet t8Timer: NodeJS.Timeout | null = null;\r\n\t\tlet t7Timer: NodeJS.Timeout | null = null;\r\n\r\n\t\tconst clearT8 = () => {\r\n\t\t\tif (t8Timer) {\r\n\t\t\t\tclearTimeout(t8Timer);\r\n\t\t\t\tt8Timer = null;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst resetT8 = () => {\r\n\t\t\tclearT8();\r\n\t\t\tif (this.timeoutT8 <= 0) return;\r\n\t\t\tt8Timer = setTimeout(() => {\r\n\t\t\t\tt8Timer = null;\r\n\t\t\t\tif (buffer.length > 0 && !socket.destroyed) {\r\n\t\t\t\t\tthis.emit(\"error\", new Error(\"T8 Timeout\"));\r\n\t\t\t\t\tsocket.destroy();\r\n\t\t\t\t}\r\n\t\t\t}, this.timeoutT8 * 1000);\r\n\t\t};\r\n\r\n\t\tconst clearT7 = () => {\r\n\t\t\tif (t7Timer) {\r\n\t\t\t\tclearTimeout(t7Timer);\r\n\t\t\t\tt7Timer = null;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst resetT7 = () => {\r\n\t\t\tclearT7();\r\n\t\t\tif (this.timeoutT7 <= 0) return;\r\n\t\t\tt7Timer = setTimeout(() => {\r\n\t\t\t\tt7Timer = null;\r\n\t\t\t\tif (!socket.destroyed) {\r\n\t\t\t\t\tsocket.destroy();\r\n\t\t\t\t}\r\n\t\t\t}, this.timeoutT7 * 1000);\r\n\t\t};\r\n\r\n\t\tconst sendSocketBuffer = async (buf: Buffer): Promise<void> => {\r\n\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\tsocket.write(buf, (err) => {\r\n\t\t\t\t\tif (err) reject(err);\r\n\t\t\t\t\telse resolve();\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\tconst cleanup = () => {\r\n\t\t\tclearT8();\r\n\t\t\tclearT7();\r\n\t\t};\r\n\r\n\t\tconst promoteToSelected = (selectReq: HsmsMessage) => {\r\n\t\t\tsocket.removeListener(\"data\", onData);\r\n\t\t\tsocket.removeListener(\"close\", onClose);\r\n\t\t\tsocket.removeListener(\"end\", onEnd);\r\n\t\t\tsocket.removeListener(\"error\", onError);\r\n\t\t\tcleanup();\r\n\t\t\tthis.handleSocketEvents(socket);\r\n\t\t\tthis.handleSelectReq(selectReq);\r\n\t\t};\r\n\r\n\t\tconst handlePreSelectedMessage = async (msg: HsmsMessage) => {\r\n\t\t\tswitch (msg.sType as HsmsControlType) {\r\n\t\t\t\tcase HsmsControlType.Data: {\r\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(msg, RejectReason.NotSelected);\r\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcase HsmsControlType.LinkTestReq: {\r\n\t\t\t\t\tconst rsp = HsmsMessage.linkTestRsp(msg);\r\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcase HsmsControlType.SeparateReq: {\r\n\t\t\t\t\tsocket.destroy();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcase HsmsControlType.SelectReq: {\r\n\t\t\t\t\tif (\r\n\t\t\t\t\t\tthis.socket &&\r\n\t\t\t\t\t\t!this.socket.destroyed &&\r\n\t\t\t\t\t\tthis.state === HsmsState.Selected\r\n\t\t\t\t\t) {\r\n\t\t\t\t\t\tconst rsp = HsmsMessage.selectRsp(msg, SelectStatus.AlreadyUsed);\r\n\t\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tpromoteToSelected(msg);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcase HsmsControlType.SelectRsp:\r\n\t\t\t\tcase HsmsControlType.LinkTestRsp: {\r\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(\r\n\t\t\t\t\t\tmsg,\r\n\t\t\t\t\t\tRejectReason.TransactionNotOpen,\r\n\t\t\t\t\t);\r\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcase HsmsControlType.RejectReq: {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tdefault: {\r\n\t\t\t\t\tconst reason =\r\n\t\t\t\t\t\tmsg.pType !== 0\r\n\t\t\t\t\t\t\t? RejectReason.NotSupportTypeP\r\n\t\t\t\t\t\t\t: RejectReason.NotSupportTypeS;\r\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(msg, reason);\r\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tlet processing = false;\r\n\t\tconst processIncoming = async () => {\r\n\t\t\tif (processing) return;\r\n\t\t\tprocessing = true;\r\n\t\t\ttry {\r\n\t\t\t\twhile (true) {\r\n\t\t\t\t\tif (buffer.length < 4) return;\r\n\t\t\t\t\tconst length = buffer.readUInt32BE(0);\r\n\t\t\t\t\tif (length < 10) {\r\n\t\t\t\t\t\tthis.emit(\"error\", new Error(\"Receive message size < 10\"));\r\n\t\t\t\t\t\tbuffer = Buffer.alloc(0);\r\n\t\t\t\t\t\tsocket.destroy();\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (buffer.length < 4 + length) return;\r\n\r\n\t\t\t\t\tconst msgBuffer = buffer.subarray(0, 4 + length);\r\n\t\t\t\t\tbuffer = buffer.subarray(4 + length);\r\n\t\t\t\t\tif (buffer.length === 0) clearT8();\r\n\r\n\t\t\t\t\tlet msg: HsmsMessage;\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tmsg = HsmsMessage.fromBuffer(msgBuffer);\r\n\t\t\t\t\t} catch (err) {\r\n\t\t\t\t\t\tthis.emit(\r\n\t\t\t\t\t\t\t\"error\",\r\n\t\t\t\t\t\t\terr instanceof Error ? err : new Error(String(err)),\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t\tsocket.destroy();\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tresetT7();\r\n\t\t\t\t\tawait handlePreSelectedMessage(msg);\r\n\r\n\t\t\t\t\tif (this.socket === socket && this.state === HsmsState.Selected) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} catch (err) {\r\n\t\t\t\tthis.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\r\n\t\t\t\tsocket.destroy();\r\n\t\t\t} finally {\r\n\t\t\t\tprocessing = false;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onData = (data: Buffer) => {\r\n\t\t\tbuffer = Buffer.concat([buffer, data]);\r\n\t\t\tresetT8();\r\n\t\t\tvoid processIncoming();\r\n\t\t};\r\n\r\n\t\tconst onClose = () => {\r\n\t\t\tcleanup();\r\n\t\t};\r\n\r\n\t\tconst onEnd = () => {\r\n\t\t\tif (!socket.destroyed) {\r\n\t\t\t\tsocket.destroy();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onError = (err: Error) => {\r\n\t\t\tthis.emit(\"error\", err);\r\n\t\t};\r\n\r\n\t\tsocket.on(\"data\", onData);\r\n\t\tsocket.on(\"close\", onClose);\r\n\t\tsocket.on(\"end\", onEnd);\r\n\t\tsocket.on(\"error\", onError);\r\n\t\tresetT7();\r\n\r\n\t\tawait new Promise<void>((resolve) => {\r\n\t\t\tsocket.once(\"close\", () => resolve());\r\n\t\t});\r\n\r\n\t\treturn this.socket === socket && this.state === HsmsState.Selected;\r\n\t}\r\n\r\n\tasync close(): Promise<void> {\r\n\t\tthis.shouldStop = true;\r\n\t\t// Close client connection first\r\n\t\tif (this.socket) {\r\n\t\t\tthis.socket.end();\r\n\t\t\tthis.socket.destroy();\r\n\t\t\tthis.socket = null;\r\n\t\t}\r\n\r\n\t\t// Stop listening\r\n\t\tconst server = this.server;\r\n\t\tif (server) {\r\n\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\tserver.close((err) => {\r\n\t\t\t\t\tthis.server = null;\r\n\t\t\t\t\tif (err) reject(err);\r\n\t\t\t\t\telse resolve();\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.serverLoopPromise) {\r\n\t\t\tconst loop = this.serverLoopPromise;\r\n\t\t\tthis.serverLoopPromise = null;\r\n\t\t\tawait loop;\r\n\t\t}\r\n\t}\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"HsmsPassiveCommunicator.js","names":["resolveFirstListen: (() => void) | null","t8Timer: NodeJS.Timeout | null","t7Timer: NodeJS.Timeout | null","msg: HsmsMessage"],"sources":["../../src/hsms/HsmsPassiveCommunicator.ts"],"sourcesContent":["import { Server, Socket, createServer } from \"net\";\nimport {\n\tHsmsCommunicator,\n\tHsmsCommunicatorConfig,\n\tHsmsState,\n} from \"./HsmsCommunicator.js\";\nimport { HsmsMessage } from \"./HsmsMessage.js\";\nimport { HsmsControlType } from \"./enums/HsmsControlType.js\";\nimport { SelectStatus } from \"./enums/SelectStatus.js\";\nimport { RejectReason } from \"./enums/RejectReason.js\";\n\nexport interface HsmsPassiveCommunicatorConfig extends HsmsCommunicatorConfig {\n\ttimeoutRebind?: number;\n}\n\n/**\n * @description HsmsPassiveCommunicator is the class that represents an HSMS passive communicator.\n */\nexport class HsmsPassiveCommunicator extends HsmsCommunicator {\n\tprivate server: Server | null = null;\n\tprivate shouldStop = false;\n\tprivate serverLoopPromise: Promise<void> | null = null;\n\tprivate timeoutRebind = 5;\n\n\tconstructor(config: HsmsPassiveCommunicatorConfig) {\n\t\tsuper(config);\n\t\tif (config.timeoutRebind !== undefined) {\n\t\t\tthis.timeoutRebind = config.timeoutRebind;\n\t\t}\n\t}\n\n\t/**\n\t * @description Opens the passive communicator.\n\t */\n\tasync open(): Promise<void> {\n\t\tif (this.serverLoopPromise) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.shouldStop = false;\n\n\t\tlet resolveFirstListen: (() => void) | null = null;\n\t\tconst firstListen = new Promise<void>((resolve) => {\n\t\t\tresolveFirstListen = resolve;\n\t\t});\n\n\t\tthis.serverLoopPromise = this.runServerLoop(() => {\n\t\t\tresolveFirstListen?.();\n\t\t\tresolveFirstListen = null;\n\t\t}).catch((err: unknown) => {\n\t\t\tthis.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n\t\t});\n\n\t\tawait firstListen;\n\t}\n\n\t/**\n\t * @description Runs the server loop.\n\t * @param onFirstListening The callback function to be called when the first listening is completed.\n\t * @returns A Promise that resolves when the server loop is stopped.\n\t */\n\tprivate async runServerLoop(onFirstListening: () => void): Promise<void> {\n\t\tlet first = true;\n\t\twhile (!this.shouldStop) {\n\t\t\ttry {\n\t\t\t\tawait this.listenOnce(first ? onFirstListening : null);\n\t\t\t} catch (err) {\n\t\t\t\tif (!this.shouldStop) {\n\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\terr instanceof Error ? err : new Error(String(err)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.shouldStop) {\n\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\tsetTimeout(resolve, this.timeoutRebind * 1000),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfirst = false;\n\t\t\tif (this.shouldStop) return;\n\t\t}\n\t}\n\n\t/**\n\t * @description Listens for a single connection.\n\t * @param onListening The callback function to be called when the connection is established.\n\t * @returns A Promise that resolves when the connection is closed.\n\t */\n\tprivate async listenOnce(onListening: (() => void) | null): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst server = createServer((socket) => {\n\t\t\t\tvoid this.handleIncomingSocket(socket);\n\t\t\t});\n\t\t\tthis.server = server;\n\n\t\t\tlet hasConnected = false;\n\t\t\tlet settled = false;\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tserver.removeListener(\"error\", onServerError);\n\t\t\t\tserver.removeListener(\"close\", onServerClose);\n\t\t\t\tthis.removeListener(\"connected\", onConnected);\n\t\t\t\tthis.removeListener(\"disconnected\", onDisconnected);\n\t\t\t};\n\n\t\t\tconst finish = (err?: Error) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tif (this.server === server) {\n\t\t\t\t\tthis.server = null;\n\t\t\t\t}\n\t\t\t\tcleanup();\n\t\t\t\tif (err) reject(err);\n\t\t\t\telse resolve();\n\t\t\t};\n\n\t\t\tconst closeServer = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (!server.listening) {\n\t\t\t\t\tfinish();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tserver.close((err) => {\n\t\t\t\t\tif (err) finish(err);\n\t\t\t\t\telse finish();\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst onServerError = (err: Error) => {\n\t\t\t\tfinish(err);\n\t\t\t};\n\n\t\t\tconst onServerClose = () => {\n\t\t\t\tfinish();\n\t\t\t};\n\n\t\t\tconst onConnected = () => {\n\t\t\t\thasConnected = true;\n\t\t\t};\n\n\t\t\tconst onDisconnected = () => {\n\t\t\t\tif (!hasConnected) return;\n\t\t\t\tcloseServer();\n\t\t\t};\n\n\t\t\tserver.on(\"error\", onServerError);\n\t\t\tserver.on(\"close\", onServerClose);\n\t\t\tthis.on(\"connected\", onConnected);\n\t\t\tthis.on(\"disconnected\", onDisconnected);\n\n\t\t\tserver.listen(this.port, this.ip, () => {\n\t\t\t\tonListening?.();\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * @description Handles an incoming socket connection.\n\t * @param socket The socket object representing the incoming connection.\n\t * @returns A Promise that resolves when the socket connection is handled.\n\t */\n\tprivate async handleIncomingSocket(socket: Socket): Promise<void> {\n\t\tsocket.setNoDelay(true);\n\n\t\tif (!this.socket || this.socket.destroyed) {\n\t\t\tconst promoted = await this.handleSocketUntilSelected(socket);\n\t\t\tif (promoted) return;\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.handleSocketUntilSelected(socket);\n\t}\n\n\t/**\n\t * @description Handles a socket connection until it is selected.\n\t * @param socket The socket object representing the connection.\n\t * @returns A Promise that resolves with a boolean indicating whether the socket was promoted to selected.\n\t */\n\tprivate async handleSocketUntilSelected(socket: Socket): Promise<boolean> {\n\t\tlet buffer = Buffer.alloc(0);\n\t\tlet t8Timer: NodeJS.Timeout | null = null;\n\t\tlet t7Timer: NodeJS.Timeout | null = null;\n\n\t\tconst clearT8 = () => {\n\t\t\tif (t8Timer) {\n\t\t\t\tclearTimeout(t8Timer);\n\t\t\t\tt8Timer = null;\n\t\t\t}\n\t\t};\n\n\t\tconst resetT8 = () => {\n\t\t\tclearT8();\n\t\t\tif (this.timeoutT8 <= 0) return;\n\t\t\tt8Timer = setTimeout(() => {\n\t\t\t\tt8Timer = null;\n\t\t\t\tif (buffer.length > 0 && !socket.destroyed) {\n\t\t\t\t\tthis.emit(\"error\", new Error(\"T8 Timeout\"));\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t}\n\t\t\t}, this.timeoutT8 * 1000);\n\t\t};\n\n\t\tconst clearT7 = () => {\n\t\t\tif (t7Timer) {\n\t\t\t\tclearTimeout(t7Timer);\n\t\t\t\tt7Timer = null;\n\t\t\t}\n\t\t};\n\n\t\tconst resetT7 = () => {\n\t\t\tclearT7();\n\t\t\tif (this.timeoutT7 <= 0) return;\n\t\t\tt7Timer = setTimeout(() => {\n\t\t\t\tt7Timer = null;\n\t\t\t\tif (!socket.destroyed) {\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t}\n\t\t\t}, this.timeoutT7 * 1000);\n\t\t};\n\n\t\tconst sendSocketBuffer = async (buf: Buffer): Promise<void> => {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tsocket.write(buf, (err) => {\n\t\t\t\t\tif (err) reject(err);\n\t\t\t\t\telse resolve();\n\t\t\t\t});\n\t\t\t});\n\t\t};\n\n\t\tconst cleanup = () => {\n\t\t\tclearT8();\n\t\t\tclearT7();\n\t\t};\n\n\t\tconst promoteToSelected = (selectReq: HsmsMessage) => {\n\t\t\tsocket.removeListener(\"data\", onData);\n\t\t\tsocket.removeListener(\"close\", onClose);\n\t\t\tsocket.removeListener(\"end\", onEnd);\n\t\t\tsocket.removeListener(\"error\", onError);\n\t\t\tcleanup();\n\t\t\tthis.handleSocketEvents(socket);\n\t\t\tthis.handleSelectReq(selectReq);\n\t\t};\n\n\t\tconst handlePreSelectedMessage = async (msg: HsmsMessage) => {\n\t\t\tswitch (msg.sType as HsmsControlType) {\n\t\t\t\tcase HsmsControlType.Data: {\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(msg, RejectReason.NotSelected);\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase HsmsControlType.LinkTestReq: {\n\t\t\t\t\tconst rsp = HsmsMessage.linkTestRsp(msg);\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase HsmsControlType.SeparateReq: {\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase HsmsControlType.SelectReq: {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.socket &&\n\t\t\t\t\t\t!this.socket.destroyed &&\n\t\t\t\t\t\tthis.state === HsmsState.Selected\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst rsp = HsmsMessage.selectRsp(msg, SelectStatus.AlreadyUsed);\n\t\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpromoteToSelected(msg);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase HsmsControlType.SelectRsp:\n\t\t\t\tcase HsmsControlType.LinkTestRsp: {\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(\n\t\t\t\t\t\tmsg,\n\t\t\t\t\t\tRejectReason.TransactionNotOpen,\n\t\t\t\t\t);\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase HsmsControlType.RejectReq: {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst reason =\n\t\t\t\t\t\tmsg.pType !== 0\n\t\t\t\t\t\t\t? RejectReason.NotSupportTypeP\n\t\t\t\t\t\t\t: RejectReason.NotSupportTypeS;\n\t\t\t\t\tconst rsp = HsmsMessage.rejectReq(msg, reason);\n\t\t\t\t\tawait sendSocketBuffer(rsp.toBuffer());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tlet processing = false;\n\t\tconst processIncoming = async () => {\n\t\t\tif (processing) return;\n\t\t\tprocessing = true;\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tif (buffer.length < 4) return;\n\t\t\t\t\tconst length = buffer.readUInt32BE(0);\n\t\t\t\t\tif (length < 10) {\n\t\t\t\t\t\tthis.emit(\"error\", new Error(\"Receive message size < 10\"));\n\t\t\t\t\t\tbuffer = Buffer.alloc(0);\n\t\t\t\t\t\tsocket.destroy();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (buffer.length < 4 + length) return;\n\n\t\t\t\t\tconst msgBuffer = buffer.subarray(0, 4 + length);\n\t\t\t\t\tbuffer = buffer.subarray(4 + length);\n\t\t\t\t\tif (buffer.length === 0) clearT8();\n\n\t\t\t\t\tlet msg: HsmsMessage;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tmsg = HsmsMessage.fromBuffer(msgBuffer);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tthis.emit(\n\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\terr instanceof Error ? err : new Error(String(err)),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tsocket.destroy();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tresetT7();\n\t\t\t\t\tawait handlePreSelectedMessage(msg);\n\n\t\t\t\t\tif (this.socket === socket && this.state === HsmsState.Selected) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n\t\t\t\tsocket.destroy();\n\t\t\t} finally {\n\t\t\t\tprocessing = false;\n\t\t\t}\n\t\t};\n\n\t\tconst onData = (data: Buffer) => {\n\t\t\tbuffer = Buffer.concat([buffer, data]);\n\t\t\tresetT8();\n\t\t\tvoid processIncoming();\n\t\t};\n\n\t\tconst onClose = () => {\n\t\t\tcleanup();\n\t\t};\n\n\t\tconst onEnd = () => {\n\t\t\tif (!socket.destroyed) {\n\t\t\t\tsocket.destroy();\n\t\t\t}\n\t\t};\n\n\t\tconst onError = (err: Error) => {\n\t\t\tthis.emit(\"error\", err);\n\t\t};\n\n\t\tsocket.on(\"data\", onData);\n\t\tsocket.on(\"close\", onClose);\n\t\tsocket.on(\"end\", onEnd);\n\t\tsocket.on(\"error\", onError);\n\t\tresetT7();\n\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsocket.once(\"close\", () => resolve());\n\t\t});\n\n\t\treturn this.socket === socket && this.state === HsmsState.Selected;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tthis.shouldStop = true;\n\t\t// Close client connection first\n\t\tif (this.socket) {\n\t\t\tthis.socket.end();\n\t\t\tthis.socket.destroy();\n\t\t\tthis.socket = null;\n\t\t}\n\n\t\t// Stop listening\n\t\tconst server = this.server;\n\t\tif (server) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tserver.close((err) => {\n\t\t\t\t\tthis.server = null;\n\t\t\t\t\tif (err) reject(err);\n\t\t\t\t\telse resolve();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tif (this.serverLoopPromise) {\n\t\t\tconst loop = this.serverLoopPromise;\n\t\t\tthis.serverLoopPromise = null;\n\t\t\tawait loop;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HsmsControlType.js","names":[],"sources":["../../../src/hsms/enums/HsmsControlType.ts"],"sourcesContent":["export enum HsmsControlType {\r\n Data = 0,\r\n SelectReq = 1,\r\n SelectRsp = 2,\r\n DeselectReq = 3,\r\n DeselectRsp = 4,\r\n LinkTestReq = 5,\r\n LinkTestRsp = 6,\r\n RejectReq = 7,\r\n SeparateReq = 9,\r\n}\r\n"],"mappings":";AAAA,IAAY,8DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"HsmsControlType.js","names":[],"sources":["../../../src/hsms/enums/HsmsControlType.ts"],"sourcesContent":["export enum HsmsControlType {\n Data = 0,\n SelectReq = 1,\n SelectRsp = 2,\n DeselectReq = 3,\n DeselectRsp = 4,\n LinkTestReq = 5,\n LinkTestRsp = 6,\n RejectReq = 7,\n SeparateReq = 9,\n}\n"],"mappings":";AAAA,IAAY,8DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"RejectReason.js","names":[],"sources":["../../../src/hsms/enums/RejectReason.ts"],"sourcesContent":["export enum RejectReason {\r\n NotSupportTypeS = 1,\r\n NotSupportTypeP = 2,\r\n TransactionNotOpen = 3,\r\n NotSelected = 4,\r\n Unknown = 0xff,\r\n}\r\n"],"mappings":";AAAA,IAAY,wDAAL;AACL;AACA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"RejectReason.js","names":[],"sources":["../../../src/hsms/enums/RejectReason.ts"],"sourcesContent":["export enum RejectReason {\n NotSupportTypeS = 1,\n NotSupportTypeP = 2,\n TransactionNotOpen = 3,\n NotSelected = 4,\n Unknown = 0xff,\n}\n"],"mappings":";AAAA,IAAY,wDAAL;AACL;AACA;AACA;AACA;AACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SelectStatus.js","names":[],"sources":["../../../src/hsms/enums/SelectStatus.ts"],"sourcesContent":["export enum SelectStatus {\r\n Success = 0,\r\n Actived = 1,\r\n NotReady = 2,\r\n AlreadyUsed = 3,\r\n Unknown = 0xff,\r\n}\r\n"],"mappings":";AAAA,IAAY,wDAAL;AACL;AACA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"SelectStatus.js","names":[],"sources":["../../../src/hsms/enums/SelectStatus.ts"],"sourcesContent":["export enum SelectStatus {\n Success = 0,\n Actived = 1,\n NotReady = 2,\n AlreadyUsed = 3,\n Unknown = 0xff,\n}\n"],"mappings":";AAAA,IAAY,wDAAL;AACL;AACA;AACA;AACA;AACA"}
package/lib/index.d.ts CHANGED
@@ -26,4 +26,5 @@ import { Secs1Communicator, Secs1CommunicatorConfig } from "./secs1/Secs1Communi
26
26
  import { Secs1OnTcpIpActiveCommunicator, Secs1OnTcpIpActiveCommunicatorConfig } from "./secs1/Secs1OnTcpIpActiveCommunicator.js";
27
27
  import { Secs1OnTcpIpPassiveCommunicator, Secs1OnTcpIpPassiveCommunicatorConfig } from "./secs1/Secs1OnTcpIpPassiveCommunicator.js";
28
28
  import { Secs1SerialCommunicator, Secs1SerialCommunicatorConfig } from "./secs1/Secs1SerialCommunicator.js";
29
- export { A, AbstractSecs2Item, AbstractSecsCommunicator, B, BOOLEAN, Clock, ClockType, CommAck, F4, F8, Gem, HsmsActiveCommunicator, HsmsCommunicator, HsmsCommunicatorConfig, HsmsCommunicatorEvents, HsmsControlType, HsmsMessage, HsmsPassiveCommunicator, HsmsPassiveCommunicatorConfig, HsmsState, I1, I2, I4, I8, L, OflAck, OnlAck, RejectReason, Secs1Communicator, Secs1CommunicatorConfig, Secs1Message, Secs1MessageBlock, Secs1OnTcpIpActiveCommunicator, Secs1OnTcpIpActiveCommunicatorConfig, Secs1OnTcpIpPassiveCommunicator, Secs1OnTcpIpPassiveCommunicatorConfig, Secs1SerialCommunicator, Secs1SerialCommunicatorConfig, Secs2ItemAscii, Secs2ItemBinary, Secs2ItemBoolean, Secs2ItemFactory, Secs2ItemList, Secs2ItemNumeric, Secs2ItemParser, SecsCommunicatorConfig, SecsCommunicatorEvents, SecsItemType, SecsLogDirection, SecsLogger, SecsLoggerConfig, SecsLoggerContext, SecsMessage, SelectStatus, TiAck, U1, U2, U4, U8 };
29
+ import { SmlParser } from "./sml/SmlParser.js";
30
+ export { A, AbstractSecs2Item, AbstractSecsCommunicator, B, BOOLEAN, Clock, ClockType, CommAck, F4, F8, Gem, HsmsActiveCommunicator, HsmsCommunicator, HsmsCommunicatorConfig, HsmsCommunicatorEvents, HsmsControlType, HsmsMessage, HsmsPassiveCommunicator, HsmsPassiveCommunicatorConfig, HsmsState, I1, I2, I4, I8, L, OflAck, OnlAck, RejectReason, Secs1Communicator, Secs1CommunicatorConfig, Secs1Message, Secs1MessageBlock, Secs1OnTcpIpActiveCommunicator, Secs1OnTcpIpActiveCommunicatorConfig, Secs1OnTcpIpPassiveCommunicator, Secs1OnTcpIpPassiveCommunicatorConfig, Secs1SerialCommunicator, Secs1SerialCommunicatorConfig, Secs2ItemAscii, Secs2ItemBinary, Secs2ItemBoolean, Secs2ItemFactory, Secs2ItemList, Secs2ItemNumeric, Secs2ItemParser, SecsCommunicatorConfig, SecsCommunicatorEvents, SecsItemType, SecsLogDirection, SecsLogger, SecsLoggerConfig, SecsLoggerContext, SecsMessage, SelectStatus, SmlParser, TiAck, U1, U2, U4, U8 };
package/lib/index.js CHANGED
@@ -26,5 +26,6 @@ import { Secs1OnTcpIpPassiveCommunicator } from "./secs1/Secs1OnTcpIpPassiveComm
26
26
  import { Secs1SerialCommunicator } from "./secs1/Secs1SerialCommunicator.js";
27
27
  import { Clock, ClockType } from "./gem/Clock.js";
28
28
  import { CommAck, Gem, OflAck, OnlAck, TiAck } from "./gem/Gem.js";
29
+ import { SmlParser } from "./sml/SmlParser.js";
29
30
 
30
- export { A, AbstractSecs2Item, AbstractSecsCommunicator, B, BOOLEAN, Clock, ClockType, CommAck, F4, F8, Gem, HsmsActiveCommunicator, HsmsCommunicator, HsmsControlType, HsmsMessage, HsmsPassiveCommunicator, HsmsState, I1, I2, I4, I8, L, OflAck, OnlAck, RejectReason, Secs1Communicator, Secs1Message, Secs1MessageBlock, Secs1OnTcpIpActiveCommunicator, Secs1OnTcpIpPassiveCommunicator, Secs1SerialCommunicator, Secs2ItemAscii, Secs2ItemBinary, Secs2ItemBoolean, Secs2ItemFactory, Secs2ItemList, Secs2ItemNumeric, Secs2ItemParser, SecsItemType, SecsLogger, SecsMessage, SelectStatus, TiAck, U1, U2, U4, U8 };
31
+ export { A, AbstractSecs2Item, AbstractSecsCommunicator, B, BOOLEAN, Clock, ClockType, CommAck, F4, F8, Gem, HsmsActiveCommunicator, HsmsCommunicator, HsmsControlType, HsmsMessage, HsmsPassiveCommunicator, HsmsState, I1, I2, I4, I8, L, OflAck, OnlAck, RejectReason, Secs1Communicator, Secs1Message, Secs1MessageBlock, Secs1OnTcpIpActiveCommunicator, Secs1OnTcpIpPassiveCommunicator, Secs1SerialCommunicator, Secs2ItemAscii, Secs2ItemBinary, Secs2ItemBoolean, Secs2ItemFactory, Secs2ItemList, Secs2ItemNumeric, Secs2ItemParser, SecsItemType, SecsLogger, SecsMessage, SelectStatus, SmlParser, TiAck, U1, U2, U4, U8 };
@@ -26,7 +26,7 @@ declare class SecsLogger {
26
26
  private readonly secs2Stream;
27
27
  private readonly maxHexBytes;
28
28
  private constructor();
29
- logSecs2(direction: SecsLogDirection, sml: string): void;
29
+ logSecs2(direction: SecsLogDirection, sml: string, deviceId: number, systemBytes: number, buffer?: Buffer): void;
30
30
  logBytes(direction: SecsLogDirection, protocol: string, buffer: Buffer, meta?: Record<string, unknown>): void;
31
31
  logState(protocol: string, prev: string, next: string, meta?: Record<string, unknown>): void;
32
32
  close(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"SecsLogger.d.ts","names":[],"sources":["../../src/logging/SecsLogger.ts"],"sourcesContent":[],"mappings":";;;KAKY,gBAAA;UAEK,gBAAA;EAFL,OAAA,CAAA,EAAA,OAAA;EAEK,OAAA,CAAA,EAAA,OAAA;EAUA,OAAA,CAAA,EAAA,MAAA;EAubJ,aAAU,CAAA,EAAA,MAAA;EACH,WAAA,CAAA,EA7bL,eA6bK;EAKV,UAAA,CAAA,EAjcI,eAicJ;EACH,WAAA,CAAA,EAAA,MAAA;;AA4EkB,UA1gBR,iBAAA,CA0gBQ;EAuBJ,IAAA,EAAA,MAAA;EAQR,QAAA,EAAA,MAAA;EAEH,OAAA,EAAA,OAAA;;AAmBD,cAvII,UAAA,CAuIJ;EAAM,OAAA,QAAA,CAAA,CAAA,EAtIK,UAsIL;wBAjIL,mCACH,oBACH;mBA2EqB;;;;;;;sBAuBJ;sBAQR,4CAEH,eACD;gEAkBA"}
1
+ {"version":3,"file":"SecsLogger.d.ts","names":[],"sources":["../../src/logging/SecsLogger.ts"],"sourcesContent":[],"mappings":";;;KAKY,gBAAA;UAEK,gBAAA;EAFL,OAAA,CAAA,EAAA,OAAA;EAEK,OAAA,CAAA,EAAA,OAAA;EAUA,OAAA,CAAA,EAAA,MAAA;EA6bJ,aAAU,CAAA,EAAA,MAAA;EACH,WAAA,CAAA,EAncL,eAmcK;EAKV,UAAA,CAAA,EAvcI,eAucJ;EACH,WAAA,CAAA,EAAA,MAAA;;AAiFkB,UArhBR,iBAAA,CAqhBQ;EAwBZ,IAAA,EAAA,MAAA;EAIF,QAAA,EAAA,MAAA;EAeE,OAAA,EAAA,OAAA;;AAGJ,cAtII,UAAA,CAsIJ;EAkBA,OAAA,QAAA,CAAA,CAAA,EAvJW,UAuJX;EAAM,OAAA,MAAA,CAAA,MAAA,EAlJL,gBAkJK,GAAA,SAAA,EAAA,GAAA,EAjJR,iBAiJQ,CAAA,EAhJX,UAgJW;mBAhEU;;;;;;;sBAwBZ,+EAIF;sBAeE,4CAEH,eACD;gEAkBA"}
@@ -277,6 +277,8 @@ var Secs2LineTransformStream = class extends Writable {
277
277
  const timeValue = rec.time;
278
278
  const dirValue = rec.dir;
279
279
  const smlValue = rec.sml;
280
+ const deviceIdValue = rec.deviceId;
281
+ const systemBytesValue = rec.systemBytes;
280
282
  const dir = dirValue === "Sent" || dirValue === "Received" ? dirValue : null;
281
283
  const sml = typeof smlValue === "string" ? smlValue : null;
282
284
  if (!dir || !sml) return;
@@ -284,7 +286,9 @@ var Secs2LineTransformStream = class extends Writable {
284
286
  if (typeof timeValue === "number") date = new Date(timeValue);
285
287
  else if (typeof timeValue === "string") date = new Date(timeValue);
286
288
  else date = /* @__PURE__ */ new Date();
287
- const out = `${formatDateTime(date)} ${dir} \n${normalizeSmlForSingleLine(sml)}\n`;
289
+ const deviceId = typeof deviceIdValue === "number" ? deviceIdValue : 0;
290
+ const systemBytes = typeof systemBytesValue === "number" ? systemBytesValue : 0;
291
+ const out = `${formatDateTime(date)} ${dir} DeviceID: ${deviceId} SystemBytes: ${systemBytes} \n${normalizeSmlForSingleLine(sml)}\n`;
288
292
  this.target.write(out);
289
293
  }
290
294
  };
@@ -328,12 +332,14 @@ var SecsLogger = class SecsLogger {
328
332
  deviceId: ctx.deviceId,
329
333
  isEquip: ctx.isEquip
330
334
  };
331
- const detailStreams = [{ stream: detailStream }];
335
+ const detailPrettyStream = new PrettyPrintTransformStream();
336
+ detailPrettyStream.pipe(detailStream);
337
+ const detailStreams = [{ stream: detailPrettyStream }];
332
338
  if (consoleEnabled) {
333
- const prettyStream = new PrettyPrintTransformStream();
334
- prettyStream.pipe(process.stdout);
339
+ const consolePrettyStream = new PrettyPrintTransformStream();
340
+ consolePrettyStream.pipe(process.stdout);
335
341
  detailStreams.push({
336
- stream: prettyStream,
342
+ stream: consolePrettyStream,
337
343
  level: detailLevel
338
344
  });
339
345
  }
@@ -341,14 +347,16 @@ var SecsLogger = class SecsLogger {
341
347
  level: detailLevel,
342
348
  base: bindings
343
349
  }, pino.multistream(detailStreams));
344
- const secs2Streams = [{ stream: secs2Stream }];
350
+ const secs2ToDetailPrettyStream = new PrettyPrintTransformStream();
351
+ secs2ToDetailPrettyStream.pipe(detailStream);
352
+ const secs2Streams = [{ stream: secs2Stream }, { stream: secs2ToDetailPrettyStream }];
345
353
  if (consoleEnabled) secs2Streams.push({
346
354
  stream: process.stdout,
347
355
  level: secs2Level
348
356
  });
349
357
  const secs2 = pino({
350
358
  level: secs2Level,
351
- base: null,
359
+ base: bindings,
352
360
  messageKey: "msg"
353
361
  }, pino.multistream(secs2Streams));
354
362
  return new SecsLogger({
@@ -378,10 +386,13 @@ var SecsLogger = class SecsLogger {
378
386
  this.secs2Stream = params.secs2Stream;
379
387
  this.maxHexBytes = params.config.maxHexBytes ?? 64 * 1024;
380
388
  }
381
- logSecs2(direction, sml) {
389
+ logSecs2(direction, sml, deviceId, systemBytes, buffer) {
382
390
  this.secs2.info({
383
391
  dir: direction,
384
- sml: normalizeSmlForSingleLine(sml)
392
+ sml: normalizeSmlForSingleLine(sml),
393
+ deviceId,
394
+ systemBytes,
395
+ hex: buffer ? bufferToHex(buffer, this.maxHexBytes) : void 0
385
396
  }, "");
386
397
  }
387
398
  logBytes(direction, protocol, buffer, meta) {
@@ -1 +1 @@
1
- {"version":3,"file":"SecsLogger.js","names":["parts: string[]","pairs: string[]","entries: fs.Dirent[]","obj: unknown","date: Date","detailStreams: pino.StreamEntry[]","secs2Streams: pino.StreamEntry[]"],"sources":["../../src/logging/SecsLogger.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { Writable, Transform } from \"stream\";\nimport pino, { type LevelWithSilent, type Logger } from \"pino\";\n\nexport type SecsLogDirection = \"Received\" | \"Sent\";\n\nexport interface SecsLoggerConfig {\n\tenabled?: boolean;\n\tconsole?: boolean;\n\tbaseDir?: string;\n\tretentionDays?: number;\n\tdetailLevel?: LevelWithSilent;\n\tsecs2Level?: LevelWithSilent;\n\tmaxHexBytes?: number;\n}\n\nexport interface SecsLoggerContext {\n\tname: string;\n\tdeviceId: number;\n\tisEquip: boolean;\n}\n\nfunction formatDate(date: Date): string {\n\tconst y = date.getFullYear();\n\tconst m = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst d = String(date.getDate()).padStart(2, \"0\");\n\treturn `${String(y)}-${m}-${d}`;\n}\n\nfunction formatDateTime(date: Date): string {\n\tconst ymd = formatDate(date);\n\tconst hh = String(date.getHours()).padStart(2, \"0\");\n\tconst mm = String(date.getMinutes()).padStart(2, \"0\");\n\tconst ss = String(date.getSeconds()).padStart(2, \"0\");\n\tconst ms = String(date.getMilliseconds()).padStart(3, \"0\");\n\treturn `${ymd} ${hh}:${mm}:${ss}.${ms}`;\n}\n\nfunction tryParseYmdDirName(dirName: string): Date | null {\n\tconst m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(dirName);\n\tif (!m) return null;\n\tconst year = Number(m[1]);\n\tconst month = Number(m[2]);\n\tconst day = Number(m[3]);\n\tif (\n\t\t!Number.isFinite(year) ||\n\t\t!Number.isFinite(month) ||\n\t\t!Number.isFinite(day)\n\t)\n\t\treturn null;\n\tconst dt = new Date(year, month - 1, day);\n\tif (dt.getFullYear() !== year) return null;\n\tif (dt.getMonth() !== month - 1) return null;\n\tif (dt.getDate() !== day) return null;\n\treturn dt;\n}\n\nfunction normalizeSmlForSingleLine(sml: string): string {\n\treturn sml.trim();\n}\n\nfunction bufferToHex(buffer: Buffer, maxHexBytes: number): string {\n\tconst len = buffer.length;\n\tconst max = Math.max(0, maxHexBytes);\n\tconst slice = len <= max ? buffer : buffer.subarray(0, max);\n\tconst hex = slice.toString(\"hex\");\n\tconst suffix = len <= max ? \"\" : `…(+${String(len - max)} bytes)`;\n\treturn `${hex}${suffix}`;\n}\n\nclass PrettyPrintTransformStream extends Transform {\n\tprivate pending = \"\";\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\toverride _transform(\n\t\tchunk: Buffer | string,\n\t\t_encoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flush();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _flush(callback: (error?: Error | null) => void): void {\n\t\tcallback();\n\t}\n\n\tprivate flush(): void {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) break;\n\t\t\tconst line = this.pending.slice(0, idx);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tif (line.length === 0) continue;\n\t\t\tconst obj = JSON.parse(line) as Record<string, unknown>;\n\t\t\tconst formatted = this.formatLine(obj);\n\t\t\tthis.push(formatted);\n\t\t}\n\t}\n\n\tprivate formatLine(obj: Record<string, unknown>): string {\n\t\tconst time = this.formatTime(obj.time);\n\t\tconst level = this.formatLevel(obj.level as number);\n\t\tconst extra = this.formatExtra(obj);\n\t\tconst msg = this.formatMessage(obj);\n\n\t\treturn `${time} ${level} ${extra} | ${msg}\\n`;\n\t}\n\n\tprivate formatTime(timeValue: unknown): string {\n\t\tif (typeof timeValue === \"number\") {\n\t\t\treturn formatDateTime(new Date(timeValue));\n\t\t}\n\t\tif (typeof timeValue === \"string\") {\n\t\t\treturn formatDateTime(new Date(timeValue));\n\t\t}\n\t\treturn formatDateTime(new Date());\n\t}\n\n\tprivate formatLevel(level: number): string {\n\t\tconst levels: Record<number, string> = {\n\t\t\t10: \"TRACE\",\n\t\t\t20: \"DEBUG\",\n\t\t\t30: \"INFO \",\n\t\t\t40: \"WARN \",\n\t\t\t50: \"ERROR\",\n\t\t\t60: \"FATAL\",\n\t\t};\n\t\treturn levels[level] ?? \"UNKNOWN\";\n\t}\n\n\tprivate formatExtra(obj: Record<string, unknown>): string {\n\t\tconst parts: string[] = [];\n\n\t\tif (typeof obj.protocol === \"string\") {\n\t\t\tparts.push(obj.protocol);\n\t\t}\n\t\tif (typeof obj.dir === \"string\") {\n\t\t\tparts.push(obj.dir);\n\t\t}\n\t\tif (typeof obj.prev === \"string\" && typeof obj.next === \"string\") {\n\t\t\tparts.push(`${obj.prev} -> ${obj.next}`);\n\t\t}\n\n\t\treturn parts.join(\" \");\n\t}\n\n\tprivate formatMessage(obj: Record<string, unknown>): string {\n\t\tconst msgValue = obj.msg;\n\t\tif (typeof msgValue === \"string\" && msgValue.trim().length > 0) {\n\t\t\treturn msgValue;\n\t\t}\n\n\t\tconst excludeKeys = new Set([\n\t\t\t\"time\",\n\t\t\t\"level\",\n\t\t\t\"msg\",\n\t\t\t\"name\",\n\t\t\t\"deviceId\",\n\t\t\t\"isEquip\",\n\t\t\t\"protocol\",\n\t\t\t\"dir\",\n\t\t\t\"prev\",\n\t\t\t\"next\",\n\t\t]);\n\n\t\tconst pairs: string[] = [];\n\t\tfor (const [key, value] of Object.entries(obj)) {\n\t\t\tif (excludeKeys.has(key)) continue;\n\t\t\tif (Buffer.isBuffer(value)) {\n\t\t\t\tpairs.push(`${key}=${value.toString(\"hex\")}`);\n\t\t\t} else if (typeof value === \"string\") {\n\t\t\t\tpairs.push(`${key}=${value}`);\n\t\t\t} else if (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\t\tpairs.push(`${key}=${String(value)}`);\n\t\t\t} else {\n\t\t\t\tpairs.push(`${key}=${this.formatValue(value)}`);\n\t\t\t}\n\t\t}\n\n\t\treturn pairs.join(\" \");\n\t}\n\n\tprivate formatValue(value: unknown): string {\n\t\tif (value === null) return \"null\";\n\t\tif (value === undefined) return \"undefined\";\n\t\tif (typeof value === \"string\") return value;\n\t\tif (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\treturn String(value);\n\t\t}\n\t\tif (Buffer.isBuffer(value)) {\n\t\t\treturn value.toString(\"hex\");\n\t\t}\n\t\tif (typeof value === \"object\") {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value);\n\t\t\t} catch {\n\t\t\t\treturn \"[object]\";\n\t\t\t}\n\t\t}\n\t\treturn String(value as string | number | bigint | boolean);\n\t}\n}\n\nclass DailyRotatingFileStream extends Writable {\n\tprivate readonly baseDir: string;\n\tprivate readonly fileNameForDate: (ymd: string) => string;\n\tprivate readonly retentionDays: number;\n\tprivate currentYmd: string | null = null;\n\tprivate currentStream: fs.WriteStream | null = null;\n\tprivate cleanupYmd: string | null = null;\n\tprivate pending = \"\";\n\n\tconstructor(params: {\n\t\tbaseDir: string;\n\t\tfileNameForDate: (ymd: string) => string;\n\t\tretentionDays: number;\n\t}) {\n\t\tsuper();\n\t\tthis.baseDir = params.baseDir;\n\t\tthis.fileNameForDate = params.fileNameForDate;\n\t\tthis.retentionDays = params.retentionDays;\n\t}\n\n\toverride _write(\n\t\tchunk: Buffer | string,\n\t\tencoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flushCompleteLines();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _final(callback: (error?: Error | null) => void): void {\n\t\ttry {\n\t\t\tif (this.pending.length > 0) {\n\t\t\t\tthis.ensureStreamForNow();\n\t\t\t\tthis.currentStream?.write(this.pending);\n\t\t\t\tthis.pending = \"\";\n\t\t\t}\n\t\t\tthis.currentStream?.end(() => callback());\n\t\t\tthis.currentStream = null;\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\tprivate flushCompleteLines() {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) break;\n\t\t\tconst line = this.pending.slice(0, idx + 1);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tthis.ensureStreamForNow();\n\t\t\tthis.currentStream?.write(line);\n\t\t}\n\t}\n\n\tprivate ensureStreamForNow() {\n\t\tconst now = new Date();\n\t\tconst ymd = formatDate(now);\n\t\tif (this.currentYmd === ymd && this.currentStream) return;\n\n\t\tif (this.currentStream) {\n\t\t\tthis.currentStream.end();\n\t\t\tthis.currentStream = null;\n\t\t}\n\n\t\tconst dir = path.join(this.baseDir, ymd);\n\t\tfs.mkdirSync(dir, { recursive: true });\n\t\tconst filePath = path.join(dir, this.fileNameForDate(ymd));\n\t\tthis.currentStream = fs.createWriteStream(filePath, { flags: \"a\" });\n\t\tthis.currentYmd = ymd;\n\n\t\tif (this.retentionDays > 0 && this.cleanupYmd !== ymd) {\n\t\t\tthis.cleanupYmd = ymd;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.cleanupOldDirs(now).catch(() => undefined);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async cleanupOldDirs(now: Date): Promise<void> {\n\t\tconst retentionDays = this.retentionDays;\n\t\tif (retentionDays <= 0) return;\n\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = await fs.promises.readdir(this.baseDir, {\n\t\t\t\twithFileTypes: true,\n\t\t\t});\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cutoff = new Date(\n\t\t\tnow.getFullYear(),\n\t\t\tnow.getMonth(),\n\t\t\tnow.getDate(),\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\tcutoff.setDate(cutoff.getDate() - retentionDays);\n\n\t\tfor (const ent of entries) {\n\t\t\tif (!ent.isDirectory()) continue;\n\t\t\tconst dirName = ent.name;\n\t\t\tconst dirDate = tryParseYmdDirName(dirName);\n\t\t\tif (!dirDate) continue;\n\t\t\tif (dirDate >= cutoff) continue;\n\t\t\tconst full = path.join(this.baseDir, dirName);\n\t\t\ttry {\n\t\t\t\tawait fs.promises.rm(full, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass Secs2LineTransformStream extends Writable {\n\tprivate readonly target: DailyRotatingFileStream;\n\tprivate pending = \"\";\n\n\tconstructor(target: DailyRotatingFileStream) {\n\t\tsuper();\n\t\tthis.target = target;\n\t}\n\n\toverride _write(\n\t\tchunk: Buffer | string,\n\t\tencoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flush();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _final(callback: (error?: Error | null) => void): void {\n\t\ttry {\n\t\t\tthis.flush(true);\n\t\t\tthis.target.end(() => callback());\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\tprivate flush(flushAll = false) {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) {\n\t\t\t\tif (flushAll && this.pending.length > 0) {\n\t\t\t\t\tthis.handleLine(this.pending);\n\t\t\t\t\tthis.pending = \"\";\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst line = this.pending.slice(0, idx);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tif (line.length === 0) continue;\n\t\t\tthis.handleLine(line);\n\t\t}\n\t}\n\n\tprivate handleLine(jsonLine: string) {\n\t\tlet obj: unknown;\n\t\ttry {\n\t\t\tobj = JSON.parse(jsonLine);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!obj || typeof obj !== \"object\") return;\n\t\tconst rec = obj as Record<string, unknown>;\n\t\tconst timeValue = rec.time;\n\t\tconst dirValue = rec.dir;\n\t\tconst smlValue = rec.sml;\n\n\t\tconst dir =\n\t\t\tdirValue === \"Sent\" || dirValue === \"Received\" ? dirValue : null;\n\t\tconst sml = typeof smlValue === \"string\" ? smlValue : null;\n\t\tif (!dir || !sml) return;\n\n\t\tlet date: Date;\n\t\tif (typeof timeValue === \"number\") {\n\t\t\tdate = new Date(timeValue);\n\t\t} else if (typeof timeValue === \"string\") {\n\t\t\tdate = new Date(timeValue);\n\t\t} else {\n\t\t\tdate = new Date();\n\t\t}\n\n\t\tconst out = `${formatDateTime(date)} ${dir} \\n${normalizeSmlForSingleLine(sml)}\\n`;\n\t\tthis.target.write(out);\n\t}\n}\n\nclass DisabledSecsLogger {\n\tdetail: Logger;\n\tsecs2: Logger;\n\tconstructor() {\n\t\tthis.detail = pino({ enabled: false });\n\t\tthis.secs2 = pino({ enabled: false });\n\t}\n\n\tlogSecs2(_direction: SecsLogDirection, _sml: string): void {\n\t\treturn;\n\t}\n\n\tlogBytes(\n\t\t_direction: SecsLogDirection,\n\t\t_protocol: string,\n\t\t_buffer: Buffer,\n\t\t_meta?: Record<string, unknown>,\n\t): void {\n\t\treturn;\n\t}\n\n\tlogState(\n\t\t_protocol: string,\n\t\t_prev: string,\n\t\t_next: string,\n\t\t_meta?: Record<string, unknown>,\n\t): void {\n\t\treturn;\n\t}\n\n\tclose(): void {\n\t\treturn;\n\t}\n}\n\nexport class SecsLogger {\n\tstatic disabled(): SecsLogger {\n\t\treturn new DisabledSecsLogger() as unknown as SecsLogger;\n\t}\n\n\tstatic create(\n\t\tconfig: SecsLoggerConfig | undefined,\n\t\tctx: SecsLoggerContext,\n\t): SecsLogger {\n\t\tconst enabled = config?.enabled ?? false;\n\t\tconst consoleEnabled = config?.console ?? false;\n\t\tif (!enabled) return SecsLogger.disabled();\n\n\t\tconst baseDir = config?.baseDir\n\t\t\t? path.resolve(config.baseDir)\n\t\t\t: path.resolve(process.cwd(), \"logs\");\n\t\tconst retentionDays = config?.retentionDays ?? 7;\n\t\tconst detailLevel = config?.detailLevel ?? \"debug\";\n\t\tconst secs2Level = config?.secs2Level ?? \"info\";\n\n\t\tconst detailStream = new DailyRotatingFileStream({\n\t\t\tbaseDir,\n\t\t\tfileNameForDate: (ymd) => `${ymd}-DETAIL.log`,\n\t\t\tretentionDays,\n\t\t});\n\n\t\tconst secs2Target = new DailyRotatingFileStream({\n\t\t\tbaseDir,\n\t\t\tfileNameForDate: (ymd) => `${ymd}-SECS-II.log`,\n\t\t\tretentionDays,\n\t\t});\n\t\tconst secs2Stream = new Secs2LineTransformStream(secs2Target);\n\n\t\tconst bindings = {\n\t\t\tname: ctx.name,\n\t\t\tdeviceId: ctx.deviceId,\n\t\t\tisEquip: ctx.isEquip,\n\t\t};\n\n\t\tconst detailStreams: pino.StreamEntry[] = [\n\t\t\t{ stream: detailStream as pino.DestinationStream },\n\t\t];\n\t\tif (consoleEnabled) {\n\t\t\tconst prettyStream = new PrettyPrintTransformStream();\n\t\t\tprettyStream.pipe(process.stdout);\n\t\t\tdetailStreams.push({\n\t\t\t\tstream: prettyStream,\n\t\t\t\tlevel: detailLevel as pino.Level,\n\t\t\t});\n\t\t}\n\t\tconst detail = pino(\n\t\t\t{ level: detailLevel, base: bindings },\n\t\t\tpino.multistream(detailStreams),\n\t\t);\n\n\t\tconst secs2Streams: pino.StreamEntry[] = [\n\t\t\t{ stream: secs2Stream as pino.DestinationStream },\n\t\t];\n\t\tif (consoleEnabled) {\n\t\t\tsecs2Streams.push({\n\t\t\t\tstream: process.stdout,\n\t\t\t\tlevel: secs2Level as pino.Level,\n\t\t\t});\n\t\t}\n\t\tconst secs2 = pino(\n\t\t\t{\n\t\t\t\tlevel: secs2Level,\n\t\t\t\tbase: null,\n\t\t\t\tmessageKey: \"msg\",\n\t\t\t},\n\t\t\tpino.multistream(secs2Streams),\n\t\t);\n\n\t\treturn new SecsLogger({\n\t\t\tconfig: { ...config, baseDir, retentionDays },\n\t\t\tdetail,\n\t\t\tsecs2,\n\t\t\tdetailStream,\n\t\t\tsecs2Target,\n\t\t\tsecs2Stream,\n\t\t});\n\t}\n\n\tpublic readonly detail: Logger;\n\tprivate readonly secs2: Logger;\n\tprivate readonly detailStream: DailyRotatingFileStream;\n\tprivate readonly secs2Target: DailyRotatingFileStream;\n\tprivate readonly secs2Stream: Secs2LineTransformStream;\n\tprivate readonly maxHexBytes: number;\n\n\tprivate constructor(params: {\n\t\tconfig: SecsLoggerConfig;\n\t\tdetail: Logger;\n\t\tsecs2: Logger;\n\t\tdetailStream: DailyRotatingFileStream;\n\t\tsecs2Target: DailyRotatingFileStream;\n\t\tsecs2Stream: Secs2LineTransformStream;\n\t}) {\n\t\tthis.detail = params.detail;\n\t\tthis.secs2 = params.secs2;\n\t\tthis.detailStream = params.detailStream;\n\t\tthis.secs2Target = params.secs2Target;\n\t\tthis.secs2Stream = params.secs2Stream;\n\t\tthis.maxHexBytes = params.config.maxHexBytes ?? 64 * 1024;\n\t}\n\n\tlogSecs2(direction: SecsLogDirection, sml: string): void {\n\t\tthis.secs2.info(\n\t\t\t{ dir: direction, sml: normalizeSmlForSingleLine(sml) },\n\t\t\t\"\",\n\t\t);\n\t}\n\n\tlogBytes(\n\t\tdirection: SecsLogDirection,\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): void {\n\t\tthis.detail.trace(\n\t\t\t{\n\t\t\t\tprotocol,\n\t\t\t\tdir: direction,\n\t\t\t\tbyteLength: buffer.length,\n\t\t\t\thex: bufferToHex(buffer, this.maxHexBytes),\n\t\t\t\t...meta,\n\t\t\t},\n\t\t\t\"bytes\",\n\t\t);\n\t}\n\n\tlogState(\n\t\tprotocol: string,\n\t\tprev: string,\n\t\tnext: string,\n\t\tmeta?: Record<string, unknown>,\n\t): void {\n\t\tthis.detail.info({ protocol, prev, next, ...meta }, \"state\");\n\t}\n\n\tclose(): void {\n\t\tthis.secs2.flush();\n\t\tthis.detail.flush();\n\t\tthis.secs2Stream.end();\n\t\tthis.secs2Target.end();\n\t\tthis.detailStream.end();\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SecsLogger.js","names":["parts: string[]","pairs: string[]","entries: fs.Dirent[]","obj: unknown","date: Date","detailStreams: pino.StreamEntry[]","secs2Streams: pino.StreamEntry[]"],"sources":["../../src/logging/SecsLogger.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { Writable, Transform } from \"stream\";\nimport pino, { type LevelWithSilent, type Logger } from \"pino\";\n\nexport type SecsLogDirection = \"Received\" | \"Sent\";\n\nexport interface SecsLoggerConfig {\n\tenabled?: boolean;\n\tconsole?: boolean;\n\tbaseDir?: string;\n\tretentionDays?: number;\n\tdetailLevel?: LevelWithSilent;\n\tsecs2Level?: LevelWithSilent;\n\tmaxHexBytes?: number;\n}\n\nexport interface SecsLoggerContext {\n\tname: string;\n\tdeviceId: number;\n\tisEquip: boolean;\n}\n\nfunction formatDate(date: Date): string {\n\tconst y = date.getFullYear();\n\tconst m = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst d = String(date.getDate()).padStart(2, \"0\");\n\treturn `${String(y)}-${m}-${d}`;\n}\n\nfunction formatDateTime(date: Date): string {\n\tconst ymd = formatDate(date);\n\tconst hh = String(date.getHours()).padStart(2, \"0\");\n\tconst mm = String(date.getMinutes()).padStart(2, \"0\");\n\tconst ss = String(date.getSeconds()).padStart(2, \"0\");\n\tconst ms = String(date.getMilliseconds()).padStart(3, \"0\");\n\treturn `${ymd} ${hh}:${mm}:${ss}.${ms}`;\n}\n\nfunction tryParseYmdDirName(dirName: string): Date | null {\n\tconst m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(dirName);\n\tif (!m) return null;\n\tconst year = Number(m[1]);\n\tconst month = Number(m[2]);\n\tconst day = Number(m[3]);\n\tif (\n\t\t!Number.isFinite(year) ||\n\t\t!Number.isFinite(month) ||\n\t\t!Number.isFinite(day)\n\t)\n\t\treturn null;\n\tconst dt = new Date(year, month - 1, day);\n\tif (dt.getFullYear() !== year) return null;\n\tif (dt.getMonth() !== month - 1) return null;\n\tif (dt.getDate() !== day) return null;\n\treturn dt;\n}\n\nfunction normalizeSmlForSingleLine(sml: string): string {\n\treturn sml.trim();\n}\n\nfunction bufferToHex(buffer: Buffer, maxHexBytes: number): string {\n\tconst len = buffer.length;\n\tconst max = Math.max(0, maxHexBytes);\n\tconst slice = len <= max ? buffer : buffer.subarray(0, max);\n\tconst hex = slice.toString(\"hex\");\n\tconst suffix = len <= max ? \"\" : `…(+${String(len - max)} bytes)`;\n\treturn `${hex}${suffix}`;\n}\n\nclass PrettyPrintTransformStream extends Transform {\n\tprivate pending = \"\";\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\toverride _transform(\n\t\tchunk: Buffer | string,\n\t\t_encoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flush();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _flush(callback: (error?: Error | null) => void): void {\n\t\tcallback();\n\t}\n\n\tprivate flush(): void {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) break;\n\t\t\tconst line = this.pending.slice(0, idx);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tif (line.length === 0) continue;\n\t\t\tconst obj = JSON.parse(line) as Record<string, unknown>;\n\t\t\tconst formatted = this.formatLine(obj);\n\t\t\tthis.push(formatted);\n\t\t}\n\t}\n\n\tprivate formatLine(obj: Record<string, unknown>): string {\n\t\tconst time = this.formatTime(obj.time);\n\t\tconst level = this.formatLevel(obj.level as number);\n\t\tconst extra = this.formatExtra(obj);\n\t\tconst msg = this.formatMessage(obj);\n\n\t\treturn `${time} ${level} ${extra} | ${msg}\\n`;\n\t}\n\n\tprivate formatTime(timeValue: unknown): string {\n\t\tif (typeof timeValue === \"number\") {\n\t\t\treturn formatDateTime(new Date(timeValue));\n\t\t}\n\t\tif (typeof timeValue === \"string\") {\n\t\t\treturn formatDateTime(new Date(timeValue));\n\t\t}\n\t\treturn formatDateTime(new Date());\n\t}\n\n\tprivate formatLevel(level: number): string {\n\t\tconst levels: Record<number, string> = {\n\t\t\t10: \"TRACE\",\n\t\t\t20: \"DEBUG\",\n\t\t\t30: \"INFO \",\n\t\t\t40: \"WARN \",\n\t\t\t50: \"ERROR\",\n\t\t\t60: \"FATAL\",\n\t\t};\n\t\treturn levels[level] ?? \"UNKNOWN\";\n\t}\n\n\tprivate formatExtra(obj: Record<string, unknown>): string {\n\t\tconst parts: string[] = [];\n\n\t\tif (typeof obj.protocol === \"string\") {\n\t\t\tparts.push(obj.protocol);\n\t\t}\n\t\tif (typeof obj.dir === \"string\") {\n\t\t\tparts.push(obj.dir);\n\t\t}\n\t\tif (typeof obj.prev === \"string\" && typeof obj.next === \"string\") {\n\t\t\tparts.push(`${obj.prev} -> ${obj.next}`);\n\t\t}\n\n\t\treturn parts.join(\" \");\n\t}\n\n\tprivate formatMessage(obj: Record<string, unknown>): string {\n\t\tconst msgValue = obj.msg;\n\t\tif (typeof msgValue === \"string\" && msgValue.trim().length > 0) {\n\t\t\treturn msgValue;\n\t\t}\n\n\t\tconst excludeKeys = new Set([\n\t\t\t\"time\",\n\t\t\t\"level\",\n\t\t\t\"msg\",\n\t\t\t\"name\",\n\t\t\t\"deviceId\",\n\t\t\t\"isEquip\",\n\t\t\t\"protocol\",\n\t\t\t\"dir\",\n\t\t\t\"prev\",\n\t\t\t\"next\",\n\t\t]);\n\n\t\tconst pairs: string[] = [];\n\t\tfor (const [key, value] of Object.entries(obj)) {\n\t\t\tif (excludeKeys.has(key)) continue;\n\t\t\tif (Buffer.isBuffer(value)) {\n\t\t\t\tpairs.push(`${key}=${value.toString(\"hex\")}`);\n\t\t\t} else if (typeof value === \"string\") {\n\t\t\t\tpairs.push(`${key}=${value}`);\n\t\t\t} else if (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\t\tpairs.push(`${key}=${String(value)}`);\n\t\t\t} else {\n\t\t\t\tpairs.push(`${key}=${this.formatValue(value)}`);\n\t\t\t}\n\t\t}\n\n\t\treturn pairs.join(\" \");\n\t}\n\n\tprivate formatValue(value: unknown): string {\n\t\tif (value === null) return \"null\";\n\t\tif (value === undefined) return \"undefined\";\n\t\tif (typeof value === \"string\") return value;\n\t\tif (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\treturn String(value);\n\t\t}\n\t\tif (Buffer.isBuffer(value)) {\n\t\t\treturn value.toString(\"hex\");\n\t\t}\n\t\tif (typeof value === \"object\") {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value);\n\t\t\t} catch {\n\t\t\t\treturn \"[object]\";\n\t\t\t}\n\t\t}\n\t\treturn String(value as string | number | bigint | boolean);\n\t}\n}\n\nclass DailyRotatingFileStream extends Writable {\n\tprivate readonly baseDir: string;\n\tprivate readonly fileNameForDate: (ymd: string) => string;\n\tprivate readonly retentionDays: number;\n\tprivate currentYmd: string | null = null;\n\tprivate currentStream: fs.WriteStream | null = null;\n\tprivate cleanupYmd: string | null = null;\n\tprivate pending = \"\";\n\n\tconstructor(params: {\n\t\tbaseDir: string;\n\t\tfileNameForDate: (ymd: string) => string;\n\t\tretentionDays: number;\n\t}) {\n\t\tsuper();\n\t\tthis.baseDir = params.baseDir;\n\t\tthis.fileNameForDate = params.fileNameForDate;\n\t\tthis.retentionDays = params.retentionDays;\n\t}\n\n\toverride _write(\n\t\tchunk: Buffer | string,\n\t\tencoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flushCompleteLines();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _final(callback: (error?: Error | null) => void): void {\n\t\ttry {\n\t\t\tif (this.pending.length > 0) {\n\t\t\t\tthis.ensureStreamForNow();\n\t\t\t\tthis.currentStream?.write(this.pending);\n\t\t\t\tthis.pending = \"\";\n\t\t\t}\n\t\t\tthis.currentStream?.end(() => callback());\n\t\t\tthis.currentStream = null;\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\tprivate flushCompleteLines() {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) break;\n\t\t\tconst line = this.pending.slice(0, idx + 1);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tthis.ensureStreamForNow();\n\t\t\tthis.currentStream?.write(line);\n\t\t}\n\t}\n\n\tprivate ensureStreamForNow() {\n\t\tconst now = new Date();\n\t\tconst ymd = formatDate(now);\n\t\tif (this.currentYmd === ymd && this.currentStream) return;\n\n\t\tif (this.currentStream) {\n\t\t\tthis.currentStream.end();\n\t\t\tthis.currentStream = null;\n\t\t}\n\n\t\tconst dir = path.join(this.baseDir, ymd);\n\t\tfs.mkdirSync(dir, { recursive: true });\n\t\tconst filePath = path.join(dir, this.fileNameForDate(ymd));\n\t\tthis.currentStream = fs.createWriteStream(filePath, { flags: \"a\" });\n\t\tthis.currentYmd = ymd;\n\n\t\tif (this.retentionDays > 0 && this.cleanupYmd !== ymd) {\n\t\t\tthis.cleanupYmd = ymd;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tthis.cleanupOldDirs(now).catch(() => undefined);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async cleanupOldDirs(now: Date): Promise<void> {\n\t\tconst retentionDays = this.retentionDays;\n\t\tif (retentionDays <= 0) return;\n\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = await fs.promises.readdir(this.baseDir, {\n\t\t\t\twithFileTypes: true,\n\t\t\t});\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cutoff = new Date(\n\t\t\tnow.getFullYear(),\n\t\t\tnow.getMonth(),\n\t\t\tnow.getDate(),\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\tcutoff.setDate(cutoff.getDate() - retentionDays);\n\n\t\tfor (const ent of entries) {\n\t\t\tif (!ent.isDirectory()) continue;\n\t\t\tconst dirName = ent.name;\n\t\t\tconst dirDate = tryParseYmdDirName(dirName);\n\t\t\tif (!dirDate) continue;\n\t\t\tif (dirDate >= cutoff) continue;\n\t\t\tconst full = path.join(this.baseDir, dirName);\n\t\t\ttry {\n\t\t\t\tawait fs.promises.rm(full, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass Secs2LineTransformStream extends Writable {\n\tprivate readonly target: DailyRotatingFileStream;\n\tprivate pending = \"\";\n\n\tconstructor(target: DailyRotatingFileStream) {\n\t\tsuper();\n\t\tthis.target = target;\n\t}\n\n\toverride _write(\n\t\tchunk: Buffer | string,\n\t\tencoding: BufferEncoding,\n\t\tcallback: (error?: Error | null) => void,\n\t): void {\n\t\ttry {\n\t\t\tconst str = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tthis.pending += str;\n\t\t\tthis.flush();\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\toverride _final(callback: (error?: Error | null) => void): void {\n\t\ttry {\n\t\t\tthis.flush(true);\n\t\t\tthis.target.end(() => callback());\n\t\t} catch (e) {\n\t\t\tcallback(e instanceof Error ? e : new Error(String(e)));\n\t\t}\n\t}\n\n\tprivate flush(flushAll = false) {\n\t\twhile (true) {\n\t\t\tconst idx = this.pending.indexOf(\"\\n\");\n\t\t\tif (idx < 0) {\n\t\t\t\tif (flushAll && this.pending.length > 0) {\n\t\t\t\t\tthis.handleLine(this.pending);\n\t\t\t\t\tthis.pending = \"\";\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst line = this.pending.slice(0, idx);\n\t\t\tthis.pending = this.pending.slice(idx + 1);\n\t\t\tif (line.length === 0) continue;\n\t\t\tthis.handleLine(line);\n\t\t}\n\t}\n\n\tprivate handleLine(jsonLine: string) {\n\t\tlet obj: unknown;\n\t\ttry {\n\t\t\tobj = JSON.parse(jsonLine);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!obj || typeof obj !== \"object\") return;\n\t\tconst rec = obj as Record<string, unknown>;\n\t\tconst timeValue = rec.time;\n\t\tconst dirValue = rec.dir;\n\t\tconst smlValue = rec.sml;\n\t\tconst deviceIdValue = rec.deviceId;\n\t\tconst systemBytesValue = rec.systemBytes;\n\n\t\tconst dir =\n\t\t\tdirValue === \"Sent\" || dirValue === \"Received\" ? dirValue : null;\n\t\tconst sml = typeof smlValue === \"string\" ? smlValue : null;\n\t\tif (!dir || !sml) return;\n\n\t\tlet date: Date;\n\t\tif (typeof timeValue === \"number\") {\n\t\t\tdate = new Date(timeValue);\n\t\t} else if (typeof timeValue === \"string\") {\n\t\t\tdate = new Date(timeValue);\n\t\t} else {\n\t\t\tdate = new Date();\n\t\t}\n\n\t\tconst deviceId = typeof deviceIdValue === \"number\" ? deviceIdValue : 0;\n\t\tconst systemBytes =\n\t\t\ttypeof systemBytesValue === \"number\" ? systemBytesValue : 0;\n\n\t\tconst out = `${formatDateTime(date)} ${dir} DeviceID: ${deviceId} SystemBytes: ${systemBytes} \\n${normalizeSmlForSingleLine(sml)}\\n`;\n\t\tthis.target.write(out);\n\t}\n}\n\nclass DisabledSecsLogger {\n\tdetail: Logger;\n\tsecs2: Logger;\n\tconstructor() {\n\t\tthis.detail = pino({ enabled: false });\n\t\tthis.secs2 = pino({ enabled: false });\n\t}\n\n\tlogSecs2(_direction: SecsLogDirection, _sml: string): void {\n\t\treturn;\n\t}\n\n\tlogBytes(\n\t\t_direction: SecsLogDirection,\n\t\t_protocol: string,\n\t\t_buffer: Buffer,\n\t\t_meta?: Record<string, unknown>,\n\t): void {\n\t\treturn;\n\t}\n\n\tlogState(\n\t\t_protocol: string,\n\t\t_prev: string,\n\t\t_next: string,\n\t\t_meta?: Record<string, unknown>,\n\t): void {\n\t\treturn;\n\t}\n\n\tclose(): void {\n\t\treturn;\n\t}\n}\n\nexport class SecsLogger {\n\tstatic disabled(): SecsLogger {\n\t\treturn new DisabledSecsLogger() as unknown as SecsLogger;\n\t}\n\n\tstatic create(\n\t\tconfig: SecsLoggerConfig | undefined,\n\t\tctx: SecsLoggerContext,\n\t): SecsLogger {\n\t\tconst enabled = config?.enabled ?? false;\n\t\tconst consoleEnabled = config?.console ?? false;\n\t\tif (!enabled) return SecsLogger.disabled();\n\n\t\tconst baseDir = config?.baseDir\n\t\t\t? path.resolve(config.baseDir)\n\t\t\t: path.resolve(process.cwd(), \"logs\");\n\t\tconst retentionDays = config?.retentionDays ?? 7;\n\t\tconst detailLevel = config?.detailLevel ?? \"debug\";\n\t\tconst secs2Level = config?.secs2Level ?? \"info\";\n\n\t\tconst detailStream = new DailyRotatingFileStream({\n\t\t\tbaseDir,\n\t\t\tfileNameForDate: (ymd) => `${ymd}-DETAIL.log`,\n\t\t\tretentionDays,\n\t\t});\n\n\t\tconst secs2Target = new DailyRotatingFileStream({\n\t\t\tbaseDir,\n\t\t\tfileNameForDate: (ymd) => `${ymd}-SECS-II.log`,\n\t\t\tretentionDays,\n\t\t});\n\t\tconst secs2Stream = new Secs2LineTransformStream(secs2Target);\n\n\t\tconst bindings = {\n\t\t\tname: ctx.name,\n\t\t\tdeviceId: ctx.deviceId,\n\t\t\tisEquip: ctx.isEquip,\n\t\t};\n\n\t\tconst detailPrettyStream = new PrettyPrintTransformStream();\n\t\tdetailPrettyStream.pipe(detailStream);\n\t\tconst detailStreams: pino.StreamEntry[] = [\n\t\t\t{ stream: detailPrettyStream as pino.DestinationStream },\n\t\t];\n\t\tif (consoleEnabled) {\n\t\t\tconst consolePrettyStream = new PrettyPrintTransformStream();\n\t\t\tconsolePrettyStream.pipe(process.stdout);\n\t\t\tdetailStreams.push({\n\t\t\t\tstream: consolePrettyStream,\n\t\t\t\tlevel: detailLevel as pino.Level,\n\t\t\t});\n\t\t}\n\t\tconst detail = pino(\n\t\t\t{ level: detailLevel, base: bindings },\n\t\t\tpino.multistream(detailStreams),\n\t\t);\n\n\t\tconst secs2ToDetailPrettyStream = new PrettyPrintTransformStream();\n\t\tsecs2ToDetailPrettyStream.pipe(detailStream);\n\t\tconst secs2Streams: pino.StreamEntry[] = [\n\t\t\t{ stream: secs2Stream as pino.DestinationStream },\n\t\t\t{ stream: secs2ToDetailPrettyStream as pino.DestinationStream },\n\t\t];\n\t\tif (consoleEnabled) {\n\t\t\tsecs2Streams.push({\n\t\t\t\tstream: process.stdout,\n\t\t\t\tlevel: secs2Level as pino.Level,\n\t\t\t});\n\t\t}\n\t\tconst secs2 = pino(\n\t\t\t{\n\t\t\t\tlevel: secs2Level,\n\t\t\t\tbase: bindings,\n\t\t\t\tmessageKey: \"msg\",\n\t\t\t},\n\t\t\tpino.multistream(secs2Streams),\n\t\t);\n\n\t\treturn new SecsLogger({\n\t\t\tconfig: { ...config, baseDir, retentionDays },\n\t\t\tdetail,\n\t\t\tsecs2,\n\t\t\tdetailStream,\n\t\t\tsecs2Target,\n\t\t\tsecs2Stream,\n\t\t});\n\t}\n\n\tpublic readonly detail: Logger;\n\tprivate readonly secs2: Logger;\n\tprivate readonly detailStream: DailyRotatingFileStream;\n\tprivate readonly secs2Target: DailyRotatingFileStream;\n\tprivate readonly secs2Stream: Secs2LineTransformStream;\n\tprivate readonly maxHexBytes: number;\n\n\tprivate constructor(params: {\n\t\tconfig: SecsLoggerConfig;\n\t\tdetail: Logger;\n\t\tsecs2: Logger;\n\t\tdetailStream: DailyRotatingFileStream;\n\t\tsecs2Target: DailyRotatingFileStream;\n\t\tsecs2Stream: Secs2LineTransformStream;\n\t}) {\n\t\tthis.detail = params.detail;\n\t\tthis.secs2 = params.secs2;\n\t\tthis.detailStream = params.detailStream;\n\t\tthis.secs2Target = params.secs2Target;\n\t\tthis.secs2Stream = params.secs2Stream;\n\t\tthis.maxHexBytes = params.config.maxHexBytes ?? 64 * 1024;\n\t}\n\n\tlogSecs2(\n\t\tdirection: SecsLogDirection,\n\t\tsml: string,\n\t\tdeviceId: number,\n\t\tsystemBytes: number,\n\t\tbuffer?: Buffer,\n\t): void {\n\t\tthis.secs2.info(\n\t\t\t{\n\t\t\t\tdir: direction,\n\t\t\t\tsml: normalizeSmlForSingleLine(sml),\n\t\t\t\tdeviceId,\n\t\t\t\tsystemBytes,\n\t\t\t\thex: buffer ? bufferToHex(buffer, this.maxHexBytes) : undefined,\n\t\t\t},\n\t\t\t\"\",\n\t\t);\n\t}\n\n\tlogBytes(\n\t\tdirection: SecsLogDirection,\n\t\tprotocol: string,\n\t\tbuffer: Buffer,\n\t\tmeta?: Record<string, unknown>,\n\t): void {\n\t\tthis.detail.trace(\n\t\t\t{\n\t\t\t\tprotocol,\n\t\t\t\tdir: direction,\n\t\t\t\tbyteLength: buffer.length,\n\t\t\t\thex: bufferToHex(buffer, this.maxHexBytes),\n\t\t\t\t...meta,\n\t\t\t},\n\t\t\t\"bytes\",\n\t\t);\n\t}\n\n\tlogState(\n\t\tprotocol: string,\n\t\tprev: string,\n\t\tnext: string,\n\t\tmeta?: Record<string, unknown>,\n\t): void {\n\t\tthis.detail.info({ protocol, prev, next, ...meta }, \"state\");\n\t}\n\n\tclose(): void {\n\t\tthis.secs2.flush();\n\t\tthis.detail.flush();\n\t\tthis.secs2Stream.end();\n\t\tthis.secs2Target.end();\n\t\tthis.detailStream.end();\n\t}\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Secs1Message.js","names":["blocks: Secs1MessageBlock[]","body: AbstractSecs2Item | null"],"sources":["../../src/secs1/Secs1Message.ts"],"sourcesContent":["import { SecsMessage } from \"../core/AbstractSecsMessage.js\";\r\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\r\nimport { Secs2ItemParser } from \"../core/secs2item/Secs2ItemParser.js\";\r\nimport { Secs1MessageBlock } from \"./Secs1MessageBlock.js\";\r\n\r\nexport class Secs1Message extends SecsMessage {\r\n\tconstructor(\r\n\t\tstream: number,\r\n\t\tfunc: number,\r\n\t\twBit: boolean,\r\n\t\tbody: AbstractSecs2Item | null,\r\n\t\tsystemBytes: number,\r\n\t\tdeviceId: number,\r\n\t\tpublic readonly rBit = false,\r\n\t) {\r\n\t\tsuper(stream, func, wBit, body, systemBytes, deviceId);\r\n\t}\r\n\r\n\t/**\r\n\t * @description Splits the message into SECS-I blocks.\r\n\t */\r\n\ttoBlocks(): Secs1MessageBlock[] {\r\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\r\n\t\tconst blocks: Secs1MessageBlock[] = [];\r\n\r\n\t\tlet pos = 0;\r\n\t\tlet blockNum = 1;\r\n\r\n\t\tif (bodyBuffer.length === 0) {\r\n\t\t\t// Header only block? Or empty body block?\r\n\t\t\t// SECS-I allows empty body.\r\n\t\t\tblocks.push(\r\n\t\t\t\tSecs1MessageBlock.fromParts(\r\n\t\t\t\t\tthis.deviceId,\r\n\t\t\t\t\tthis.stream,\r\n\t\t\t\t\tthis.func,\r\n\t\t\t\t\tthis.wBit,\r\n\t\t\t\t\ttrue, // E-Bit\r\n\t\t\t\t\tblockNum,\r\n\t\t\t\t\tthis.systemBytes,\r\n\t\t\t\t\tBuffer.alloc(0),\r\n\t\t\t\t\tthis.rBit,\r\n\t\t\t\t),\r\n\t\t\t);\r\n\t\t\treturn blocks;\r\n\t\t}\r\n\r\n\t\twhile (pos < bodyBuffer.length) {\r\n\t\t\tconst remaining = bodyBuffer.length - pos;\r\n\t\t\tconst chunkSize = remaining > 244 ? 244 : remaining;\r\n\t\t\tconst chunk = bodyBuffer.subarray(pos, pos + chunkSize);\r\n\t\t\tconst isLast = pos + chunkSize >= bodyBuffer.length;\r\n\r\n\t\t\tblocks.push(\r\n\t\t\t\tSecs1MessageBlock.fromParts(\r\n\t\t\t\t\tthis.deviceId,\r\n\t\t\t\t\tthis.stream,\r\n\t\t\t\t\tthis.func,\r\n\t\t\t\t\tthis.wBit,\r\n\t\t\t\t\tisLast, // E-Bit\r\n\t\t\t\t\tblockNum,\r\n\t\t\t\t\tthis.systemBytes,\r\n\t\t\t\t\tchunk,\r\n\t\t\t\t\tthis.rBit,\r\n\t\t\t\t),\r\n\t\t\t);\r\n\r\n\t\t\tpos += chunkSize;\r\n\t\t\tblockNum++;\r\n\t\t\tif (blockNum > 0x7fff) {\r\n\t\t\t\tthrow new Error(\"Block number overflow\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn blocks;\r\n\t}\r\n\r\n\t/**\r\n\t * Reassembles a SECS-I message from blocks.\r\n\t */\r\n\tstatic fromBlocks(blocks: Secs1MessageBlock[]): Secs1Message {\r\n\t\tif (blocks.length === 0) {\r\n\t\t\tthrow new Error(\"No blocks to reassemble\");\r\n\t\t}\r\n\r\n\t\t// Sort by block number just in case (though usually they come in order)\r\n\t\tblocks.sort((a, b) => a.blockNumber - b.blockNumber);\r\n\r\n\t\t// Validate sequence\r\n\t\tfor (let i = 0; i < blocks.length; i++) {\r\n\t\t\tif (blocks[i].blockNumber !== i + 1) {\r\n\t\t\t\tthrow new Error(`Missing block ${i + 1}`);\r\n\t\t\t}\r\n\t\t\t// Check if all blocks belong to the same message (SystemBytes, Stream, Func, DeviceID)\r\n\t\t\tif (i > 0) {\r\n\t\t\t\tconst prev = blocks[i - 1];\r\n\t\t\t\tconst curr = blocks[i];\r\n\t\t\t\tif (\r\n\t\t\t\t\tprev.systemBytes !== curr.systemBytes ||\r\n\t\t\t\t\tprev.stream !== curr.stream ||\r\n\t\t\t\t\tprev.func !== curr.func ||\r\n\t\t\t\t\tprev.deviceId !== curr.deviceId\r\n\t\t\t\t) {\r\n\t\t\t\t\tthrow new Error(\"Blocks do not belong to the same message\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!blocks[blocks.length - 1].eBit) {\r\n\t\t\tthrow new Error(\"Last block missing E-Bit\");\r\n\t\t}\r\n\r\n\t\tconst first = blocks[0];\r\n\t\tconst bodyBuffers = blocks.map((b) => b.body);\r\n\t\tconst fullBodyBuffer = Buffer.concat(bodyBuffers);\r\n\r\n\t\tlet body: AbstractSecs2Item | null = null;\r\n\t\tif (fullBodyBuffer.length > 0) {\r\n\t\t\tconst result = Secs2ItemParser.fromBuffer(fullBodyBuffer);\r\n\t\t\tbody = result.item;\r\n\t\t}\r\n\r\n\t\treturn new Secs1Message(\r\n\t\t\tfirst.stream,\r\n\t\t\tfirst.func,\r\n\t\t\tfirst.wBit,\r\n\t\t\tbody,\r\n\t\t\tfirst.systemBytes,\r\n\t\t\tfirst.deviceId,\r\n\t\t\tfirst.rBit,\r\n\t\t);\r\n\t}\r\n\r\n\t// Override toBuffer to return logical buffer (10-byte header + body)\r\n\ttoBuffer(): Buffer {\r\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\r\n\t\tconst header = Buffer.alloc(10);\r\n\r\n\t\t// Byte 0: R-Bit + DeviceID MSB\r\n\t\tlet b0 = (this.deviceId >> 8) & 0x7f;\r\n\t\tif (this.rBit) b0 |= 0x80;\r\n\t\theader[0] = b0;\r\n\r\n\t\t// Byte 1: DeviceID LSB\r\n\t\theader[1] = this.deviceId & 0xff;\r\n\r\n\t\t// Byte 2: W-Bit + Stream\r\n\t\tlet b2 = this.stream & 0x7f;\r\n\t\tif (this.wBit) b2 |= 0x80;\r\n\t\theader[2] = b2;\r\n\r\n\t\t// Byte 3: Function\r\n\t\theader[3] = this.func & 0xff;\r\n\r\n\t\t// Byte 4: E-Bit + BlockNum (Logical 0 or 1? For logical message, maybe 0)\r\n\t\t// Usually block number is per block. For a \"Message Buffer\", we don't have block number.\r\n\t\t// We'll leave it 0 or standard.\r\n\t\theader[4] = 0;\r\n\t\theader[5] = 0;\r\n\r\n\t\t// Byte 6-9: System Bytes\r\n\t\theader.writeUInt32BE(this.systemBytes, 6);\r\n\r\n\t\treturn Buffer.concat([header, bodyBuffer]);\r\n\t}\r\n}\r\n"],"mappings":";;;;;AAKA,IAAa,eAAb,MAAa,qBAAqB,YAAY;CAC7C,YACC,QACA,MACA,MACA,MACA,aACA,UACA,AAAgB,OAAO,OACtB;AACD,QAAM,QAAQ,MAAM,MAAM,MAAM,aAAa,SAAS;EAFtC;;;;;CAQjB,WAAgC;EAC/B,MAAM,aAAa,KAAK,OAAO,KAAK,KAAK,UAAU,GAAG,OAAO,MAAM,EAAE;EACrE,MAAMA,SAA8B,EAAE;EAEtC,IAAI,MAAM;EACV,IAAI,WAAW;AAEf,MAAI,WAAW,WAAW,GAAG;AAG5B,UAAO,KACN,kBAAkB,UACjB,KAAK,UACL,KAAK,QACL,KAAK,MACL,KAAK,MACL,MACA,UACA,KAAK,aACL,OAAO,MAAM,EAAE,EACf,KAAK,KACL,CACD;AACD,UAAO;;AAGR,SAAO,MAAM,WAAW,QAAQ;GAC/B,MAAM,YAAY,WAAW,SAAS;GACtC,MAAM,YAAY,YAAY,MAAM,MAAM;GAC1C,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM,UAAU;GACvD,MAAM,SAAS,MAAM,aAAa,WAAW;AAE7C,UAAO,KACN,kBAAkB,UACjB,KAAK,UACL,KAAK,QACL,KAAK,MACL,KAAK,MACL,QACA,UACA,KAAK,aACL,OACA,KAAK,KACL,CACD;AAED,UAAO;AACP;AACA,OAAI,WAAW,MACd,OAAM,IAAI,MAAM,wBAAwB;;AAI1C,SAAO;;;;;CAMR,OAAO,WAAW,QAA2C;AAC5D,MAAI,OAAO,WAAW,EACrB,OAAM,IAAI,MAAM,0BAA0B;AAI3C,SAAO,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,YAAY;AAGpD,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,OAAI,OAAO,GAAG,gBAAgB,IAAI,EACjC,OAAM,IAAI,MAAM,iBAAiB,IAAI,IAAI;AAG1C,OAAI,IAAI,GAAG;IACV,MAAM,OAAO,OAAO,IAAI;IACxB,MAAM,OAAO,OAAO;AACpB,QACC,KAAK,gBAAgB,KAAK,eAC1B,KAAK,WAAW,KAAK,UACrB,KAAK,SAAS,KAAK,QACnB,KAAK,aAAa,KAAK,SAEvB,OAAM,IAAI,MAAM,2CAA2C;;;AAK9D,MAAI,CAAC,OAAO,OAAO,SAAS,GAAG,KAC9B,OAAM,IAAI,MAAM,2BAA2B;EAG5C,MAAM,QAAQ,OAAO;EACrB,MAAM,cAAc,OAAO,KAAK,MAAM,EAAE,KAAK;EAC7C,MAAM,iBAAiB,OAAO,OAAO,YAAY;EAEjD,IAAIC,OAAiC;AACrC,MAAI,eAAe,SAAS,EAE3B,QADe,gBAAgB,WAAW,eAAe,CAC3C;AAGf,SAAO,IAAI,aACV,MAAM,QACN,MAAM,MACN,MAAM,MACN,MACA,MAAM,aACN,MAAM,UACN,MAAM,KACN;;CAIF,WAAmB;EAClB,MAAM,aAAa,KAAK,OAAO,KAAK,KAAK,UAAU,GAAG,OAAO,MAAM,EAAE;EACrE,MAAM,SAAS,OAAO,MAAM,GAAG;EAG/B,IAAI,KAAM,KAAK,YAAY,IAAK;AAChC,MAAI,KAAK,KAAM,OAAM;AACrB,SAAO,KAAK;AAGZ,SAAO,KAAK,KAAK,WAAW;EAG5B,IAAI,KAAK,KAAK,SAAS;AACvB,MAAI,KAAK,KAAM,OAAM;AACrB,SAAO,KAAK;AAGZ,SAAO,KAAK,KAAK,OAAO;AAKxB,SAAO,KAAK;AACZ,SAAO,KAAK;AAGZ,SAAO,cAAc,KAAK,aAAa,EAAE;AAEzC,SAAO,OAAO,OAAO,CAAC,QAAQ,WAAW,CAAC"}
1
+ {"version":3,"file":"Secs1Message.js","names":["blocks: Secs1MessageBlock[]","body: AbstractSecs2Item | null"],"sources":["../../src/secs1/Secs1Message.ts"],"sourcesContent":["import { SecsMessage } from \"../core/AbstractSecsMessage.js\";\nimport { AbstractSecs2Item } from \"../core/secs2item/AbstractSecs2Item.js\";\nimport { Secs2ItemParser } from \"../core/secs2item/Secs2ItemParser.js\";\nimport { Secs1MessageBlock } from \"./Secs1MessageBlock.js\";\n\nexport class Secs1Message extends SecsMessage {\n\tconstructor(\n\t\tstream: number,\n\t\tfunc: number,\n\t\twBit: boolean,\n\t\tbody: AbstractSecs2Item | null,\n\t\tsystemBytes: number,\n\t\tdeviceId: number,\n\t\tpublic readonly rBit = false,\n\t) {\n\t\tsuper(stream, func, wBit, body, systemBytes, deviceId);\n\t}\n\n\t/**\n\t * @description Splits the message into SECS-I blocks.\n\t */\n\ttoBlocks(): Secs1MessageBlock[] {\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\n\t\tconst blocks: Secs1MessageBlock[] = [];\n\n\t\tlet pos = 0;\n\t\tlet blockNum = 1;\n\n\t\tif (bodyBuffer.length === 0) {\n\t\t\t// Header only block? Or empty body block?\n\t\t\t// SECS-I allows empty body.\n\t\t\tblocks.push(\n\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\tthis.deviceId,\n\t\t\t\t\tthis.stream,\n\t\t\t\t\tthis.func,\n\t\t\t\t\tthis.wBit,\n\t\t\t\t\ttrue, // E-Bit\n\t\t\t\t\tblockNum,\n\t\t\t\t\tthis.systemBytes,\n\t\t\t\t\tBuffer.alloc(0),\n\t\t\t\t\tthis.rBit,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn blocks;\n\t\t}\n\n\t\twhile (pos < bodyBuffer.length) {\n\t\t\tconst remaining = bodyBuffer.length - pos;\n\t\t\tconst chunkSize = remaining > 244 ? 244 : remaining;\n\t\t\tconst chunk = bodyBuffer.subarray(pos, pos + chunkSize);\n\t\t\tconst isLast = pos + chunkSize >= bodyBuffer.length;\n\n\t\t\tblocks.push(\n\t\t\t\tSecs1MessageBlock.fromParts(\n\t\t\t\t\tthis.deviceId,\n\t\t\t\t\tthis.stream,\n\t\t\t\t\tthis.func,\n\t\t\t\t\tthis.wBit,\n\t\t\t\t\tisLast, // E-Bit\n\t\t\t\t\tblockNum,\n\t\t\t\t\tthis.systemBytes,\n\t\t\t\t\tchunk,\n\t\t\t\t\tthis.rBit,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tpos += chunkSize;\n\t\t\tblockNum++;\n\t\t\tif (blockNum > 0x7fff) {\n\t\t\t\tthrow new Error(\"Block number overflow\");\n\t\t\t}\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\t/**\n\t * Reassembles a SECS-I message from blocks.\n\t */\n\tstatic fromBlocks(blocks: Secs1MessageBlock[]): Secs1Message {\n\t\tif (blocks.length === 0) {\n\t\t\tthrow new Error(\"No blocks to reassemble\");\n\t\t}\n\n\t\t// Sort by block number just in case (though usually they come in order)\n\t\tblocks.sort((a, b) => a.blockNumber - b.blockNumber);\n\n\t\t// Validate sequence\n\t\tfor (let i = 0; i < blocks.length; i++) {\n\t\t\tif (blocks[i].blockNumber !== i + 1) {\n\t\t\t\tthrow new Error(`Missing block ${i + 1}`);\n\t\t\t}\n\t\t\t// Check if all blocks belong to the same message (SystemBytes, Stream, Func, DeviceID)\n\t\t\tif (i > 0) {\n\t\t\t\tconst prev = blocks[i - 1];\n\t\t\t\tconst curr = blocks[i];\n\t\t\t\tif (\n\t\t\t\t\tprev.systemBytes !== curr.systemBytes ||\n\t\t\t\t\tprev.stream !== curr.stream ||\n\t\t\t\t\tprev.func !== curr.func ||\n\t\t\t\t\tprev.deviceId !== curr.deviceId\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\"Blocks do not belong to the same message\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!blocks[blocks.length - 1].eBit) {\n\t\t\tthrow new Error(\"Last block missing E-Bit\");\n\t\t}\n\n\t\tconst first = blocks[0];\n\t\tconst bodyBuffers = blocks.map((b) => b.body);\n\t\tconst fullBodyBuffer = Buffer.concat(bodyBuffers);\n\n\t\tlet body: AbstractSecs2Item | null = null;\n\t\tif (fullBodyBuffer.length > 0) {\n\t\t\tconst result = Secs2ItemParser.fromBuffer(fullBodyBuffer);\n\t\t\tbody = result.item;\n\t\t}\n\n\t\treturn new Secs1Message(\n\t\t\tfirst.stream,\n\t\t\tfirst.func,\n\t\t\tfirst.wBit,\n\t\t\tbody,\n\t\t\tfirst.systemBytes,\n\t\t\tfirst.deviceId,\n\t\t\tfirst.rBit,\n\t\t);\n\t}\n\n\t// Override toBuffer to return logical buffer (10-byte header + body)\n\ttoBuffer(): Buffer {\n\t\tconst bodyBuffer = this.body ? this.body.toBuffer() : Buffer.alloc(0);\n\t\tconst header = Buffer.alloc(10);\n\n\t\t// Byte 0: R-Bit + DeviceID MSB\n\t\tlet b0 = (this.deviceId >> 8) & 0x7f;\n\t\tif (this.rBit) b0 |= 0x80;\n\t\theader[0] = b0;\n\n\t\t// Byte 1: DeviceID LSB\n\t\theader[1] = this.deviceId & 0xff;\n\n\t\t// Byte 2: W-Bit + Stream\n\t\tlet b2 = this.stream & 0x7f;\n\t\tif (this.wBit) b2 |= 0x80;\n\t\theader[2] = b2;\n\n\t\t// Byte 3: Function\n\t\theader[3] = this.func & 0xff;\n\n\t\t// Byte 4: E-Bit + BlockNum (Logical 0 or 1? For logical message, maybe 0)\n\t\t// Usually block number is per block. For a \"Message Buffer\", we don't have block number.\n\t\t// We'll leave it 0 or standard.\n\t\theader[4] = 0;\n\t\theader[5] = 0;\n\n\t\t// Byte 6-9: System Bytes\n\t\theader.writeUInt32BE(this.systemBytes, 6);\n\n\t\treturn Buffer.concat([header, bodyBuffer]);\n\t}\n}\n"],"mappings":";;;;;AAKA,IAAa,eAAb,MAAa,qBAAqB,YAAY;CAC7C,YACC,QACA,MACA,MACA,MACA,aACA,UACA,AAAgB,OAAO,OACtB;AACD,QAAM,QAAQ,MAAM,MAAM,MAAM,aAAa,SAAS;EAFtC;;;;;CAQjB,WAAgC;EAC/B,MAAM,aAAa,KAAK,OAAO,KAAK,KAAK,UAAU,GAAG,OAAO,MAAM,EAAE;EACrE,MAAMA,SAA8B,EAAE;EAEtC,IAAI,MAAM;EACV,IAAI,WAAW;AAEf,MAAI,WAAW,WAAW,GAAG;AAG5B,UAAO,KACN,kBAAkB,UACjB,KAAK,UACL,KAAK,QACL,KAAK,MACL,KAAK,MACL,MACA,UACA,KAAK,aACL,OAAO,MAAM,EAAE,EACf,KAAK,KACL,CACD;AACD,UAAO;;AAGR,SAAO,MAAM,WAAW,QAAQ;GAC/B,MAAM,YAAY,WAAW,SAAS;GACtC,MAAM,YAAY,YAAY,MAAM,MAAM;GAC1C,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM,UAAU;GACvD,MAAM,SAAS,MAAM,aAAa,WAAW;AAE7C,UAAO,KACN,kBAAkB,UACjB,KAAK,UACL,KAAK,QACL,KAAK,MACL,KAAK,MACL,QACA,UACA,KAAK,aACL,OACA,KAAK,KACL,CACD;AAED,UAAO;AACP;AACA,OAAI,WAAW,MACd,OAAM,IAAI,MAAM,wBAAwB;;AAI1C,SAAO;;;;;CAMR,OAAO,WAAW,QAA2C;AAC5D,MAAI,OAAO,WAAW,EACrB,OAAM,IAAI,MAAM,0BAA0B;AAI3C,SAAO,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,YAAY;AAGpD,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,OAAI,OAAO,GAAG,gBAAgB,IAAI,EACjC,OAAM,IAAI,MAAM,iBAAiB,IAAI,IAAI;AAG1C,OAAI,IAAI,GAAG;IACV,MAAM,OAAO,OAAO,IAAI;IACxB,MAAM,OAAO,OAAO;AACpB,QACC,KAAK,gBAAgB,KAAK,eAC1B,KAAK,WAAW,KAAK,UACrB,KAAK,SAAS,KAAK,QACnB,KAAK,aAAa,KAAK,SAEvB,OAAM,IAAI,MAAM,2CAA2C;;;AAK9D,MAAI,CAAC,OAAO,OAAO,SAAS,GAAG,KAC9B,OAAM,IAAI,MAAM,2BAA2B;EAG5C,MAAM,QAAQ,OAAO;EACrB,MAAM,cAAc,OAAO,KAAK,MAAM,EAAE,KAAK;EAC7C,MAAM,iBAAiB,OAAO,OAAO,YAAY;EAEjD,IAAIC,OAAiC;AACrC,MAAI,eAAe,SAAS,EAE3B,QADe,gBAAgB,WAAW,eAAe,CAC3C;AAGf,SAAO,IAAI,aACV,MAAM,QACN,MAAM,MACN,MAAM,MACN,MACA,MAAM,aACN,MAAM,UACN,MAAM,KACN;;CAIF,WAAmB;EAClB,MAAM,aAAa,KAAK,OAAO,KAAK,KAAK,UAAU,GAAG,OAAO,MAAM,EAAE;EACrE,MAAM,SAAS,OAAO,MAAM,GAAG;EAG/B,IAAI,KAAM,KAAK,YAAY,IAAK;AAChC,MAAI,KAAK,KAAM,OAAM;AACrB,SAAO,KAAK;AAGZ,SAAO,KAAK,KAAK,WAAW;EAG5B,IAAI,KAAK,KAAK,SAAS;AACvB,MAAI,KAAK,KAAM,OAAM;AACrB,SAAO,KAAK;AAGZ,SAAO,KAAK,KAAK,OAAO;AAKxB,SAAO,KAAK;AACZ,SAAO,KAAK;AAGZ,SAAO,cAAc,KAAK,aAAa,EAAE;AAEzC,SAAO,OAAO,OAAO,CAAC,QAAQ,WAAW,CAAC"}