1+ /* client.js */
12const WebSocket = require ( 'ws' ) ;
23const root = require ( './generated/containerPb.js' ) ;
34const Container = root . DBMessaging . Protobuf . Container ;
45const CDPValueType = root . ICD . Protobuf . CDPValueType ;
56
7+ /**
8+ * A client for interacting with CDP Logger or LogServer via WebSocket.
9+ */
610class Client {
711 /**
812 * @param {string } endpoint - The logger endpoint (e.g. "127.0.0.1:17000" or "ws://127.0.0.1:17000")
@@ -27,7 +31,7 @@ class Client {
2731 this . nameToId = { } ;
2832 this . idToName = { } ;
2933
30- // New mapping for signal types.
34+ // Mapping for signal types (in case we need to interpret values) .
3135 this . nameToType = { } ;
3236
3337 // Time-diff related
@@ -43,7 +47,13 @@ class Client {
4347
4448 /**
4549 * Enable or disable time synchronization.
46- * @param {boolean } enable - If true, time sync is enabled; if false, time sync is disabled.
50+ *
51+ * Note:
52+ * Time sync is triggered on-demand (e.g., with the next request) or after a timeout.
53+ * Re-enabling time sync will automatically sync on the next operation.
54+ * For immediate sync, call `_updateTimeDiff()` explicitly.
55+ *
56+ * @param {boolean } enable - True to enable, false to disable time sync.
4757 */
4858 setEnableTimeSync ( enable ) {
4959 this . enableTimeSync = enable ;
@@ -174,17 +184,50 @@ class Client {
174184
175185 /**
176186 * Request events based on the provided query parameters.
187+ *
188+ * The `query.flags` field uses bitmask values similar to an enum:
189+ * 0 = None
190+ * 1 = NewestFirst
191+ * 2 = TimeRangeBeginExclusive
192+ * 4 = TimeRangeEndExclusive
193+ * 8 = UseLogStampForTimeRange
194+ *
195+ * The `query.senderConditions` field can be used to filter by event sender (Source).
196+ * The `query.dataConditions` field can be used to filter by data fields (key-value patterns).
197+ *
198+ * For additional information:
199+ * https://cdpstudio.com/manual/cdp/cdplogger/eventlogreader.html#Flags-enum
200+ * https://cdpstudio.com/manual/cdp/cdplogger/eventlogreader.html#cdp-event-code-flags
201+ *
202+ * We also support mapping the `evt.code` field to a human-readable string
203+ * with `getEventCodeDescription()`.
204+ *
177205 * @param {Object } query - An object matching the EventQuery schema.
178- * For example :
206+ * Example :
179207 * {
180208 * timeRangeBegin: 1620000000,
181- * timeRangeEnd: 1620003600,
182- * codeMask: 0,
183- * limit: 100,
184- * offset: 0,
185- * flags: 1
209+ * timeRangeEnd: 1620003600,
210+ * codeMask: 0xFFFFFFFF,
211+ * limit: 100,
212+ * offset: 0,
213+ * flags: 1, // e.g. 'NewestFirst'
214+ *
215+ * // Example conditions:
216+ * senderConditions: {
217+ * conditions: [
218+ * { value: "*TemperatureSensor*", type: 1 } // 1 = Wildcard
219+ * ]
220+ * },
221+ * dataConditions: {
222+ * pressure: {
223+ * conditions: [
224+ * { value: "high", type: 0 } // 0 = Exact
225+ * ]
226+ * }
227+ * }
186228 * }
187- * @returns {Promise<Array> } Resolves with an array of events.
229+ *
230+ * @returns {Promise<Array> } Resolves with an array of events (each event includes a 'codeDescription').
188231 */
189232 requestEvents ( query ) {
190233 this . _timeRequest ( ) ;
@@ -202,11 +245,41 @@ class Client {
202245 _sendEventsRequest ( requestId , query ) {
203246 const container = Container . create ( ) ;
204247 container . messageType = Container . Type . eEventsRequest ;
205- container . eventsRequest = { requestId : requestId , query : query } ;
248+ container . eventsRequest = { requestId, query } ;
206249 const buffer = Container . encode ( container ) . finish ( ) ;
207250 this . ws . send ( buffer ) ;
208251 }
209252
253+ /**
254+ * Converts a numeric CDP event code into a descriptive string.
255+ * Multiple flags can be set simultaneously, so we combine them.
256+ *
257+ * Common codes (from the docs):
258+ * 0x1 = AlarmSet
259+ * 0x2 = AlarmClr
260+ * 0x4 = AlarmAck
261+ * 0x40 = AlarmReprise
262+ * 0x100 = SourceObjectUnavailable
263+ * 0x40000000 = NodeBoot
264+ *
265+ * @param {number } code - The event code from an eEventsResponse
266+ * @returns {string } - A human-readable combination of flags
267+ */
268+ getEventCodeDescription ( code ) {
269+ const flags = [ ] ;
270+ if ( code & 0x1 ) flags . push ( "AlarmSet" ) ;
271+ if ( code & 0x2 ) flags . push ( "AlarmClr" ) ;
272+ if ( code & 0x4 ) flags . push ( "AlarmAck" ) ;
273+ if ( code & 0x40 ) flags . push ( "AlarmReprise" ) ;
274+ if ( code & 0x100 ) flags . push ( "SourceObjectUnavailable" ) ;
275+ if ( code & 0x40000000 ) flags . push ( "NodeBoot" ) ;
276+
277+ if ( flags . length === 0 ) {
278+ flags . push ( "None" ) ;
279+ }
280+ return flags . join ( " + " ) ;
281+ }
282+
210283 _handleMessage ( ws , message ) {
211284 const data = Container . decode ( new Uint8Array ( message ) ) ;
212285 this . _parseMessage ( data ) ;
@@ -292,13 +365,13 @@ class Client {
292365 }
293366
294367 case Container . Type . eSignalDataResponse : {
295- let dataPoints = [ ] ;
368+ const dataPoints = [ ] ;
296369 let index = 0 ;
297370 for ( const row of data . signalDataResponse . row ) {
298371 if ( this . enableTimeSync ) {
299372 data . signalDataResponse . criterion [ index ] += this . timeDiff ;
300373 }
301- let signalNames = [ ] ;
374+ const signalNames = [ ] ;
302375 for ( const signalId of row . signalId ) {
303376 signalNames . push ( this . idToName [ signalId ] ) ;
304377 }
@@ -310,7 +383,7 @@ class Client {
310383 ) ;
311384 dataPoints . push ( {
312385 timestamp : data . signalDataResponse . criterion [ index ] ,
313- value : value
386+ value
314387 } ) ;
315388 index ++ ;
316389 }
@@ -323,6 +396,13 @@ class Client {
323396 }
324397
325398 case Container . Type . eEventsResponse : {
399+ // Optionally enrich each event with a human-readable code description:
400+ if ( data . eventsResponse . events && data . eventsResponse . events . length > 0 ) {
401+ data . eventsResponse . events . forEach ( evt => {
402+ evt . codeDescription = this . getEventCodeDescription ( evt . code ) ;
403+ } ) ;
404+ }
405+
326406 if ( this . storedPromises [ data . eventsResponse . requestId ] ) {
327407 const { resolve } = this . storedPromises [ data . eventsResponse . requestId ] ;
328408 delete this . storedPromises [ data . eventsResponse . requestId ] ;
@@ -452,11 +532,11 @@ class Client {
452532 } ) ;
453533 return promise ;
454534 }
455-
535+
456536 _sendTimeRequest ( requestId ) {
457537 const container = Container . create ( ) ;
458538 container . messageType = Container . Type . eTimeRequest ;
459- container . timeRequest = { requestId : requestId } ;
539+ container . timeRequest = { requestId } ;
460540 const buffer = Container . encode ( container ) . finish ( ) ;
461541 this . ws . send ( buffer ) ;
462542 }
@@ -484,15 +564,15 @@ class Client {
484564 _sendLoggedNodesRequest ( requestId ) {
485565 const container = Container . create ( ) ;
486566 container . messageType = Container . Type . eSignalInfoRequest ;
487- container . signalInfoRequest = { requestId : requestId } ;
567+ container . signalInfoRequest = { requestId } ;
488568 const buffer = Container . encode ( container ) . finish ( ) ;
489569 this . ws . send ( buffer ) ;
490570 }
491571
492572 _sendLogLimitsRequest ( requestId ) {
493573 const container = Container . create ( ) ;
494574 container . messageType = Container . Type . eCriterionLimitsRequest ;
495- container . criterionLimitsRequest = { requestId : requestId } ;
575+ container . criterionLimitsRequest = { requestId } ;
496576 const buffer = Container . encode ( container ) . finish ( ) ;
497577 this . ws . send ( buffer ) ;
498578 }
@@ -545,7 +625,7 @@ class Client {
545625 const container = Container . create ( ) ;
546626 container . messageType = Container . Type . eSignalDataRequest ;
547627 container . signalDataRequest = {
548- requestId : requestId ,
628+ requestId,
549629 signalId : nodeIds ,
550630 numOfDatapoints : noOfDataPoints ,
551631 criterionMin : this . enableTimeSync ? ( startS - this . timeDiff ) : startS ,
@@ -558,7 +638,7 @@ class Client {
558638 _sendApiVersionRequest ( requestId ) {
559639 const container = Container . create ( ) ;
560640 container . messageType = Container . Type . eVersionRequest ;
561- container . versionRequest = { requestId : requestId } ;
641+ container . versionRequest = { requestId } ;
562642 const buffer = Container . encode ( container ) . finish ( ) ;
563643 this . ws . send ( buffer ) ;
564644 }
0 commit comments