Forráskód Böngészése

Replace deep copy function to fully support all ARP field types

Lennart Grahl 6 éve
szülő
commit
79a4f4e937
2 módosított fájl, 51 hozzáadás és 8 törlés
  1. 49 6
      src/helpers.ts
  2. 2 2
      src/services/webclient.ts

+ 49 - 6
src/helpers.ts

@@ -370,18 +370,61 @@ export function isActionTrigger(ev: KeyboardEvent): boolean {
     }
 }
 
-/*
+/**
  * Create a shallow copy of an object.
  */
-export function copyShallow<T extends object>(obj: T): T {
-    return Object.assign({}, obj);
+export function copyShallow(object: object): object {
+    return Object.assign({}, object);
 }
 
 /**
- * Create a deep copy of an object by serializing and deserializing it.
+ * Create a deep copy (mostly).
+ *
+ * This handles the following types:
+ *
+ * - copies `undefined` and `null`,
+ * - copies `Boolean`, `Number` and `String`,
+ * - copies `object` recursively,
+ * - copies `Array` recursively,
+ * - copies `ArrayBuffer`,
+ * - copies `Uint8Array`,
+ *
+ * Everything else will be **referenced**.
  */
-export function copyDeep<T extends object>(obj: T): T {
-    return JSON.parse(JSON.stringify(obj));
+export function copyDeepOrReference(value: any): any {
+    // Handle `null` and `undefined` early
+    if (value === null || value === undefined) {
+        return value;
+    }
+
+    // Plain object
+    if (value.constructor === Object) {
+        const object = {};
+        for (const [k, v] of Object.entries(value)) {
+            object[k] = copyDeepOrReference(v);
+        }
+        return object;
+    }
+
+    // Plain array
+    if (value instanceof Array) {
+        return value.map((item) => copyDeepOrReference(item));
+    }
+
+    // ArrayBuffer
+    if (value instanceof ArrayBuffer) {
+        return value.slice(0);
+    }
+
+    // Uint8Array
+    if (value instanceof Uint8Array) {
+        // Note: To mimic the byte offset, we copy the whole underlying buffer.
+        const buffer = value.buffer.slice(0);
+        return new Uint8Array(buffer, value.byteOffset, value.byteLength);
+    }
+
+    // Reference everything else
+    return value;
 }
 
 /**

+ 2 - 2
src/services/webclient.ts

@@ -24,7 +24,7 @@ import {Logger} from 'ts-log';
 
 import * as msgpack from 'msgpack-lite';
 import {
-    arraysAreEqual, base64ToU8a, bufferToUrl, copyDeep, hasFeature, hasValue, hexToU8a,
+    arraysAreEqual, base64ToU8a, bufferToUrl, copyDeepOrReference, hasFeature, hasValue, hexToU8a,
     msgpackVisualizer, randomString, stringToUtf8a, u8aToHex,
 } from '../helpers';
 import {
@@ -4056,7 +4056,7 @@ export class WebClientService {
             // Sanitise incoming message before logging
             // Note: Deep-copy message to prevent issues with JS debugger
             this.arpLogV.debug(`Incoming: ${message.type}/${message.subType}`,
-                new ConfidentialWireMessage(copyDeep(message)));
+                new ConfidentialWireMessage(copyDeepOrReference(message)));
         }
 
         // Process data