3
3
4
4
import * as KernelMessage from './messages' ;
5
5
6
+ /**
7
+ * Serialize a kernel message for transport.
8
+ */
9
+ export function serialize (
10
+ msg : KernelMessage . IMessage ,
11
+ protocol : string
12
+ ) : string | ArrayBuffer {
13
+ switch ( protocol ) {
14
+ case '0.0.1' :
15
+ return serialize_0_0_1 ( msg ) ;
16
+ default :
17
+ return serialize_default ( msg ) ;
18
+ }
19
+ }
20
+
6
21
/**
7
22
* Deserialize and return the unpacked message.
8
23
*/
9
- export function deserialize ( binMsg : ArrayBuffer ) : KernelMessage . IMessage {
24
+ export function deserialize (
25
+ data : ArrayBuffer ,
26
+ protocol : string
27
+ ) : KernelMessage . IMessage {
28
+ switch ( protocol ) {
29
+ case '0.0.1' :
30
+ return deserialize_0_0_1 ( data ) ;
31
+ default :
32
+ return deserialize_default ( data ) ;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Deserialize and return the unpacked message.
38
+ * Protocol v0.0.1
39
+ */
40
+ function deserialize_0_0_1 ( binMsg : ArrayBuffer ) : KernelMessage . IMessage {
10
41
let msg : KernelMessage . IMessage ;
11
42
const data = new DataView ( binMsg ) ;
12
43
const layoutLength = data . getUint16 ( 0 , true /* littleEndian */ ) ;
13
44
const layoutBytes = new Uint8Array ( binMsg . slice ( 2 , 2 + layoutLength ) ) ;
14
45
const decoder = new TextDecoder ( 'utf8' ) ;
15
46
const layout = JSON . parse ( decoder . decode ( layoutBytes ) ) ;
16
47
const channel = layout . channel ;
17
- let iter = getParts ( new Uint8Array ( binMsg . slice ( 2 + layoutLength ) ) , layout . offsets ) ;
48
+ let iter = getParts (
49
+ new Uint8Array ( binMsg . slice ( 2 + layoutLength ) ) ,
50
+ layout . offsets
51
+ ) ;
18
52
const header = JSON . parse ( decoder . decode ( iter . next ( ) . value as Uint8Array ) ) ;
19
- const parent_header = JSON . parse ( decoder . decode ( iter . next ( ) . value as Uint8Array ) ) ;
53
+ const parent_header = JSON . parse (
54
+ decoder . decode ( iter . next ( ) . value as Uint8Array )
55
+ ) ;
20
56
const metadata = JSON . parse ( decoder . decode ( iter . next ( ) . value as Uint8Array ) ) ;
21
57
const content = JSON . parse ( decoder . decode ( iter . next ( ) . value as Uint8Array ) ) ;
22
58
let curr = iter . next ( ) ;
@@ -31,58 +67,182 @@ export function deserialize(binMsg: ArrayBuffer): KernelMessage.IMessage {
31
67
parent_header,
32
68
metadata,
33
69
content,
34
- buffers,
70
+ buffers
35
71
} ;
36
72
return msg ;
37
73
}
38
74
39
75
/**
40
76
* Serialize a kernel message for transport.
77
+ * Protocol v0.0.1
41
78
*/
42
- export function serialize ( msg : KernelMessage . IMessage ) : ArrayBuffer {
79
+ function serialize_0_0_1 ( msg : KernelMessage . IMessage ) : ArrayBuffer {
43
80
const header = JSON . stringify ( msg . header ) ;
44
81
const parent_header = JSON . stringify ( msg . parent_header ) ;
45
82
const metadata = JSON . stringify ( msg . metadata ) ;
46
83
const content = JSON . stringify ( msg . content ) ;
47
84
let offsets = [ ] ;
48
85
let curr_sum = 0 ;
49
- for ( var length of [ header . length , parent_header . length , metadata . length , content . length ] ) {
86
+ for ( let length of [
87
+ header . length ,
88
+ parent_header . length ,
89
+ metadata . length ,
90
+ content . length
91
+ ] ) {
50
92
offsets . push ( length + curr_sum ) ;
51
93
curr_sum += length ;
52
94
}
53
95
let buffersLength = 0 ;
54
- const buffers : ( ArrayBuffer | ArrayBufferView ) [ ] = ( msg . buffers !== undefined ) ? msg . buffers : [ ] ;
55
- for ( var buffer of buffers ) {
56
- length = buffer . byteLength ;
96
+ const buffers : ( ArrayBuffer | ArrayBufferView ) [ ] =
97
+ msg . buffers !== undefined ? msg . buffers : [ ] ;
98
+ for ( let buffer of buffers ) {
99
+ let length = buffer . byteLength ;
57
100
offsets . push ( length + curr_sum ) ;
58
101
curr_sum += length ;
59
102
buffersLength += length ;
60
103
}
61
104
const layoutJson = {
62
105
channel : msg . channel ,
63
- offsets,
106
+ offsets
64
107
} ;
65
108
const layout = JSON . stringify ( layoutJson ) ;
66
109
const layoutLength = new ArrayBuffer ( 2 ) ;
67
- new DataView ( layoutLength ) . setInt16 ( 0 , layout . length , true /* littleEndian */ ) ;
110
+ new DataView ( layoutLength ) . setInt16 (
111
+ 0 ,
112
+ layout . length ,
113
+ true /* littleEndian */
114
+ ) ;
68
115
const encoder = new TextEncoder ( ) ;
69
- const binMsgNoBuff = encoder . encode ( layout + header + parent_header + metadata + content ) ;
116
+ const binMsgNoBuff = encoder . encode (
117
+ layout + header + parent_header + metadata + content
118
+ ) ;
70
119
const binMsg = new Uint8Array ( 2 + binMsgNoBuff . byteLength + buffersLength ) ;
71
120
binMsg . set ( new Uint8Array ( layoutLength ) , 0 ) ;
72
121
binMsg . set ( new Uint8Array ( binMsgNoBuff ) , 2 ) ;
73
122
let pos = 2 + binMsgNoBuff . byteLength ;
74
- for ( var buffer of buffers ) {
75
- binMsg . set ( new Uint8Array ( ArrayBuffer . isView ( buffer ) ? buffer . buffer : buffer ) , pos ) ;
123
+ for ( let buffer of buffers ) {
124
+ binMsg . set (
125
+ new Uint8Array ( ArrayBuffer . isView ( buffer ) ? buffer . buffer : buffer ) ,
126
+ pos
127
+ ) ;
76
128
pos += buffer . byteLength ;
77
129
}
78
130
return binMsg . buffer ;
79
131
}
80
132
81
133
function * getParts ( binMsg : Uint8Array , offsets : number [ ] ) {
82
134
let i0 = 0 ;
83
- for ( var i1 of offsets ) {
135
+ for ( let i1 of offsets ) {
84
136
yield binMsg . slice ( i0 , i1 ) ;
85
137
i0 = i1 ;
86
138
}
87
139
yield binMsg . slice ( i0 ) ;
88
140
}
141
+
142
+ /**
143
+ * Deserialize and return the unpacked message.
144
+ * Default protocol
145
+ *
146
+ * #### Notes
147
+ * Handles JSON blob strings and binary messages.
148
+ */
149
+ function deserialize_default (
150
+ data : ArrayBuffer | string
151
+ ) : KernelMessage . IMessage {
152
+ let value : KernelMessage . IMessage ;
153
+ if ( typeof data === 'string' ) {
154
+ value = JSON . parse ( data ) ;
155
+ } else {
156
+ value = deserializeBinary ( data ) ;
157
+ }
158
+ return value ;
159
+ }
160
+
161
+ /**
162
+ * Serialize a kernel message for transport.
163
+ * Default protocol
164
+ *
165
+ * #### Notes
166
+ * If there is binary content, an `ArrayBuffer` is returned,
167
+ * otherwise the message is converted to a JSON string.
168
+ */
169
+ function serialize_default ( msg : KernelMessage . IMessage ) : string | ArrayBuffer {
170
+ let value : string | ArrayBuffer ;
171
+ if ( msg . buffers ?. length ) {
172
+ value = serializeBinary ( msg ) ;
173
+ } else {
174
+ value = JSON . stringify ( msg ) ;
175
+ }
176
+ return value ;
177
+ }
178
+
179
+ /**
180
+ * Deserialize a binary message to a Kernel Message.
181
+ */
182
+ function deserializeBinary ( buf : ArrayBuffer ) : KernelMessage . IMessage {
183
+ const data = new DataView ( buf ) ;
184
+ // read the header: 1 + nbufs 32b integers
185
+ const nbufs = data . getUint32 ( 0 ) ;
186
+ const offsets : number [ ] = [ ] ;
187
+ if ( nbufs < 2 ) {
188
+ throw new Error ( 'Invalid incoming Kernel Message' ) ;
189
+ }
190
+ for ( let i = 1 ; i <= nbufs ; i ++ ) {
191
+ offsets . push ( data . getUint32 ( i * 4 ) ) ;
192
+ }
193
+ const jsonBytes = new Uint8Array ( buf . slice ( offsets [ 0 ] , offsets [ 1 ] ) ) ;
194
+ const msg = JSON . parse ( new TextDecoder ( 'utf8' ) . decode ( jsonBytes ) ) ;
195
+ // the remaining chunks are stored as DataViews in msg.buffers
196
+ msg . buffers = [ ] ;
197
+ for ( let i = 1 ; i < nbufs ; i ++ ) {
198
+ const start = offsets [ i ] ;
199
+ const stop = offsets [ i + 1 ] || buf . byteLength ;
200
+ msg . buffers . push ( new DataView ( buf . slice ( start , stop ) ) ) ;
201
+ }
202
+ return msg ;
203
+ }
204
+
205
+ /**
206
+ * Implement the binary serialization protocol.
207
+ *
208
+ * Serialize Kernel message to ArrayBuffer.
209
+ */
210
+ function serializeBinary ( msg : KernelMessage . IMessage ) : ArrayBuffer {
211
+ const offsets : number [ ] = [ ] ;
212
+ const buffers : ArrayBuffer [ ] = [ ] ;
213
+ const encoder = new TextEncoder ( ) ;
214
+ let origBuffers : ( ArrayBuffer | ArrayBufferView ) [ ] = [ ] ;
215
+ if ( msg . buffers !== undefined ) {
216
+ origBuffers = msg . buffers ;
217
+ delete msg [ 'buffers' ] ;
218
+ }
219
+ const jsonUtf8 = encoder . encode ( JSON . stringify ( msg ) ) ;
220
+ buffers . push ( jsonUtf8 . buffer ) ;
221
+ for ( let i = 0 ; i < origBuffers . length ; i ++ ) {
222
+ // msg.buffers elements could be either views or ArrayBuffers
223
+ // buffers elements are ArrayBuffers
224
+ const b : any = origBuffers [ i ] ;
225
+ buffers . push ( ArrayBuffer . isView ( b ) ? b . buffer : b ) ;
226
+ }
227
+ const nbufs = buffers . length ;
228
+ offsets . push ( 4 * ( nbufs + 1 ) ) ;
229
+ for ( let i = 0 ; i + 1 < buffers . length ; i ++ ) {
230
+ offsets . push ( offsets [ offsets . length - 1 ] + buffers [ i ] . byteLength ) ;
231
+ }
232
+ const msgBuf = new Uint8Array (
233
+ offsets [ offsets . length - 1 ] + buffers [ buffers . length - 1 ] . byteLength
234
+ ) ;
235
+ // use DataView.setUint32 for network byte-order
236
+ const view = new DataView ( msgBuf . buffer ) ;
237
+ // write nbufs to first 4 bytes
238
+ view . setUint32 ( 0 , nbufs ) ;
239
+ // write offsets to next 4 * nbufs bytes
240
+ for ( let i = 0 ; i < offsets . length ; i ++ ) {
241
+ view . setUint32 ( 4 * ( i + 1 ) , offsets [ i ] ) ;
242
+ }
243
+ // write all the buffers at their respective offsets
244
+ for ( let i = 0 ; i < buffers . length ; i ++ ) {
245
+ msgBuf . set ( new Uint8Array ( buffers [ i ] ) , offsets [ i ] ) ;
246
+ }
247
+ return msgBuf . buffer ;
248
+ }
0 commit comments