@@ -5,7 +5,7 @@ const Client = require('./client');
55
66/**
77 * Recursively normalizes an object/value.
8- * If the value is a string, it trims whitespace.
8+ * If the value is a string, it trims whitespace and compresses internal whitespace .
99 * If it's an object (or array), it normalizes each property.
1010 * This helps ensure that logically identical values produce the same string.
1111 *
@@ -14,7 +14,7 @@ const Client = require('./client');
1414 */
1515function normalizeValue ( val ) {
1616 if ( typeof val === 'string' ) {
17- return val . trim ( ) ;
17+ return val . trim ( ) . replace ( / \s + / g , ' ' ) ;
1818 } else if ( typeof val === 'object' && val !== null ) {
1919 if ( Array . isArray ( val ) ) {
2020 return val . map ( normalizeValue ) ;
@@ -51,61 +51,98 @@ function canonicalize(obj) {
5151 return '{' + result + '}' ;
5252}
5353
54+ /**
55+ * Orders the keys of an object based on a desired order.
56+ * Keys in the desiredOrder array appear first (in that order) and any remaining keys
57+ * are appended in alphabetical order.
58+ *
59+ * @param {Object } obj - The object whose keys are to be ordered.
60+ * @returns {Object } - A new object with keys in the desired order.
61+ */
62+ function orderObjectKeys ( obj ) {
63+ if ( typeof obj !== 'object' || obj === null || Array . isArray ( obj ) ) {
64+ return obj ;
65+ }
66+ // Define your desired key order
67+ const desiredOrder = [ "Level" , "Group" , "Description" , "Text" ] ;
68+ const ordered = { } ;
69+
70+ // Add keys in the desired order if they exist in the object
71+ for ( const key of desiredOrder ) {
72+ if ( key in obj ) {
73+ ordered [ key ] = obj [ key ] ;
74+ }
75+ }
76+
77+ // Get any keys not in the desired order and sort them alphabetically
78+ const remainingKeys = Object . keys ( obj )
79+ . filter ( key => ! desiredOrder . includes ( key ) )
80+ . sort ( ) ;
81+
82+ for ( const key of remainingKeys ) {
83+ ordered [ key ] = obj [ key ] ;
84+ }
85+ return ordered ;
86+ }
87+
5488( async function main ( ) {
5589 const client = new Client ( 'ws://127.0.0.1:17000' , false ) ;
5690 try {
57- // Example query: adjust the time range, etc., as needed:
91+ // Wide time range and large limit
5892 const query = {
59- timeRangeBegin : 1742540000 ,
60- timeRangeEnd : 1742550000 ,
61- codeMask : 0xFFFFFFFF ,
62- limit : 100 ,
93+ timeRangeBegin : 0 , // start from the epoch
94+ timeRangeEnd : 2147483647 , // far in the future
95+ codeMask : 0xFFFFFFFF , // all codes
96+ limit : 1000 , // max number of events to retrieve
6397 offset : 0 ,
64- flags : 1 // 'NewestFirst' from your enum
98+ flags : 1 // e.g. 'NewestFirst'
6599 } ;
66100
67101 const events = await client . requestEvents ( query ) ;
68102
69- // De-duplicate events using a composite key built from normalized fields.
70- // We'll canonicalize e.data to handle reordered JSON keys.
103+ // -----------------------------------------------------------------------
104+ // Deduplicate events:
105+ // Use only the sender and the event's data (after normalizing and ordering)
106+ // to build a composite key. This ignores differences in timestamp, code,
107+ // or JSON key order.
108+ // -----------------------------------------------------------------------
71109 const seen = new Set ( ) ;
72110 const uniqueEvents = [ ] ;
73111
74112 for ( const e of events ) {
75- const tsPart = ( typeof e . timestampSec !== 'undefined' && e . timestampSec !== null )
76- ? String ( e . timestampSec )
77- : '' ;
113+ const senderPart = ( typeof e . sender === 'string' ) ? e . sender : '' ;
78114
79- const codePart = ( typeof e . code !== 'undefined' && e . code !== null )
80- ? String ( e . code )
81- : '' ;
82-
83- const senderPart = ( typeof e . sender !== 'undefined' && e . sender !== null )
84- ? String ( e . sender )
85- : '' ;
86-
87- // Canonicalize the data so that JSON field order does not matter
88- const dataPart = e . data
89- ? canonicalize ( normalizeValue ( e . data ) )
90- : '' ;
115+ // Process the data: normalize, then order the keys
116+ let dataPart = '' ;
117+ if ( e . data ) {
118+ const normalizedData = normalizeValue ( e . data ) ;
119+ const orderedData = orderObjectKeys ( normalizedData ) ;
120+ dataPart = canonicalize ( orderedData ) ;
121+ }
91122
92- const compositeKey = `${ tsPart } -${ codePart } -${ senderPart } -${ dataPart } ` ;
123+ // Build composite key from sender and data only
124+ const compositeKey = `${ senderPart } -${ dataPart } ` ;
93125
94126 if ( ! seen . has ( compositeKey ) ) {
95127 seen . add ( compositeKey ) ;
96128 uniqueEvents . push ( e ) ;
97129 }
98130 }
99131
100- // Print the unique events
132+ // Print the final unique events, with data keys ordered for display
101133 if ( uniqueEvents . length === 0 ) {
102- console . log ( "No events found." ) ;
134+ console . log ( "No events found (after dedup) ." ) ;
103135 } else {
136+ console . log ( `Showing ${ uniqueEvents . length } unique events:\n` ) ;
104137 for ( const evt of uniqueEvents ) {
105138 console . log ( `Timestamp: ${ evt . timestampSec } ` ) ;
106139 console . log ( `Code: ${ evt . code } ` ) ;
107140 console . log ( `Sender: ${ evt . sender } ` ) ;
108- console . log ( `Data: ${ JSON . stringify ( evt . data ) } ` ) ;
141+ let orderedData = evt . data ;
142+ if ( typeof evt . data === 'object' && evt . data !== null && ! Array . isArray ( evt . data ) ) {
143+ orderedData = orderObjectKeys ( evt . data ) ;
144+ }
145+ console . log ( `Data: ${ JSON . stringify ( orderedData ) } ` ) ;
109146 console . log ( '--------------------' ) ;
110147 }
111148 }
0 commit comments