@@ -7,6 +7,11 @@ import { Duplex } from 'stream';
7
7
* used when running compass-web in a local sandbox, mms has their own
8
8
* implementation
9
9
*/
10
+ enum MESSAGE_TYPE {
11
+ JSON = 0x01 ,
12
+ BINARY = 0x02 ,
13
+ }
14
+
10
15
class Socket extends Duplex {
11
16
private _ws : WebSocket | null = null ;
12
17
constructor ( ) {
@@ -36,7 +41,7 @@ class Socket extends Duplex {
36
41
ok : 1 ,
37
42
} ) ;
38
43
setTimeout ( ( ) => {
39
- this . _ws ?. send ( connectMsg ) ;
44
+ this . _ws ?. send ( this . encodeStringMessageWithTypeByte ( connectMsg ) ) ;
40
45
} ) ;
41
46
} ,
42
47
{ once : true }
@@ -49,10 +54,11 @@ class Socket extends Duplex {
49
54
} ) ;
50
55
this . _ws . addEventListener (
51
56
'message' ,
52
- ( { data } : MessageEvent < string | ArrayBuffer > ) => {
53
- if ( typeof data === 'string' ) {
57
+ ( { data } : MessageEvent < ArrayBuffer > ) => {
58
+ const dataView = new Uint8Array ( data ) ;
59
+ if ( dataView [ 0 ] === 0x01 ) {
54
60
try {
55
- const res = JSON . parse ( data ) as { preMessageOk : 1 } ;
61
+ const res = this . decodeMessageWithTypeByte ( dataView ) ;
56
62
if ( res . preMessageOk ) {
57
63
setTimeout ( ( ) => {
58
64
this . emit ( options . tls ? 'secureConnect' : 'connect' ) ;
@@ -64,7 +70,7 @@ class Socket extends Duplex {
64
70
}
65
71
} else {
66
72
setTimeout ( ( ) => {
67
- this . emit ( 'data' , Buffer . from ( data ) ) ;
73
+ this . emit ( 'data' , this . decodeMessageWithTypeByte ( dataView ) ) ;
68
74
} ) ;
69
75
}
70
76
}
@@ -75,7 +81,7 @@ class Socket extends Duplex {
75
81
// noop
76
82
}
77
83
_write ( chunk : ArrayBufferLike , _encoding : BufferEncoding , cb : ( ) => void ) {
78
- this . _ws ?. send ( chunk ) ;
84
+ this . _ws ?. send ( this . encodeBinaryMessageWithTypeByte ( new Uint8Array ( chunk ) ) ) ;
79
85
setTimeout ( ( ) => {
80
86
cb ( ) ;
81
87
} ) ;
@@ -110,6 +116,38 @@ class Socket extends Duplex {
110
116
setNoDelay ( ) {
111
117
return this ;
112
118
}
119
+
120
+ encodeStringMessageWithTypeByte ( message : string ) {
121
+ const utf8Encoder = new TextEncoder ( ) ;
122
+ const utf8Array = utf8Encoder . encode ( message ) ;
123
+ return this . encodeMessageWithTypeByte ( utf8Array , MESSAGE_TYPE . JSON ) ;
124
+ }
125
+
126
+ encodeBinaryMessageWithTypeByte ( message : Uint8Array ) {
127
+ return this . encodeMessageWithTypeByte ( message , MESSAGE_TYPE . BINARY ) ;
128
+ }
129
+
130
+ encodeMessageWithTypeByte ( message : Uint8Array , type : MESSAGE_TYPE ) {
131
+ const encoded = new Uint8Array ( message . length + 1 ) ;
132
+ encoded [ 0 ] = type ;
133
+ encoded . set ( message , 1 ) ;
134
+ return encoded ;
135
+ }
136
+
137
+ decodeMessageWithTypeByte ( message : Uint8Array ) {
138
+ const typeByte = message [ 0 ] ;
139
+ if ( typeByte === MESSAGE_TYPE . JSON ) {
140
+ const jsonBytes = message . subarray ( 1 ) ;
141
+ const textDecoder = new TextDecoder ( 'utf-8' ) ;
142
+ const jsonStr = textDecoder . decode ( jsonBytes ) ;
143
+ return JSON . parse ( jsonStr ) ;
144
+ } else if ( typeByte === MESSAGE_TYPE . BINARY ) {
145
+ return message . subarray ( 1 ) ;
146
+ } else {
147
+ // eslint-disable-next-line no-console
148
+ console . error ( 'message does not have valid type byte "%s"' , message ) ;
149
+ }
150
+ }
113
151
}
114
152
115
153
export { isIPv4 , isIPv6 } from 'is-ip' ;
0 commit comments