-
Notifications
You must be signed in to change notification settings - Fork 30.3k
/
Copy pathextHostWebviewMessaging.ts
122 lines (109 loc) · 6.21 KB
/
extHostWebviewMessaging.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from '../../../base/common/buffer.js';
import * as extHostProtocol from './extHost.protocol.js';
class ArrayBufferSet {
public readonly buffers: ArrayBuffer[] = [];
public add(buffer: ArrayBuffer): number {
let index = this.buffers.indexOf(buffer);
if (index < 0) {
index = this.buffers.length;
this.buffers.push(buffer);
}
return index;
}
}
export function serializeWebviewMessage(
message: any,
options: { serializeBuffersForPostMessage?: boolean }
): { message: string; buffers: VSBuffer[] } {
if (options.serializeBuffersForPostMessage) {
// Extract all ArrayBuffers from the message and replace them with references.
const arrayBuffers = new ArrayBufferSet();
const replacer = (_key: string, value: any) => {
if (value instanceof ArrayBuffer) {
const index = arrayBuffers.add(value);
return {
$$vscode_array_buffer_reference$$: true,
index,
} satisfies extHostProtocol.WebviewMessageArrayBufferReference;
} else if (ArrayBuffer.isView(value)) {
const type = getTypedArrayType(value);
if (type) {
const index = arrayBuffers.add(value.buffer);
return {
$$vscode_array_buffer_reference$$: true,
index,
view: {
type: type,
byteLength: value.byteLength,
byteOffset: value.byteOffset,
}
} satisfies extHostProtocol.WebviewMessageArrayBufferReference;
}
}
return value;
};
const serializedMessage = JSON.stringify(message, replacer);
const buffers = arrayBuffers.buffers.map(arrayBuffer => {
const bytes = new Uint8Array(arrayBuffer);
return VSBuffer.wrap(bytes);
});
return { message: serializedMessage, buffers };
} else {
return { message: JSON.stringify(message), buffers: [] };
}
}
function getTypedArrayType(value: ArrayBufferView): extHostProtocol.WebviewMessageArrayBufferViewType | undefined {
switch (value.constructor.name) {
case 'Int8Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int8Array;
case 'Uint8Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint8Array;
case 'Uint8ClampedArray': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint8ClampedArray;
case 'Int16Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int16Array;
case 'Uint16Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint16Array;
case 'Int32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int32Array;
case 'Uint32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint32Array;
case 'Float32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Float32Array;
case 'Float64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Float64Array;
case 'BigInt64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.BigInt64Array;
case 'BigUint64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.BigUint64Array;
}
return undefined;
}
export function deserializeWebviewMessage(jsonMessage: string, buffers: VSBuffer[]): { message: any; arrayBuffers: ArrayBuffer[] } {
const arrayBuffers: ArrayBuffer[] = buffers.map(buffer => {
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
const uint8Array = new Uint8Array(arrayBuffer);
uint8Array.set(buffer.buffer);
return arrayBuffer;
});
const reviver = !buffers.length ? undefined : (_key: string, value: any) => {
if (value && typeof value === 'object' && (value as extHostProtocol.WebviewMessageArrayBufferReference).$$vscode_array_buffer_reference$$) {
const ref = value as extHostProtocol.WebviewMessageArrayBufferReference;
const { index } = ref;
const arrayBuffer = arrayBuffers[index];
if (ref.view) {
switch (ref.view.type) {
case extHostProtocol.WebviewMessageArrayBufferViewType.Int8Array: return new Int8Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int8Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint8Array: return new Uint8Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint8Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint8ClampedArray: return new Uint8ClampedArray(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint8ClampedArray.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Int16Array: return new Int16Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int16Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint16Array: return new Uint16Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint16Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Int32Array: return new Int32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint32Array: return new Uint32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Float32Array: return new Float32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Float32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Float64Array: return new Float64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Float64Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.BigInt64Array: return new BigInt64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / BigInt64Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.BigUint64Array: return new BigUint64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / BigUint64Array.BYTES_PER_ELEMENT);
default: throw new Error('Unknown array buffer view type');
}
}
return arrayBuffer;
}
return value;
};
const message = JSON.parse(jsonMessage, reviver);
return { message, arrayBuffers };
}