diodejs 0.2.2 → 0.4.0

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.
package/rpc.js CHANGED
@@ -1,7 +1,86 @@
1
1
  //rpc.js
2
- const { makeReadable, parseRequestId, parseResponseType, parseReason } = require('./utils');
2
+ const { makeReadable, parseRequestId, parseResponseType, parseReason, parseUInt, toBufferView } = require('./utils');
3
3
  const logger = require('./logger');
4
4
 
5
+ function decodeToken(value) {
6
+ if (typeof value === 'string') return value;
7
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
8
+ return toBufferView(value).toString('utf8');
9
+ }
10
+ return '';
11
+ }
12
+
13
+ function normalizeAddressParam(value) {
14
+ if (!value) return value;
15
+ if (Buffer.isBuffer(value)) return value;
16
+ if (value instanceof Uint8Array) return toBufferView(value);
17
+ if (typeof value === 'string') {
18
+ const hex = value.toLowerCase().startsWith('0x') ? value.slice(2) : value;
19
+ if (!hex) return Buffer.alloc(0);
20
+ return Buffer.from(hex, 'hex');
21
+ }
22
+ return value;
23
+ }
24
+
25
+ function parseDeviceTicketObject(obj) {
26
+ if (!Array.isArray(obj) || obj.length < 2) {
27
+ return null;
28
+ }
29
+ const objectType = decodeToken(obj[0]);
30
+ if (objectType !== 'ticket' && objectType !== 'ticketv2') {
31
+ return null;
32
+ }
33
+ const serverIdRaw = obj[1];
34
+ let serverId = null;
35
+ if (Buffer.isBuffer(serverIdRaw) || serverIdRaw instanceof Uint8Array) {
36
+ serverId = toBufferView(serverIdRaw);
37
+ } else if (typeof serverIdRaw === 'string') {
38
+ const hex = serverIdRaw.toLowerCase().startsWith('0x') ? serverIdRaw.slice(2) : serverIdRaw;
39
+ if (hex && /^[0-9a-f]+$/.test(hex)) {
40
+ serverId = Buffer.from(hex, 'hex');
41
+ }
42
+ }
43
+ const serverIdHex = serverId ? `0x${serverId.toString('hex')}` : '';
44
+
45
+ const ticket = {
46
+ objectType,
47
+ serverId,
48
+ serverIdHex,
49
+ };
50
+
51
+ if (objectType === 'ticketv2') {
52
+ ticket.chainId = parseUInt(obj[2]);
53
+ ticket.epoch = parseUInt(obj[3]);
54
+ } else {
55
+ ticket.blockNumber = parseUInt(obj[2]);
56
+ }
57
+
58
+ return ticket;
59
+ }
60
+
61
+ function parseServerObject(obj) {
62
+ if (!Array.isArray(obj) || obj.length < 4) {
63
+ return null;
64
+ }
65
+ const type = decodeToken(obj[0]);
66
+ if (type !== 'server') {
67
+ return null;
68
+ }
69
+
70
+ const hostRaw = obj[1];
71
+ const host = (Buffer.isBuffer(hostRaw) || hostRaw instanceof Uint8Array)
72
+ ? toBufferView(hostRaw).toString('utf8')
73
+ : (typeof hostRaw === 'string' ? hostRaw : '');
74
+ const edgePort = parseUInt(obj[2]);
75
+ const serverPort = parseUInt(obj[3]);
76
+
77
+ return {
78
+ host,
79
+ edgePort,
80
+ serverPort,
81
+ };
82
+ }
83
+
5
84
  class DiodeRPC {
6
85
  constructor(connection) {
7
86
  this.connection = connection;
@@ -17,7 +96,8 @@ class DiodeRPC {
17
96
  const blockNumberRaw = responseData[0];
18
97
  let blockNumber;
19
98
  if (blockNumberRaw instanceof Uint8Array) {
20
- blockNumber = Buffer.from(blockNumberRaw).readUIntBE(0, blockNumberRaw.length);
99
+ const buf = toBufferView(blockNumberRaw);
100
+ blockNumber = buf.readUIntBE(0, buf.length);
21
101
  } else if (Buffer.isBuffer(blockNumberRaw)) {
22
102
  blockNumber = blockNumberRaw.readUIntBE(0, blockNumberRaw.length);
23
103
  } else if (typeof blockNumberRaw === 'number') {
@@ -25,10 +105,10 @@ class DiodeRPC {
25
105
  } else {
26
106
  throw new Error('Invalid block number format. response:', makeReadable(responseData));
27
107
  }
28
- logger.debug(`Block number is: ${blockNumber}`);
108
+ logger.debug(() => `Block number is: ${blockNumber}`);
29
109
  return blockNumber;
30
110
  }).catch((error) => {
31
- logger.error(`Error during get block peak: ${error}`);
111
+ logger.error(() => `Error during get block peak: ${error}`);
32
112
  return;
33
113
  });
34
114
  }
@@ -36,7 +116,7 @@ class DiodeRPC {
36
116
  return this.connection.sendCommand(['getblockheader', index]).then((responseData) => {
37
117
  return responseData[0]; // block_header
38
118
  }).catch((error) => {
39
- logger.error(`Error during get block header: ${error}`);
119
+ logger.error(() => `Error during get block header: ${error}`);
40
120
  return;
41
121
  });
42
122
  }
@@ -45,7 +125,31 @@ class DiodeRPC {
45
125
  return this.connection.sendCommand(['getblock', index]).then((responseData) => {
46
126
  return responseData[0]; // block
47
127
  }).catch((error) => {
48
- logger.error(`Error during get block: ${error}`);
128
+ logger.error(() => `Error during get block: ${error}`);
129
+ return;
130
+ });
131
+ }
132
+
133
+ getObject(deviceId) {
134
+ const normalized = normalizeAddressParam(deviceId);
135
+ return this.connection.sendCommand(['getobject', normalized]).then((responseData) => {
136
+ const obj = responseData[0];
137
+ const parsed = parseDeviceTicketObject(obj);
138
+ return parsed || obj;
139
+ }).catch((error) => {
140
+ logger.error(() => `Error during get object: ${error}`);
141
+ return;
142
+ });
143
+ }
144
+
145
+ getNode(nodeId) {
146
+ const normalized = normalizeAddressParam(nodeId);
147
+ return this.connection.sendCommand(['getnode', normalized]).then((responseData) => {
148
+ const obj = responseData[0];
149
+ const parsed = parseServerObject(obj);
150
+ return parsed || obj;
151
+ }).catch((error) => {
152
+ logger.error(() => `Error during get node: ${error}`);
49
153
  return;
50
154
  });
51
155
  }
@@ -64,7 +168,7 @@ class DiodeRPC {
64
168
  throw new Error(`Unknown status in response: '${status}'`);
65
169
  }
66
170
  }).catch((error) => {
67
- logger.error(`Error during ping: ${error}`);
171
+ logger.error(() => `Error during ping: ${error}`);
68
172
  return false;
69
173
  })
70
174
  }
@@ -82,7 +186,7 @@ class DiodeRPC {
82
186
  if (status === 'ok') {
83
187
  let ref = refOrReasonRaw;
84
188
  if (Buffer.isBuffer(ref) || ref instanceof Uint8Array) {
85
- ref = Buffer.from(ref);
189
+ ref = toBufferView(ref);
86
190
  }
87
191
  return ref;
88
192
  } else if (status === 'error') {
@@ -92,7 +196,28 @@ class DiodeRPC {
92
196
  throw new Error(`Unknown status in response: '${status}'`);
93
197
  }
94
198
  }).catch((error) => {
95
- logger.error(`Error during port open: ${error}`);
199
+ logger.error(() => `Error during port open: ${error}`);
200
+ return;
201
+ });
202
+ }
203
+
204
+ portOpen2(deviceId, port, flags = 'rw') {
205
+ return this.connection.sendCommand(['portopen2', deviceId, port, flags]).then((responseData) => {
206
+ // responseData is [status, physicalPortOrReason]
207
+ const [statusRaw, portOrReasonRaw] = responseData;
208
+ const status = parseResponseType(statusRaw);
209
+
210
+ if (status === 'ok') {
211
+ const physicalPort = parseUInt(portOrReasonRaw);
212
+ return physicalPort !== null ? physicalPort : portOrReasonRaw;
213
+ } else if (status === 'error') {
214
+ const reason = parseReason(portOrReasonRaw);
215
+ throw new Error(reason);
216
+ } else {
217
+ throw new Error(`Unknown status in response: '${status}'`);
218
+ }
219
+ }).catch((error) => {
220
+ logger.error(() => `Error during port open2: ${error}`);
96
221
  return;
97
222
  });
98
223
  }
@@ -108,7 +233,7 @@ class DiodeRPC {
108
233
  try {
109
234
  // If data is too large, split it into chunks
110
235
  if (data.length > MAX_CHUNK_SIZE) {
111
- logger.debug(`Chunking large data of ${data.length} bytes into pieces of max ${MAX_CHUNK_SIZE} bytes`);
236
+ logger.debug(() => `Chunking large data of ${data.length} bytes into pieces of max ${MAX_CHUNK_SIZE} bytes`);
112
237
  let offset = 0;
113
238
 
114
239
  while (offset < data.length) {
@@ -144,7 +269,7 @@ class DiodeRPC {
144
269
  });
145
270
  }
146
271
  } catch (error) {
147
- logger.error(`Error during port send: ${error}`);
272
+ logger.error(() => `Error during port send: ${error}`);
148
273
  throw error; // Rethrow to allow proper error handling upstream
149
274
  }
150
275
  }
@@ -165,21 +290,21 @@ class DiodeRPC {
165
290
  throw new Error(`Unknown status in response: '${status}'`);
166
291
  }
167
292
  }).catch((error) => {
168
- logger.error(`Error during port close: ${error}`);
293
+ logger.error(() => `Error during port close: ${error}`);
169
294
  return;
170
295
  });
171
296
  }
172
297
 
173
298
  sendError(sessionId, ref, error) {
174
299
  return this.connection.sendCommandWithSessionId(['response', ref, 'error', error], sessionId).catch((error) => {
175
- logger.error(`Error during send error: ${error}`);
300
+ logger.error(() => `Error during send error: ${error}`);
176
301
  return;
177
302
  });
178
303
  }
179
304
 
180
305
  sendResponse(sessionId, ref, response) {
181
306
  return this.connection.sendCommandWithSessionId(['response', ref, response], sessionId).catch((error) => {
182
- logger.error(`Error during send response: ${error}`);
307
+ logger.error(() => `Error during send response: ${error}`);
183
308
  return;
184
309
  });
185
310
  }
@@ -187,10 +312,10 @@ class DiodeRPC {
187
312
  async getEpoch() {
188
313
  const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
189
314
  if (this.epochCache.expiry && this.epochCache.expiry > currentTime) {
190
- logger.debug(`Using cached epoch: ${this.epochCache.epoch}`);
315
+ logger.debug(() => `Using cached epoch: ${this.epochCache.epoch}`);
191
316
  return this.epochCache.epoch;
192
317
  }
193
- logger.debug(`Fetching new epoch. Expiry: ${this.epochCache.expiry}, Current time: ${currentTime}`);
318
+ logger.debug(() => `Fetching new epoch. Expiry: ${this.epochCache.expiry}, Current time: ${currentTime}`);
194
319
  const blockPeak = await this.getBlockPeak();
195
320
  const blockHeader = await this.getBlockHeader(blockPeak);
196
321
 
@@ -209,39 +334,34 @@ class DiodeRPC {
209
334
  return epoch;
210
335
  }
211
336
 
212
- parseTimestamp(blockHeader) {
213
- // Search for the timestamp field by name
337
+ parseTimestamp(blockHeader) {
338
+ // Search for the timestamp field by name (robust to Buffer/Uint8Array)
214
339
  if (Array.isArray(blockHeader)) {
215
340
  for (const field of blockHeader) {
216
- if (Array.isArray(field) && field.length >= 2 && field[0] === 'timestamp') {
217
- const timestampValue = field[1];
218
-
219
- // Handle different timestamp value types
220
- if (typeof timestampValue === 'number') {
221
- return timestampValue;
222
- } else if (typeof timestampValue === 'string' && timestampValue.startsWith('0x')) {
223
- // Handle hex string
224
- return parseInt(timestampValue.slice(2), 16);
225
- } else if (typeof timestampValue === 'string') {
226
- // Handle decimal string
227
- return parseInt(timestampValue, 10);
228
- } else if (timestampValue instanceof Uint8Array || Buffer.isBuffer(timestampValue)) {
229
- // Handle buffer - carefully determine the byte length
230
- const buf = Buffer.from(timestampValue);
231
- // Use a safe approach to read the value based on buffer length
232
- if (buf.length <= 6) {
233
- return buf.readUIntBE(0, buf.length);
234
- } else {
235
- // For larger buffers, convert to hex string first
341
+ if (Array.isArray(field) && field.length >= 2) {
342
+ const key = typeof field[0] === 'string' ? field[0] : toBufferView(field[0]).toString('utf8');
343
+ if (key === 'timestamp') {
344
+ const timestampValue = field[1];
345
+ // Handle different timestamp value types
346
+ if (typeof timestampValue === 'number') {
347
+ return timestampValue;
348
+ } else if (typeof timestampValue === 'string' && timestampValue.startsWith('0x')) {
349
+ return parseInt(timestampValue.slice(2), 16);
350
+ } else if (typeof timestampValue === 'string') {
351
+ return parseInt(timestampValue, 10);
352
+ } else if (timestampValue instanceof Uint8Array || Buffer.isBuffer(timestampValue)) {
353
+ const buf = toBufferView(timestampValue);
354
+ if (buf.length <= 6) {
355
+ return buf.readUIntBE(0, buf.length);
356
+ }
236
357
  return parseInt(buf.toString('hex'), 16);
237
358
  }
238
359
  }
239
360
  }
240
361
  }
241
362
  }
242
-
243
- // Fallback: if we couldn't find the timestamp or parse it correctly
244
- logger.warn('Could not find or parse timestamp in block header, using current time');
363
+ // Fallback
364
+ logger.warn(() => 'Could not find or parse timestamp in block header, using current time');
245
365
  return Math.floor(Date.now() / 1000);
246
366
  }
247
367
  }
@@ -15,11 +15,10 @@ server.on('message',function(msg,info){
15
15
  //sending msg
16
16
  server.send(msg,info.port,'localhost',function(error){
17
17
  if(error){
18
- client.close();
18
+ server.close(); // was client.close();
19
19
  }else{
20
20
  console.log('Data sent !!!');
21
21
  }
22
-
23
22
  });
24
23
 
25
24
  });
package/utils.js CHANGED
@@ -6,11 +6,20 @@ const { KEYUTIL } = require("jsrsasign");
6
6
  const fs = require('fs');
7
7
  var path = require('path');
8
8
 
9
+ // Zero-copy view for Uint8Array -> Buffer where possible
10
+ function toBufferView(u8) {
11
+ if (Buffer.isBuffer(u8)) return u8;
12
+ if (u8 && u8.buffer && typeof u8.byteOffset === 'number') {
13
+ return Buffer.from(u8.buffer, u8.byteOffset, u8.byteLength);
14
+ }
15
+ return Buffer.from(u8);
16
+ }
17
+
9
18
  function makeReadable(decodedMessage) {
10
19
  if (Array.isArray(decodedMessage)) {
11
20
  return decodedMessage.map((item) => makeReadable(item));
12
21
  } else if (decodedMessage instanceof Uint8Array) {
13
- const buffer = Buffer.from(decodedMessage);
22
+ const buffer = toBufferView(decodedMessage);
14
23
  // Try to interpret the Buffer as a UTF-8 string
15
24
  const str = buffer.toString('utf8');
16
25
  if (/^[\x20-\x7E]+$/.test(str)) {
@@ -42,7 +51,7 @@ function makeReadable(decodedMessage) {
42
51
  // Helper functions
43
52
  function parseRequestId(requestIdRaw) {
44
53
  if (requestIdRaw instanceof Uint8Array || Buffer.isBuffer(requestIdRaw)) {
45
- const buffer = Buffer.from(requestIdRaw);
54
+ const buffer = toBufferView(requestIdRaw);
46
55
  return buffer.readUIntBE(0, buffer.length);
47
56
  } else if (typeof requestIdRaw === 'number') {
48
57
  return requestIdRaw;
@@ -53,10 +62,10 @@ function parseRequestId(requestIdRaw) {
53
62
 
54
63
  function parseResponseType(responseTypeRaw) {
55
64
  if (responseTypeRaw instanceof Uint8Array || Buffer.isBuffer(responseTypeRaw)) {
56
- return Buffer.from(responseTypeRaw).toString('utf8');
65
+ return toBufferView(responseTypeRaw).toString('utf8');
57
66
  } else if (Array.isArray(responseTypeRaw)) {
58
67
  // Convert each element to Buffer and concatenate
59
- const buffers = responseTypeRaw.map((item) => Buffer.from(item));
68
+ const buffers = responseTypeRaw.map((item) => toBufferView(item));
60
69
  const concatenated = Buffer.concat(buffers);
61
70
  return concatenated.toString('utf8');
62
71
  } else if (typeof responseTypeRaw === 'string') {
@@ -68,7 +77,7 @@ function parseResponseType(responseTypeRaw) {
68
77
 
69
78
  function parseReason(reasonRaw) {
70
79
  if (Buffer.isBuffer(reasonRaw) || reasonRaw instanceof Uint8Array) {
71
- return Buffer.from(reasonRaw).toString('utf8');
80
+ return toBufferView(reasonRaw).toString('utf8');
72
81
  } else if (typeof reasonRaw === 'string') {
73
82
  return reasonRaw;
74
83
  } else {
@@ -76,6 +85,28 @@ function parseReason(reasonRaw) {
76
85
  }
77
86
  }
78
87
 
88
+ function parseUInt(valueRaw) {
89
+ if (valueRaw === null || valueRaw === undefined) {
90
+ return null;
91
+ }
92
+ if (typeof valueRaw === 'number') {
93
+ return valueRaw;
94
+ }
95
+ if (typeof valueRaw === 'string') {
96
+ if (valueRaw.startsWith('0x')) {
97
+ return parseInt(valueRaw.slice(2), 16);
98
+ }
99
+ const parsed = Number(valueRaw);
100
+ return Number.isFinite(parsed) ? parsed : null;
101
+ }
102
+ if (Buffer.isBuffer(valueRaw) || valueRaw instanceof Uint8Array) {
103
+ const buffer = toBufferView(valueRaw);
104
+ if (buffer.length === 0) return 0;
105
+ return buffer.readUIntBE(0, buffer.length);
106
+ }
107
+ return null;
108
+ }
109
+
79
110
  function generateCert(privateKeyObj, publicKeyObj) {
80
111
  // Generate a certificate valid for 1 month
81
112
  function formatDate(date) {
@@ -128,7 +159,7 @@ function loadOrGenerateKeyPair(keyLocation) {
128
159
 
129
160
  // Try to load existing keys
130
161
  if (fs.existsSync(keyLocation)) {
131
- logger.info(`Loading keys from ${keyLocation}`);
162
+ logger.info(() => `Loading keys from ${keyLocation}`);
132
163
  const keyData = JSON.parse(fs.readFileSync(keyLocation, 'utf8'));
133
164
 
134
165
  // Convert the stored JSON back to keypair objects
@@ -138,7 +169,7 @@ function loadOrGenerateKeyPair(keyLocation) {
138
169
  return { prvKeyObj, pubKeyObj };
139
170
  } else {
140
171
  // Generate new keypair
141
- logger.info(`Generating new key pair at ${keyLocation}`);
172
+ logger.info(() => `Generating new key pair at ${keyLocation}`);
142
173
  const kp = KEYUTIL.generateKeypair("EC", "secp256k1");
143
174
 
144
175
  // Store the keys in a serializable format
@@ -154,7 +185,7 @@ function loadOrGenerateKeyPair(keyLocation) {
154
185
  return kp;
155
186
  }
156
187
  } catch (error) {
157
- logger.error(`Error loading or generating key pair: ${error}`);
188
+ logger.error(() => `Error loading or generating key pair: ${error}`);
158
189
  throw error;
159
190
  }
160
191
  }
@@ -173,7 +204,9 @@ module.exports = {
173
204
  parseRequestId,
174
205
  parseResponseType,
175
206
  parseReason,
207
+ parseUInt,
176
208
  generateCert,
177
209
  loadOrGenerateKeyPair,
178
- ensureDirectoryExistence
210
+ ensureDirectoryExistence,
211
+ toBufferView,
179
212
  };