socket-function 0.10.8 → 0.11.1

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/CallFactory.ts +141 -133
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "0.10.8",
3
+ "version": "0.11.1",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -28,6 +28,6 @@
28
28
  "@types/node-forge": "^1.3.1",
29
29
  "debugbreak": "^0.6.5",
30
30
  "pegjs": "^0.10.0",
31
- "typedev": "^0.1.1"
31
+ "typedev": "^0.1.3"
32
32
  }
33
33
  }
@@ -296,7 +296,7 @@ export async function createCallFactory(
296
296
  }
297
297
  }
298
298
  async function send(data: Buffer[]) {
299
- sendRaw([
299
+ await sendRaw([
300
300
  (data.length + BASE_LENGTH_OFFSET).toString(),
301
301
  ...data,
302
302
  ]);
@@ -324,7 +324,7 @@ export async function createCallFactory(
324
324
  }
325
325
  // if (totalResultSize > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
326
326
  // Split up Buffer[] if they are too large
327
- sendRaw([
327
+ await sendRaw([
328
328
  JSON.stringify(header),
329
329
  ...data,
330
330
  ]);
@@ -346,6 +346,141 @@ export async function createCallFactory(
346
346
  let pendingCall: MessageHeader & {
347
347
  buffers: Buffer[];
348
348
  } | undefined;
349
+
350
+ async function processPendingCall() {
351
+ if (!pendingCall) throw new Error(`No pending call`);
352
+ let currentCall = pendingCall;
353
+ pendingCall = undefined;
354
+ let currentBuffers = currentCall.buffers;
355
+ let call: InternalCallType | InternalReturnType;
356
+ let resultSize: number;
357
+ let time = Date.now();
358
+ if (currentCall.type === "Buffer" || currentCall.type === "Buffer[]") {
359
+ let result: Buffer | Buffer[] = currentBuffers;
360
+ if (currentCall.bufferLengths) {
361
+ let pendingBuffers = currentBuffers;
362
+ function takeBuffer(len: number) {
363
+ let lenLeft = len;
364
+ let buffers: Buffer[] = [];
365
+ while (lenLeft > 0) {
366
+ let buf = currentBuffers.pop();
367
+ if (!buf) {
368
+ throw new Error(`Not enough buffers received.`);
369
+ }
370
+ if (buf.length > lenLeft) {
371
+ buffers.push(buf.slice(0, lenLeft));
372
+ currentBuffers.unshift(buf.slice(lenLeft));
373
+ break;
374
+ } else {
375
+ buffers.push(buf);
376
+ lenLeft -= buf.length;
377
+ }
378
+ }
379
+ if (buffers.length === 1) {
380
+ return buffers[0];
381
+ }
382
+ return Buffer.concat(buffers);
383
+ }
384
+ result = currentCall.bufferLengths.map(takeBuffer);
385
+ if (pendingBuffers.length > 0) {
386
+ throw new Error(`Received too many buffers.`);
387
+ }
388
+ }
389
+ resultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
390
+ if (currentCall.type === "Buffer") {
391
+ if (result.length === 1) {
392
+ result = result[0];
393
+ } else {
394
+ result = Buffer.concat(result);
395
+ }
396
+ }
397
+ call = {
398
+ ...currentCall.metadata,
399
+ result,
400
+ };
401
+ } else {
402
+ resultSize = currentBuffers.map(x => x.length).reduce((a, b) => a + b, 0);
403
+ call = await SocketFunction.WIRE_SERIALIZER.deserialize(currentBuffers) as InternalCallType | InternalReturnType;
404
+ }
405
+ time = Date.now() - time;
406
+ for (let callback of SocketFunction.trackMessageSizes.download) {
407
+ callback(resultSize);
408
+ }
409
+
410
+ if (call.isReturn) {
411
+ let callbackObj = pendingCalls.get(call.seqNum);
412
+ if (time > SocketFunction.WIRE_WARN_TIME) {
413
+ console.log(red(`Slow parse, took ${time}ms to parse ${resultSize} bytes, for receieving result of call to ${callbackObj?.call.classGuid}.${callbackObj?.call.functionName}`));
414
+ }
415
+ if (!callbackObj) {
416
+ console.log(`Got return for unknown call ${call.seqNum} (created at time ${new Date(call.seqNum)})`);
417
+ return;
418
+ }
419
+ if (SocketFunction.logMessages) {
420
+ let call = callbackObj.call;
421
+ console.log(`SIZE\t${(formatNumberSuffixed(resultSize) + "B").padEnd(4, " ")}\t${call.classGuid}.${call.functionName} at ${Date.now()}`);
422
+ }
423
+ if (call.isResultCompressed) {
424
+ call.result = await decompressObj(call.result as Buffer);
425
+ call.isResultCompressed = false;
426
+ }
427
+ callbackObj.callback(call);
428
+ } else {
429
+ if (call.isArgsCompressed) {
430
+ call.args = await decompressObj(call.args as any as Buffer) as any;
431
+ call.isArgsCompressed = false;
432
+ }
433
+ if (SocketFunction.logMessages) {
434
+ console.log(`SIZE\t${(formatNumberSuffixed(resultSize) + "B").padEnd(4, " ")}\t${call.classGuid}.${call.functionName} at ${Date.now()}`);
435
+ }
436
+ if (time > SocketFunction.WIRE_WARN_TIME) {
437
+ console.log(red(`Slow parse, took ${time}ms to parse ${resultSize} bytes, for call to ${call.classGuid}.${call.functionName}`));
438
+ }
439
+
440
+ let response: InternalReturnType;
441
+ try {
442
+ let result = await performLocalCall({ call, caller: callerContext });
443
+ response = {
444
+ isReturn: true,
445
+ result,
446
+ seqNum: call.seqNum,
447
+ };
448
+ if (shouldCompressCall(call)) {
449
+ response.result = await compressObj(response.result) as any;
450
+ response.isResultCompressed = true;
451
+ }
452
+ } catch (e: any) {
453
+ response = {
454
+ isReturn: true,
455
+ result: undefined,
456
+ seqNum: call.seqNum,
457
+ error: e.stack,
458
+ };
459
+ }
460
+
461
+ if (response.result instanceof Buffer) {
462
+ let { result, ...remaining } = response;
463
+ await sendWithHeader([result], { type: "Buffer", bufferCount: 1, metadata: remaining });
464
+ } else if (Array.isArray(response.result) && response.result.every(x => x instanceof Buffer)) {
465
+ let { result, ...remaining } = response;
466
+ await sendWithHeader(result, { type: "Buffer[]", bufferCount: result.length, metadata: remaining });
467
+ } else {
468
+ let result: Buffer[] = await SocketFunction.WIRE_SERIALIZER.serialize(response);
469
+ let totalResultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
470
+ if (totalResultSize > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
471
+ response = {
472
+ isReturn: true,
473
+ result: undefined,
474
+ seqNum: call.seqNum,
475
+ error: new Error(`Response too large to send (${call.classGuid}.${call.functionName}, size: ${formatNumber(totalResultSize)} > ${formatNumber(SocketFunction.MAX_MESSAGE_SIZE)}). If you need to handle very large static data use some external service, such as Backblaze B2 or AWS S3. Or consider fragmenting data at an application level, because sending large data will cause large lag spikes for other clients using this server. Or, if absolutely required, set SocketFunction.MAX_MESSAGE_SIZE to a higher value.`).stack,
476
+ };
477
+ result = await SocketFunction.WIRE_SERIALIZER.serialize(response);
478
+ }
479
+ await send(result);
480
+ }
481
+ }
482
+ }
483
+
349
484
  let clientsideSerial = runInSerial(async <T>(val: Promise<T>) => val);
350
485
  async function onMessage(message: ws.RawData | ws.MessageEvent | string) {
351
486
  try {
@@ -386,6 +521,9 @@ export async function createCallFactory(
386
521
  type: "serialized",
387
522
  };
388
523
  }
524
+ if (pendingCall?.bufferCount === 0) {
525
+ await processPendingCall();
526
+ }
389
527
  return;
390
528
  }
391
529
  if (message instanceof Buffer) {
@@ -393,141 +531,11 @@ export async function createCallFactory(
393
531
  throw new Error(`Received data without size`);
394
532
  }
395
533
  pendingCall.buffers.push(message);
396
- let currentBuffers: Buffer[];
397
534
  if (pendingCall.buffers.length !== pendingCall.bufferCount) {
398
535
  return;
399
536
  }
400
537
 
401
- let currentCall = pendingCall;
402
- pendingCall = undefined;
403
- currentBuffers = currentCall.buffers;
404
- let call: InternalCallType | InternalReturnType;
405
- let resultSize: number;
406
- let time = Date.now();
407
- if (currentCall.type === "Buffer" || currentCall.type === "Buffer[]") {
408
- let result: Buffer | Buffer[] = currentBuffers;
409
- if (currentCall.bufferLengths) {
410
- let pendingBuffers = currentBuffers;
411
- function takeBuffer(len: number) {
412
- let lenLeft = len;
413
- let buffers: Buffer[] = [];
414
- while (lenLeft > 0) {
415
- let buf = currentBuffers.pop();
416
- if (!buf) {
417
- throw new Error(`Not enough buffers received.`);
418
- }
419
- if (buf.length > lenLeft) {
420
- buffers.push(buf.slice(0, lenLeft));
421
- currentBuffers.unshift(buf.slice(lenLeft));
422
- break;
423
- } else {
424
- buffers.push(buf);
425
- lenLeft -= buf.length;
426
- }
427
- }
428
- if (buffers.length === 1) {
429
- return buffers[0];
430
- }
431
- return Buffer.concat(buffers);
432
- }
433
- result = currentCall.bufferLengths.map(takeBuffer);
434
- if (pendingBuffers.length > 0) {
435
- throw new Error(`Received too many buffers.`);
436
- }
437
- }
438
- resultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
439
- if (currentCall.type === "Buffer") {
440
- if (result.length === 1) {
441
- result = result[0];
442
- } else {
443
- result = Buffer.concat(result);
444
- }
445
- }
446
- call = {
447
- ...currentCall.metadata,
448
- result,
449
- };
450
- } else {
451
- resultSize = currentBuffers.map(x => x.length).reduce((a, b) => a + b, 0);
452
- call = await SocketFunction.WIRE_SERIALIZER.deserialize(currentBuffers) as InternalCallType | InternalReturnType;
453
- }
454
- time = Date.now() - time;
455
- for (let callback of SocketFunction.trackMessageSizes.download) {
456
- callback(resultSize);
457
- }
458
-
459
- if (call.isReturn) {
460
- let callbackObj = pendingCalls.get(call.seqNum);
461
- if (time > SocketFunction.WIRE_WARN_TIME) {
462
- console.log(red(`Slow parse, took ${time}ms to parse ${resultSize} bytes, for receieving result of call to ${callbackObj?.call.classGuid}.${callbackObj?.call.functionName}`));
463
- }
464
- if (!callbackObj) {
465
- console.log(`Got return for unknown call ${call.seqNum} (created at time ${new Date(call.seqNum)})`);
466
- return;
467
- }
468
- if (SocketFunction.logMessages) {
469
- let call = callbackObj.call;
470
- console.log(`SIZE\t${(formatNumberSuffixed(resultSize) + "B").padEnd(4, " ")}\t${call.classGuid}.${call.functionName} at ${Date.now()}`);
471
- }
472
- if (call.isResultCompressed) {
473
- call.result = await decompressObj(call.result as Buffer);
474
- call.isResultCompressed = false;
475
- }
476
- callbackObj.callback(call);
477
- } else {
478
- if (call.isArgsCompressed) {
479
- call.args = await decompressObj(call.args as any as Buffer) as any;
480
- call.isArgsCompressed = false;
481
- }
482
- if (SocketFunction.logMessages) {
483
- console.log(`SIZE\t${(formatNumberSuffixed(resultSize) + "B").padEnd(4, " ")}\t${call.classGuid}.${call.functionName} at ${Date.now()}`);
484
- }
485
- if (time > SocketFunction.WIRE_WARN_TIME) {
486
- console.log(red(`Slow parse, took ${time}ms to parse ${resultSize} bytes, for call to ${call.classGuid}.${call.functionName}`));
487
- }
488
-
489
- let response: InternalReturnType;
490
- try {
491
- let result = await performLocalCall({ call, caller: callerContext });
492
- response = {
493
- isReturn: true,
494
- result,
495
- seqNum: call.seqNum,
496
- };
497
- if (shouldCompressCall(call)) {
498
- response.result = await compressObj(response.result) as any;
499
- response.isResultCompressed = true;
500
- }
501
- } catch (e: any) {
502
- response = {
503
- isReturn: true,
504
- result: undefined,
505
- seqNum: call.seqNum,
506
- error: e.stack,
507
- };
508
- }
509
-
510
- if (response.result instanceof Buffer) {
511
- let { result, ...remaining } = response;
512
- await sendWithHeader([result], { type: "Buffer", bufferCount: 1, metadata: remaining });
513
- } else if (Array.isArray(response.result) && response.result.every(x => x instanceof Buffer)) {
514
- let { result, ...remaining } = response;
515
- await sendWithHeader(result, { type: "Buffer[]", bufferCount: result.length, metadata: remaining });
516
- } else {
517
- let result: Buffer[] = await SocketFunction.WIRE_SERIALIZER.serialize(response);
518
- let totalResultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
519
- if (totalResultSize > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
520
- response = {
521
- isReturn: true,
522
- result: undefined,
523
- seqNum: call.seqNum,
524
- error: new Error(`Response too large to send (${call.classGuid}.${call.functionName}, size: ${formatNumber(totalResultSize)} > ${formatNumber(SocketFunction.MAX_MESSAGE_SIZE)}). If you need to handle very large static data use some external service, such as Backblaze B2 or AWS S3. Or consider fragmenting data at an application level, because sending large data will cause large lag spikes for other clients using this server. Or, if absolutely required, set SocketFunction.MAX_MESSAGE_SIZE to a higher value.`).stack,
525
- };
526
- result = await SocketFunction.WIRE_SERIALIZER.serialize(response);
527
- }
528
- await send(result);
529
- }
530
- }
538
+ await processPendingCall();
531
539
  return;
532
540
  }
533
541
  throw new Error(`Unhandled data type ${typeof message}`);