1- /* client.js */
1+ // client.js
22const WebSocket = require ( 'ws' ) ;
33const root = require ( './generated/containerPb.js' ) ;
44const Container = root . DBMessaging . Protobuf . Container ;
@@ -21,9 +21,7 @@ class Client {
2121
2222 this . reqId = - 1 ;
2323 this . autoReconnect = autoReconnect ;
24-
25- // Time synchronization is enabled by default.
26- this . enableTimeSync = true ;
24+ this . enableTimeSync = true ; // Time synchronization is enabled by default.
2725
2826 this . isOpen = false ;
2927 this . queuedRequests = { } ;
@@ -129,6 +127,9 @@ class Client {
129127
130128 // --- Public API methods ---
131129
130+ /**
131+ * Request the API version.
132+ */
132133 requestApiVersion ( ) {
133134 this . _timeRequest ( ) ;
134135 const requestId = this . _getRequestId ( ) ;
@@ -142,6 +143,9 @@ class Client {
142143 } ) ;
143144 }
144145
146+ /**
147+ * Request the list of logged nodes.
148+ */
145149 requestLoggedNodes ( ) {
146150 this . _timeRequest ( ) ;
147151 const requestId = this . _getRequestId ( ) ;
@@ -155,6 +159,9 @@ class Client {
155159 } ) ;
156160 }
157161
162+ /**
163+ * Request the log limits.
164+ */
158165 requestLogLimits ( ) {
159166 this . _timeRequest ( ) ;
160167 const requestId = this . _getRequestId ( ) ;
@@ -168,6 +175,14 @@ class Client {
168175 } ) ;
169176 }
170177
178+ /**
179+ * Request data points for given node names and time range.
180+ * @param {Array<string> } nodeNames
181+ * @param {number } startS
182+ * @param {number } endS
183+ * @param {number } noOfDataPoints
184+ * @returns {Promise<Array> }
185+ */
171186 requestDataPoints ( nodeNames , startS , endS , noOfDataPoints ) {
172187 this . _timeRequest ( ) ;
173188 const requestId = this . _getRequestId ( ) ;
@@ -186,62 +201,62 @@ class Client {
186201 * Request events based on the provided query parameters.
187202 *
188203 * 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
194204 *
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).
205+ * 0 = None
206+ * 1 = NewestFirst
207+ * 2 = TimeRangeBeginExclusive
208+ * 4 = TimeRangeEndExclusive
209+ * 8 = UseLogStampForTimeRange
210+ *
211+ * In addition, the user can simply supply the following properties in the query object:
197212 *
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
213+ * - **senderConditions**: An array of sender strings (exact matches by default).
214+ * - **dataConditions**: An object where each key is a data field name and the value can be:
215+ * - A string (defaults to an exact match),
216+ * - An array of strings,
217+ * - An object (or array of objects) with properties:
218+ * - `value`: the string value to match,
219+ * - `matchType`: either `"exact"` (default) or `"wildcard"`.
201220 *
202- * We also support mapping the `evt.code` field to a human-readable string
203- * with `getEventCodeDescription()` .
221+ * The helper method `_buildEventQuery(query)` converts this simple plain object into a proper
222+ * `DBMessaging.Protobuf.EventQuery` message .
204223 *
205- * @param {Object } query - An object matching the EventQuery schema.
206- * Example:
207- * {
208- * timeRangeBegin: 1620000000,
209- * timeRangeEnd: 1620003600,
210- * codeMask: 0xFFFFFFFF,
211- * limit: 100,
212- * offset: 0,
213- * flags: 1, // e.g. 'NewestFirst'
224+ * enum EventQuery::MatchType:
225+ * - Exact (0): The string must match exactly.
226+ * - Wildcard (1): The string may contain wildcards.
214227 *
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- * }
228- * }
228+ * Example usage:
229229 *
230+ * // Filter for events with sender exactly "CDPLoggerDemoApp.InvalidLicense":
231+ * { senderConditions: ["CDPLoggerDemoApp.InvalidLicense"] }
232+ *
233+ * // Filter for events where the "Text" data field equals "Invalid or missing feature license detected.":
234+ * { dataConditions: { "Text": "Invalid or missing feature license detected." } }
235+ *
236+ *
237+ * @param {Object } query - A simple plain object representing the EventQuery.
230238 * @returns {Promise<Array> } Resolves with an array of events (each event includes a 'codeDescription').
231239 */
232240 requestEvents ( query ) {
233241 this . _timeRequest ( ) ;
234242 const requestId = this . _getRequestId ( ) ;
243+ // Convert the simple query into a proper EventQuery message.
244+ const eventQuery = this . _buildEventQuery ( query ) ;
245+
246+
247+
235248 if ( ! this . isOpen ) {
236- this . queuedRequests [ requestId ] = { type : "events" , query : query } ;
249+ this . queuedRequests [ requestId ] = { type : "events" , query : eventQuery } ;
237250 } else {
238- this . _sendEventsRequest ( requestId , query ) ;
251+ this . _sendEventsRequest ( requestId , eventQuery ) ;
239252 }
240253 return new Promise ( ( resolve , reject ) => {
241254 this . storedPromises [ requestId ] = { resolve, reject } ;
242255 } ) ;
243256 }
244257
258+ // --- Internal methods ---
259+
245260 _sendEventsRequest ( requestId , query ) {
246261 const container = Container . create ( ) ;
247262 container . messageType = Container . Type . eEventsRequest ;
@@ -250,6 +265,74 @@ class Client {
250265 this . ws . send ( buffer ) ;
251266 }
252267
268+ /**
269+ * Helper method to build a proper EventQuery message from a simple plain object.
270+ *
271+ *
272+ *
273+ *
274+ * @param {Object } query - The simple plain object query.
275+ * @returns {DBMessaging.Protobuf.EventQuery } - The built EventQuery message.
276+ */
277+ _buildEventQuery ( query ) {
278+ const root = require ( './generated/containerPb.js' ) ;
279+ const { EventQuery } = root . DBMessaging . Protobuf ;
280+ const { MatchType } = EventQuery ;
281+
282+ // Create base query with primitive fields
283+ const baseQuery = {
284+ timeRangeBegin : query . timeRangeBegin || 0 ,
285+ timeRangeEnd : query . timeRangeEnd || Math . floor ( Date . now ( ) / 1000 ) ,
286+ codeMask : query . codeMask !== undefined ? query . codeMask : 0xFFFFFFFF ,
287+ limit : query . limit || 50 ,
288+ offset : query . offset || 0 ,
289+ flags : query . flags || 0
290+ } ;
291+
292+ // Build sender conditions if present
293+ if ( query . senders && query . senders . length > 0 ) {
294+ baseQuery . senderConditions = {
295+ conditions : query . senders . map ( sender => ( {
296+ value : sender ,
297+ type : MatchType . Exact
298+ } ) )
299+ } ;
300+ }
301+
302+ // Build data conditions if present
303+ if ( query . dataConditions ) {
304+ const dataConds = { } ;
305+ for ( const key in query . dataConditions ) {
306+ const val = query . dataConditions [ key ] ;
307+ const conditions = [ ] ;
308+
309+ if ( Array . isArray ( val ) ) {
310+ for ( const item of val ) {
311+ conditions . push ( {
312+ value : String ( item ) ,
313+ type : MatchType . Exact
314+ } ) ;
315+ }
316+ } else {
317+ conditions . push ( {
318+ value : String ( val ) ,
319+ type : MatchType . Exact
320+ } ) ;
321+ }
322+
323+ // Store without any table qualification
324+ dataConds [ key ] = { conditions } ;
325+ }
326+ baseQuery . dataConditions = dataConds ;
327+ }
328+
329+ return EventQuery . create ( baseQuery ) ;
330+ }
331+
332+
333+
334+
335+
253336 /**
254337 * Converts a numeric CDP event code into a descriptive string.
255338 * Multiple flags can be set simultaneously, so we combine them.
@@ -262,8 +345,8 @@ class Client {
262345 * 0x100 = SourceObjectUnavailable
263346 * 0x40000000 = NodeBoot
264347 *
265- * @param {number } code - The event code from an eEventsResponse
266- * @returns {string } - A human-readable combination of flags
348+ * @param {number } code - The event code from an eEventsResponse.
349+ * @returns {string } - A human-readable combination of flags.
267350 */
268351 getEventCodeDescription ( code ) {
269352 const flags = [ ] ;
@@ -396,13 +479,12 @@ class Client {
396479 }
397480
398481 case Container . Type . eEventsResponse : {
399- // Optionally enrich each event with a human-readable code description:
482+ // Enrich events with a human-readable code description.
400483 if ( data . eventsResponse . events && data . eventsResponse . events . length > 0 ) {
401484 data . eventsResponse . events . forEach ( evt => {
402485 evt . codeDescription = this . getEventCodeDescription ( evt . code ) ;
403486 } ) ;
404487 }
405-
406488 if ( this . storedPromises [ data . eventsResponse . requestId ] ) {
407489 const { resolve } = this . storedPromises [ data . eventsResponse . requestId ] ;
408490 delete this . storedPromises [ data . eventsResponse . requestId ] ;
@@ -524,9 +606,7 @@ class Client {
524606 }
525607 const requestId = reqId ;
526608 this . lastTimeRequest = Date . now ( ) / 1000 ;
527- // Always send the time request.
528609 this . _sendTimeRequest ( requestId ) ;
529- // Create the promise and store the callbacks.
530610 const promise = new Promise ( ( resolve , reject ) => {
531611 this . storedPromises [ requestId ] = { resolve, reject } ;
532612 } ) ;
0 commit comments