wspromisify 2.4.4 → 2.5.0
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.
- package/LICENSE +1 -1
- package/README.md +1 -2
- package/TODO +9 -0
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.ts +7 -2
- package/dist/bundle.mjs +1 -1
- package/package.json +91 -94
- package/rollup.config.js +1 -1
- package/src/WSC.ts +271 -0
- package/src/config.ts +7 -6
- package/src/utils.ts +5 -23
- package/test/index.ts +21 -0
- package/test/mock/WS.ts +43 -0
- package/test/mock/server.ts +17 -0
- package/test/specs/close.ts +18 -0
- package/test/specs/drops.ts +30 -0
- package/test/specs/echo.ts +24 -0
- package/test/specs/encode-decode.ts +1 -0
- package/test/specs/existing_socket.ts +55 -0
- package/test/specs/lazy.ts +22 -0
- package/test/specs/lazySendBeforeOpen.ts +19 -0
- package/test/specs/no-native-throws.ts +18 -0
- package/test/specs/ready.ts +12 -0
- package/test/specs/reconnect.ts +23 -0
- package/test/specs/socket.ts +13 -0
- package/test/suite.ts +3 -0
- package/test/utils.ts +27 -0
- package/tsconfig.json +3 -2
- package/src/WS.ts +0 -166
- package/src/connectLib.ts +0 -120
- package/test/mock/WS.js +0 -51
- package/test/mock/index.js +0 -52
- package/test/specs/close.js +0 -25
- package/test/specs/drops.js +0 -29
- package/test/specs/echo.js +0 -26
- package/test/specs/encode-decode.js +0 -3
- package/test/specs/existing_socket.js +0 -55
- package/test/specs/lazy.js +0 -26
- package/test/specs/ready.js +0 -16
- package/test/specs/reconnect.js +0 -28
- package/test/specs/sendBeforeOpen.js +0 -23
- package/test/specs/socket.js +0 -22
- package/test/specs/utils_once.js +0 -16
- package/test/utils.js +0 -27
package/src/WSC.ts
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import './types'
|
|
2
|
+
import { Zipnum } from 'zipnum'
|
|
3
|
+
import { add_event, sett } from './utils'
|
|
4
|
+
import { processConfig } from './config'
|
|
5
|
+
import { AnyFunc, once, T } from 'pepka'
|
|
6
|
+
|
|
7
|
+
const MAX_32 = 2**31 - 1
|
|
8
|
+
const zipnum = new Zipnum()
|
|
9
|
+
|
|
10
|
+
class WebSocketClient {
|
|
11
|
+
private open = false
|
|
12
|
+
private ws: wsc.Socket|null = null
|
|
13
|
+
private forcibly_closed = false
|
|
14
|
+
private reconnect_timeout: NodeJS.Timeout|null = null
|
|
15
|
+
private queue = {}
|
|
16
|
+
private messages: any[] = []
|
|
17
|
+
private onReadyQueue: AnyFunc[] = []
|
|
18
|
+
private onCloseQueue: AnyFunc[] = []
|
|
19
|
+
private handlers = <{[event in wsc.WSEvent]: ((e: any) => void)[]}>{
|
|
20
|
+
open: [], close: [], message: [], error: []
|
|
21
|
+
}
|
|
22
|
+
private config = <wsc.Config>{}
|
|
23
|
+
|
|
24
|
+
private init_flush(): void {
|
|
25
|
+
this.queue = {} // data queuse
|
|
26
|
+
this.messages = [] // send() queue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private log(event: string, message: any = null, time: number|null = null): void {
|
|
30
|
+
const config = this.config
|
|
31
|
+
if(time !== null) {
|
|
32
|
+
config.log(event, time, message)
|
|
33
|
+
} else {
|
|
34
|
+
if(config.timer) {
|
|
35
|
+
config.log(event, null, message)
|
|
36
|
+
} else {
|
|
37
|
+
config.log(event, message)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private initSocket(ws: wsc.Socket) {
|
|
43
|
+
const config = this.config
|
|
44
|
+
this.open = true
|
|
45
|
+
this.onReadyQueue.forEach((fn: Function) => fn())
|
|
46
|
+
this.onReadyQueue.splice(0)
|
|
47
|
+
const {id_key, data_key} = config.server
|
|
48
|
+
// Works also on previously opened sockets that do not fire 'open' event.
|
|
49
|
+
this.handlers.open.forEach((h) => h(ws))
|
|
50
|
+
// Send all pending messages.
|
|
51
|
+
this.messages.forEach((message: any) => message.send())
|
|
52
|
+
// It's reconnecting.
|
|
53
|
+
if(this.reconnect_timeout !== null) {
|
|
54
|
+
clearInterval(this.reconnect_timeout)
|
|
55
|
+
this.reconnect_timeout = null
|
|
56
|
+
}
|
|
57
|
+
if(config.ping) {
|
|
58
|
+
const ping_interval = setInterval(() => {
|
|
59
|
+
if(this.open) this.send(config.ping.content)
|
|
60
|
+
if(this.forcibly_closed) clearInterval(ping_interval)
|
|
61
|
+
}, config.ping.interval*1e3)
|
|
62
|
+
}
|
|
63
|
+
add_event(ws, 'close', async (...e) => {
|
|
64
|
+
this.log('close')
|
|
65
|
+
this.open = false
|
|
66
|
+
this.onCloseQueue.forEach((fn: Function) => fn())
|
|
67
|
+
this.onCloseQueue.splice(0)
|
|
68
|
+
this.handlers.close.forEach((h: any) => h(...e))
|
|
69
|
+
// Auto reconnect.
|
|
70
|
+
const reconnect = config.reconnect
|
|
71
|
+
if(
|
|
72
|
+
typeof reconnect === 'number' &&
|
|
73
|
+
!isNaN(reconnect) &&
|
|
74
|
+
!this.forcibly_closed
|
|
75
|
+
) {
|
|
76
|
+
const reconnectFunc = async () => {
|
|
77
|
+
this.log('reconnect')
|
|
78
|
+
if(this.ws !== null) {
|
|
79
|
+
this.ws.close()
|
|
80
|
+
this.ws = null
|
|
81
|
+
}
|
|
82
|
+
// If some error occured, try again.
|
|
83
|
+
const status = await this.connect()
|
|
84
|
+
if(status !== null) {
|
|
85
|
+
this.reconnect_timeout = setTimeout(reconnectFunc, reconnect * 1000)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// No need for await.
|
|
89
|
+
reconnectFunc()
|
|
90
|
+
} else {
|
|
91
|
+
this.ws = null
|
|
92
|
+
this.open = false
|
|
93
|
+
}
|
|
94
|
+
// reset the flag to reuse.
|
|
95
|
+
this.forcibly_closed = false
|
|
96
|
+
})
|
|
97
|
+
add_event(ws, 'message', (e) => {
|
|
98
|
+
try {
|
|
99
|
+
const data = config.decode(e.data)
|
|
100
|
+
this.handlers.message.forEach((h: any) => h({...e, data}))
|
|
101
|
+
if(data[id_key]) {
|
|
102
|
+
const q = this.queue[data[id_key]]
|
|
103
|
+
if(q) {
|
|
104
|
+
// Debug, Log.
|
|
105
|
+
const time = q.sent_time ? (Date.now() - q.sent_time) : null
|
|
106
|
+
this.log('message', data[data_key], time)
|
|
107
|
+
// Play.
|
|
108
|
+
q.ff(data[data_key])
|
|
109
|
+
clearTimeout(q.timeout)
|
|
110
|
+
delete this.queue[data[id_key]]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(err, `WSP: Decode error. Got: ${e.data}`)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private async connect() { // returns status if won't open or null if ok.
|
|
120
|
+
return new Promise((ff) => {
|
|
121
|
+
if(this.open === true) {
|
|
122
|
+
return ff(null)
|
|
123
|
+
}
|
|
124
|
+
const config = this.config
|
|
125
|
+
const ws = config.socket || config.adapter(config.url, config.protocols)
|
|
126
|
+
this.ws = ws
|
|
127
|
+
|
|
128
|
+
if(!ws || ws.readyState > 1) {
|
|
129
|
+
this.ws = null
|
|
130
|
+
this.log('error', 'ready() on closing or closed state! status 2.')
|
|
131
|
+
return ff(2)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
add_event(ws, 'error', once((e) => {
|
|
135
|
+
this.log('error', 'status 3.')
|
|
136
|
+
this.handlers.error.forEach((h) => h(e))
|
|
137
|
+
this.ws = null
|
|
138
|
+
// Some network error: Connection refused or so.
|
|
139
|
+
return ff(3)
|
|
140
|
+
}))
|
|
141
|
+
// Because 'open' won't be envoked on opened socket.
|
|
142
|
+
if(ws.readyState) {
|
|
143
|
+
this.initSocket(ws)
|
|
144
|
+
ff(null)
|
|
145
|
+
} else {
|
|
146
|
+
add_event(ws, 'open', once(() => {
|
|
147
|
+
this.log('open')
|
|
148
|
+
this.initSocket(ws)
|
|
149
|
+
return ff(null)
|
|
150
|
+
}))
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public get socket() {
|
|
156
|
+
return this.ws
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public async ready() {
|
|
160
|
+
return new Promise<void>((ff) => {
|
|
161
|
+
if(this.open) {
|
|
162
|
+
ff()
|
|
163
|
+
} else {
|
|
164
|
+
this.onReadyQueue.push(ff)
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public on(
|
|
170
|
+
event_name: wsc.WSEvent,
|
|
171
|
+
handler: (data: any) => any,
|
|
172
|
+
predicate: (data: any) => boolean = T,
|
|
173
|
+
raw = false
|
|
174
|
+
) {
|
|
175
|
+
const _handler: wsc.EventHandler = (event) =>
|
|
176
|
+
predicate(event) && handler(event)
|
|
177
|
+
return raw
|
|
178
|
+
? add_event(this.ws as wsc.Socket, event_name, _handler)
|
|
179
|
+
: this.handlers[event_name].push(_handler)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public async close(): wsc.AsyncErrCode {
|
|
183
|
+
return new Promise((ff, rj) => {
|
|
184
|
+
if(this.ws === null) {
|
|
185
|
+
rj('WSP: closing a non-inited socket!')
|
|
186
|
+
} else {
|
|
187
|
+
this.open = false
|
|
188
|
+
this.onCloseQueue.push(() => {
|
|
189
|
+
this.init_flush()
|
|
190
|
+
this.ws = null
|
|
191
|
+
this.forcibly_closed = true
|
|
192
|
+
ff(null)
|
|
193
|
+
})
|
|
194
|
+
this.ws.close()
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** .send(your_data) wraps request to server with {id: `hash`, data: `actually your data`},
|
|
200
|
+
returns a Promise that will be rejected after a timeout or
|
|
201
|
+
resolved if server returns the same signature: {id: `same_hash`, data: `response data`}.
|
|
202
|
+
*/
|
|
203
|
+
public async send<RequestDataType = any, ResponseDataType = any>(
|
|
204
|
+
message_data: RequestDataType,
|
|
205
|
+
opts = <wsc.SendOptions>{}
|
|
206
|
+
): Promise<ResponseDataType> {
|
|
207
|
+
this.log('send', message_data)
|
|
208
|
+
const config = this.config
|
|
209
|
+
const message = {}
|
|
210
|
+
const data_key = config.server.data_key
|
|
211
|
+
const first_time_lazy = config.lazy && !this.open
|
|
212
|
+
|
|
213
|
+
const message_id = zipnum.zip((Math.random()*(MAX_32-10))|0)
|
|
214
|
+
if(typeof opts.top === 'object') {
|
|
215
|
+
if(opts.top[data_key]) {
|
|
216
|
+
throw new Error('Attempting to set data key/token via send() options!')
|
|
217
|
+
}
|
|
218
|
+
Object.assign(message, opts.top)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
config.pipes.forEach(
|
|
222
|
+
(pipe) => message_data = pipe(message_data)
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if(this.open === true) {
|
|
226
|
+
(this.ws as wsc.Socket).send(config.encode(message_id, message_data, config))
|
|
227
|
+
} else if(this.open === false || first_time_lazy) {
|
|
228
|
+
this.messages.push({
|
|
229
|
+
send: () => (this.ws as wsc.Socket).send(config.encode(message_id, message_data, config))
|
|
230
|
+
})
|
|
231
|
+
if(first_time_lazy) {
|
|
232
|
+
this.connect()
|
|
233
|
+
}
|
|
234
|
+
} else if(this.open === null) {
|
|
235
|
+
throw new Error('Attempting to send via closed WebSocket connection!')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return new Promise((ff, rj) => {
|
|
239
|
+
this.queue[message_id] = {
|
|
240
|
+
ff,
|
|
241
|
+
data_type: config.data_type,
|
|
242
|
+
sent_time: config.timer ? Date.now() : null,
|
|
243
|
+
timeout: sett(config.timeout, () => {
|
|
244
|
+
if(this.queue[message_id]) {
|
|
245
|
+
rj({
|
|
246
|
+
'Websocket timeout expired: ': config.timeout,
|
|
247
|
+
'for the message ': message_data
|
|
248
|
+
})
|
|
249
|
+
delete this.queue[message_id]
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
constructor(user_config: wsc.UserConfig = {}) {
|
|
257
|
+
this.config = processConfig(user_config)
|
|
258
|
+
// Init.
|
|
259
|
+
this.init_flush()
|
|
260
|
+
// Flags.
|
|
261
|
+
this.open = false
|
|
262
|
+
this.reconnect_timeout = null
|
|
263
|
+
this.forcibly_closed = false
|
|
264
|
+
if(!this.config.lazy) {
|
|
265
|
+
this.connect()
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* TODO: v3: @.deprecated. Use named import { WebSocketClient } instead. */
|
|
271
|
+
export default WebSocketClient
|
package/src/config.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import './types'
|
|
2
|
+
import { native_ws } from './utils'
|
|
2
3
|
|
|
3
4
|
const default_config = <wsc.Config>{
|
|
4
5
|
data_type: 'json', // ToDo some other stuff maybe.
|
|
@@ -29,13 +30,17 @@ const default_config = <wsc.Config>{
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
const
|
|
33
|
+
export const processConfig = (config: wsc.UserConfig) => {
|
|
34
|
+
if(native_ws===null && !('adapter' in config)) throw new Error(`
|
|
35
|
+
This platform has no native WebSocket implementation.
|
|
36
|
+
Please use 'ws' package as an adapter.
|
|
37
|
+
See https://github.com/houd1ni/WebsocketPromisify/issues/23
|
|
38
|
+
`)
|
|
33
39
|
const full_config: wsc.Config = Object.assign(
|
|
34
40
|
{},
|
|
35
41
|
default_config,
|
|
36
42
|
config
|
|
37
43
|
)
|
|
38
|
-
|
|
39
44
|
const url = full_config.url
|
|
40
45
|
if(url[0] == '/') {
|
|
41
46
|
try {
|
|
@@ -47,8 +52,4 @@ const enrichConfig = (config: wsc.UserConfig) => {
|
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
return full_config
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export {
|
|
53
|
-
enrichConfig
|
|
54
55
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
import './types'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
return o.addEventListener(e, handler)
|
|
5
|
-
}
|
|
3
|
+
export const native_ws = (() => {try {return WebSocket||null}catch { return null }})()
|
|
6
4
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
let cached = null
|
|
10
|
-
return (...args: any) => {
|
|
11
|
-
if(has_been_cached) {
|
|
12
|
-
return cached
|
|
13
|
-
} else {
|
|
14
|
-
has_been_cached = true
|
|
15
|
-
return cached = fn(...args)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
5
|
+
export const add_event = (o: wsc.Socket, e: string, handler: wsc.EventHandler) => {
|
|
6
|
+
return o.addEventListener(e, handler)
|
|
18
7
|
}
|
|
19
8
|
|
|
20
|
-
const sett = (
|
|
9
|
+
export const sett = (
|
|
21
10
|
a: number,
|
|
22
11
|
b: { (): void; (...args: any[]): void; }
|
|
23
|
-
) => setTimeout(b, a)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export {
|
|
27
|
-
add_event,
|
|
28
|
-
once,
|
|
29
|
-
sett
|
|
30
|
-
}
|
|
12
|
+
) => setTimeout(b, a)
|
package/test/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import './specs/close'
|
|
2
|
+
import './specs/drops'
|
|
3
|
+
import './specs/echo'
|
|
4
|
+
import './specs/existing_socket'
|
|
5
|
+
import './specs/lazy'
|
|
6
|
+
import './specs/ready'
|
|
7
|
+
import './specs/reconnect'
|
|
8
|
+
import './specs/lazySendBeforeOpen'
|
|
9
|
+
import './specs/socket'
|
|
10
|
+
import './specs/no-native-throws'
|
|
11
|
+
import mockServer from './mock/server'
|
|
12
|
+
import {test} from './suite'
|
|
13
|
+
|
|
14
|
+
const {shutDown} = await mockServer()
|
|
15
|
+
test.after(() => {
|
|
16
|
+
setTimeout(async () => {
|
|
17
|
+
await shutDown()
|
|
18
|
+
process.exit()
|
|
19
|
+
}, 100)
|
|
20
|
+
})
|
|
21
|
+
test.run()
|
package/test/mock/WS.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
import WebSocket, { WebSocketServer } from 'ws'
|
|
3
|
+
import {noop} from 'pepka'
|
|
4
|
+
|
|
5
|
+
let server: WebSocketServer|null = null
|
|
6
|
+
|
|
7
|
+
const createServer = (port = 40510) => new Promise<WebSocketServer>((ff, rj) => {
|
|
8
|
+
if(server) return rj('The server is already running!')
|
|
9
|
+
server = new WebSocketServer({ port }, () => {
|
|
10
|
+
server!.on('connection', (socket: WebSocket&{isAlive: boolean}) => {
|
|
11
|
+
socket.on('message', (rawMessage: string) => {
|
|
12
|
+
const {id, data} = JSON.parse(rawMessage)
|
|
13
|
+
let response = ''
|
|
14
|
+
if(data.shut) {
|
|
15
|
+
socket.terminate()
|
|
16
|
+
socket.isAlive = false
|
|
17
|
+
socket.ping('', false, noop)
|
|
18
|
+
return null
|
|
19
|
+
} else if(data.echo) {
|
|
20
|
+
response = data
|
|
21
|
+
}
|
|
22
|
+
socket.send(JSON.stringify({ id, data: response }))
|
|
23
|
+
return null
|
|
24
|
+
})
|
|
25
|
+
return true
|
|
26
|
+
})
|
|
27
|
+
return ff(server!)
|
|
28
|
+
})
|
|
29
|
+
server.on('', console.log)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const killServer = async () => new Promise<void>((ff, rj) => {
|
|
33
|
+
if(server) {
|
|
34
|
+
for(const socket of server.clients) socket.terminate()
|
|
35
|
+
server.close(() => {
|
|
36
|
+
server = null
|
|
37
|
+
ff()
|
|
38
|
+
})
|
|
39
|
+
} else
|
|
40
|
+
rj('The server is already down!')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export { createServer, killServer }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import { WebSocketServer } from 'ws'
|
|
3
|
+
import { createServer, killServer } from './WS.js'
|
|
4
|
+
|
|
5
|
+
let port: number,
|
|
6
|
+
server: WebSocketServer|null
|
|
7
|
+
|
|
8
|
+
export default async (new_port?: number) => {
|
|
9
|
+
if(!server) {
|
|
10
|
+
port = new_port || 8000 + Math.ceil(Math.random()*500)
|
|
11
|
+
server = await createServer(port)
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
server, port,
|
|
15
|
+
shutDown: async () => { await killServer(); server=null }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { test } from '../suite'
|
|
2
|
+
import { createNew } from '../utils.js'
|
|
3
|
+
import mockServer from '../mock/server'
|
|
4
|
+
|
|
5
|
+
/** Closes the connenction. */
|
|
6
|
+
test('close', () => new Promise<void>(async (ff, rj) => {
|
|
7
|
+
const {port} = await mockServer()
|
|
8
|
+
const ws = createNew({}, port)
|
|
9
|
+
|
|
10
|
+
setTimeout(async () => {
|
|
11
|
+
try {
|
|
12
|
+
await ws.close()
|
|
13
|
+
if(ws.socket === null) ff(); else rj()
|
|
14
|
+
} catch(e) {
|
|
15
|
+
rj()
|
|
16
|
+
}
|
|
17
|
+
}, 500)
|
|
18
|
+
}))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createNew } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { test } from '../suite'
|
|
4
|
+
|
|
5
|
+
/** Rejects messages by timout */
|
|
6
|
+
test('drops', () => new Promise(async (ff, rj) => {
|
|
7
|
+
const {port, shutDown} = await mockServer()
|
|
8
|
+
const ws = createNew({timeout: 500}, port)
|
|
9
|
+
|
|
10
|
+
await shutDown()
|
|
11
|
+
const lauchServ = async () => await mockServer(port)
|
|
12
|
+
|
|
13
|
+
setTimeout(async () => {
|
|
14
|
+
const msg = {echo: true, msg: 'hello!'}
|
|
15
|
+
let to: NodeJS.Timeout
|
|
16
|
+
try {
|
|
17
|
+
to = setTimeout(() => {
|
|
18
|
+
return rj()
|
|
19
|
+
}, 600)
|
|
20
|
+
await ws.send(msg)
|
|
21
|
+
if(to) clearTimeout(to)
|
|
22
|
+
await lauchServ()
|
|
23
|
+
return rj()
|
|
24
|
+
} catch(e) {
|
|
25
|
+
if(to!) clearTimeout(to)
|
|
26
|
+
await lauchServ()
|
|
27
|
+
return ff()
|
|
28
|
+
}
|
|
29
|
+
}, 200)
|
|
30
|
+
}))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { equals } from 'pepka'
|
|
2
|
+
import { createNew, timeout } from '../utils'
|
|
3
|
+
import mockServer from '../mock/server'
|
|
4
|
+
import { test } from '../suite'
|
|
5
|
+
|
|
6
|
+
/** Proof of work. */
|
|
7
|
+
test('echo', timeout(5e3, () => new Promise<void>(async (ff, rj) => {
|
|
8
|
+
const {port} = await mockServer()
|
|
9
|
+
let to = setTimeout(() => rj('cannot create'), 2e2)
|
|
10
|
+
const ws = createNew({}, port)
|
|
11
|
+
clearTimeout(to)
|
|
12
|
+
|
|
13
|
+
to = setTimeout(() => rj('cannot ready'), 2e2)
|
|
14
|
+
await ws.ready()
|
|
15
|
+
clearTimeout(to)
|
|
16
|
+
|
|
17
|
+
const msg = {echo: true, msg: 'hello!'}
|
|
18
|
+
to = setTimeout(() => rj('cannot send'), 2e2)
|
|
19
|
+
const response = await ws.send(msg)
|
|
20
|
+
clearTimeout(to)
|
|
21
|
+
|
|
22
|
+
if(equals(response, msg)) ff(); else rj('echo msg is not equal.')
|
|
23
|
+
})
|
|
24
|
+
))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// TODO with mock server with specific port.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createNew } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
|
|
4
|
+
import WS from 'ws'
|
|
5
|
+
import { test } from '../suite'
|
|
6
|
+
import { equals } from 'pepka'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const addr = (port: number) => 'ws://localhost:' + port
|
|
10
|
+
|
|
11
|
+
/** If an existing socket connection is provided via config. */
|
|
12
|
+
test('existing_socket', () => {
|
|
13
|
+
return new Promise(async (ff, rj) => {
|
|
14
|
+
const {port} = await mockServer()
|
|
15
|
+
const to = setTimeout(() => rj(), 4e4)
|
|
16
|
+
const existing_addr = addr(port)
|
|
17
|
+
|
|
18
|
+
// This one CANNOT connect as fast as we send to it,
|
|
19
|
+
// So readyState is 0.
|
|
20
|
+
const ws1 = createNew({socket: new WS(existing_addr)}, port)
|
|
21
|
+
|
|
22
|
+
if(ws1.socket?.readyState !== 0) return rj('not ready.')
|
|
23
|
+
|
|
24
|
+
const msg1 = {echo: true, msg: 'existing_socket!'}
|
|
25
|
+
const response1 = await ws1.send(msg1)
|
|
26
|
+
|
|
27
|
+
if(
|
|
28
|
+
ws1.socket?.readyState as number !== 1
|
|
29
|
+
|| !equals(response1, msg1)
|
|
30
|
+
) return rj('not ready.')
|
|
31
|
+
await ws1.close()
|
|
32
|
+
|
|
33
|
+
// This one DO CAN connect as fast as we send to it,
|
|
34
|
+
// So readyState should be 1.
|
|
35
|
+
const ws2_0 = new WS(existing_addr)
|
|
36
|
+
|
|
37
|
+
ws2_0.addEventListener('open', async () => {
|
|
38
|
+
const ws2 = await createNew({socket: ws2_0}, port)
|
|
39
|
+
|
|
40
|
+
if(ws2.socket?.readyState !== 1) return rj('not ready.')
|
|
41
|
+
|
|
42
|
+
const msg2 = {echo: true, msg: 'existing_socket!'}
|
|
43
|
+
const response2 = await ws2.send(msg2)
|
|
44
|
+
|
|
45
|
+
if(
|
|
46
|
+
ws2.socket?.readyState as number !== 1
|
|
47
|
+
|| !equals(response2, msg2)
|
|
48
|
+
) return rj('not ready.')
|
|
49
|
+
await ws2.close()
|
|
50
|
+
|
|
51
|
+
clearTimeout(to)
|
|
52
|
+
ff()
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createNew, timeout } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { equals } from 'pepka'
|
|
4
|
+
import { test } from '../suite'
|
|
5
|
+
|
|
6
|
+
/** Lazy connect */
|
|
7
|
+
test('lazy', timeout(2e3, () => {
|
|
8
|
+
return new Promise<void>(async (ff, rj) => {
|
|
9
|
+
const {port} = await mockServer()
|
|
10
|
+
const ws = createNew({ lazy: true }, port)
|
|
11
|
+
|
|
12
|
+
setTimeout(async () => {
|
|
13
|
+
if(ws.socket !== null) {
|
|
14
|
+
rj()
|
|
15
|
+
} else {
|
|
16
|
+
const msg = {echo: true, msg: 'hello!'}
|
|
17
|
+
const response = await ws.send(msg)
|
|
18
|
+
if(equals(response, msg)) ff(); else rj()
|
|
19
|
+
}
|
|
20
|
+
}, 500)
|
|
21
|
+
})
|
|
22
|
+
}))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createNew } from '../utils.js'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { equals } from 'pepka'
|
|
4
|
+
import { test } from '../suite'
|
|
5
|
+
|
|
6
|
+
/** Sends massages if they were .send() before connection is estabilished. */
|
|
7
|
+
test('lazy send before open queued.', () => new Promise(async (ff, rj) => {
|
|
8
|
+
const {port} = await mockServer()
|
|
9
|
+
let to = setTimeout(() => rj('cannot create'), 2e2)
|
|
10
|
+
const ws = createNew({lazy: true}, port)
|
|
11
|
+
clearTimeout(to)
|
|
12
|
+
|
|
13
|
+
const msg = {echo: true, msg: 'hello!'}
|
|
14
|
+
to = setTimeout(() => rj('cannot send'), 2e2)
|
|
15
|
+
const response = await ws.send(msg)
|
|
16
|
+
clearTimeout(to)
|
|
17
|
+
|
|
18
|
+
if(equals(response, msg)) ff(); else rj()
|
|
19
|
+
}))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import mockServer from '../mock/server'
|
|
2
|
+
import { test } from '../suite'
|
|
3
|
+
import {WebSocketClient} from '../../src/WSC'
|
|
4
|
+
|
|
5
|
+
/** Ready method. */
|
|
6
|
+
test('No native throws without an adapter', async () => {
|
|
7
|
+
const {port} = await mockServer()
|
|
8
|
+
let pass = false
|
|
9
|
+
try {
|
|
10
|
+
new WebSocketClient({ url: 'ws://127.0.0.1:' + port })
|
|
11
|
+
try {
|
|
12
|
+
if(WebSocket) pass = true
|
|
13
|
+
} catch {}
|
|
14
|
+
} catch {
|
|
15
|
+
pass=true
|
|
16
|
+
}
|
|
17
|
+
if(!pass) throw new Error('Does not throw.')
|
|
18
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createNew, timeout } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { test } from '../suite'
|
|
4
|
+
|
|
5
|
+
/** Ready method. */
|
|
6
|
+
test('ready', timeout(4e3, async () => {
|
|
7
|
+
const {port} = await mockServer()
|
|
8
|
+
const ws = createNew({}, port)
|
|
9
|
+
|
|
10
|
+
await ws.ready()
|
|
11
|
+
if(!ws.socket) throw new Error()
|
|
12
|
+
}))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createNew, timeout } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { equals } from 'pepka'
|
|
4
|
+
import { test } from '../suite'
|
|
5
|
+
|
|
6
|
+
/** Reconnects if connection is broken. */
|
|
7
|
+
test('reconnect', timeout(1e4, () => new Promise<void>(async (ff, rj) => {
|
|
8
|
+
const {port, shutDown} = await mockServer()
|
|
9
|
+
const ws = createNew({ reconnect: 1 }, port)
|
|
10
|
+
|
|
11
|
+
setTimeout(async () => {
|
|
12
|
+
await shutDown()
|
|
13
|
+
setTimeout(async () => {
|
|
14
|
+
await mockServer(port)
|
|
15
|
+
setTimeout(async () => {
|
|
16
|
+
const msg = {echo: true, msg: 'hello!'}
|
|
17
|
+
const response = await ws.send(msg)
|
|
18
|
+
if(equals(response, msg)) ff(); else rj('not equals.')
|
|
19
|
+
}, 1500)
|
|
20
|
+
}, 1100)
|
|
21
|
+
}, 500)
|
|
22
|
+
})
|
|
23
|
+
))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNew, timeout } from '../utils'
|
|
2
|
+
import mockServer from '../mock/server'
|
|
3
|
+
import { test } from '../suite'
|
|
4
|
+
|
|
5
|
+
/** Socket property check. */
|
|
6
|
+
test('sockets', timeout(1e4, () => new Promise<void>(async (ff, rj) => {
|
|
7
|
+
const {port} = await mockServer()
|
|
8
|
+
const ws = createNew({}, port)
|
|
9
|
+
|
|
10
|
+
await ws.ready()
|
|
11
|
+
|
|
12
|
+
if(ws.socket && !isNaN(ws.socket.readyState)) ff(); else rj()
|
|
13
|
+
})))
|
package/test/suite.ts
ADDED