@eleven-am/pondsocket 0.1.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/.eslintrc.js +28 -0
- package/.idea/modules.xml +8 -0
- package/.idea/pondsocket.iml +12 -0
- package/LICENSE +674 -0
- package/base.d.ts +1 -0
- package/base.js +17 -0
- package/client.d.ts +1 -0
- package/client.js +17 -0
- package/index.d.ts +1 -0
- package/index.js +17 -0
- package/jest.config.js +11 -0
- package/package.json +48 -0
- package/pondBase/baseClass.d.ts +37 -0
- package/pondBase/baseClass.js +111 -0
- package/pondBase/baseClass.test.js +73 -0
- package/pondBase/enums.d.ts +9 -0
- package/pondBase/enums.js +14 -0
- package/pondBase/index.d.ts +6 -0
- package/pondBase/index.js +22 -0
- package/pondBase/pondBase.d.ts +41 -0
- package/pondBase/pondBase.js +60 -0
- package/pondBase/pondBase.test.js +101 -0
- package/pondBase/pubSub.d.ts +73 -0
- package/pondBase/pubSub.js +138 -0
- package/pondBase/pubSub.test.js +309 -0
- package/pondBase/simpleBase.d.ts +131 -0
- package/pondBase/simpleBase.js +211 -0
- package/pondBase/simpleBase.test.js +153 -0
- package/pondBase/types.d.ts +2 -0
- package/pondBase/types.js +2 -0
- package/pondClient/channel.d.ts +66 -0
- package/pondClient/channel.js +152 -0
- package/pondClient/index.d.ts +2 -0
- package/pondClient/index.js +18 -0
- package/pondClient/socket.d.ts +42 -0
- package/pondClient/socket.js +116 -0
- package/pondSocket/channel.d.ts +134 -0
- package/pondSocket/channel.js +287 -0
- package/pondSocket/channel.test.js +377 -0
- package/pondSocket/channelMiddleWare.d.ts +26 -0
- package/pondSocket/channelMiddleWare.js +36 -0
- package/pondSocket/endpoint.d.ts +90 -0
- package/pondSocket/endpoint.js +323 -0
- package/pondSocket/endpoint.test.js +513 -0
- package/pondSocket/enums.d.ts +19 -0
- package/pondSocket/enums.js +25 -0
- package/pondSocket/index.d.ts +7 -0
- package/pondSocket/index.js +23 -0
- package/pondSocket/pondChannel.d.ts +79 -0
- package/pondSocket/pondChannel.js +219 -0
- package/pondSocket/pondChannel.test.js +430 -0
- package/pondSocket/pondResponse.d.ts +25 -0
- package/pondSocket/pondResponse.js +120 -0
- package/pondSocket/pondSocket.d.ts +47 -0
- package/pondSocket/pondSocket.js +94 -0
- package/pondSocket/server.test.js +136 -0
- package/pondSocket/socketMiddleWare.d.ts +6 -0
- package/pondSocket/socketMiddleWare.js +32 -0
- package/pondSocket/types.d.ts +74 -0
- package/pondSocket/types.js +2 -0
- package/socket.d.ts +1 -0
- package/socket.js +17 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +90 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const endpoint_1 = require("./endpoint");
|
|
7
|
+
const pondSocket_1 = require("./pondSocket");
|
|
8
|
+
const superwstest_1 = __importDefault(require("superwstest"));
|
|
9
|
+
const enums_1 = require("./enums");
|
|
10
|
+
const createPondSocket = () => {
|
|
11
|
+
const mock = jest.fn();
|
|
12
|
+
const socket = new pondSocket_1.PondSocket();
|
|
13
|
+
const server = socket.listen(3001, mock);
|
|
14
|
+
return { socket, server, mock };
|
|
15
|
+
};
|
|
16
|
+
describe('endpoint', () => {
|
|
17
|
+
it('should be defined', () => {
|
|
18
|
+
expect(endpoint_1.Endpoint).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
it('should be instantiable', () => {
|
|
21
|
+
const socketServer = {};
|
|
22
|
+
const handler = jest.fn();
|
|
23
|
+
expect(new endpoint_1.Endpoint(socketServer, handler)).toBeInstanceOf(endpoint_1.Endpoint);
|
|
24
|
+
});
|
|
25
|
+
// Functionality tests
|
|
26
|
+
it('should be able to close a socket', async () => {
|
|
27
|
+
const { socket, server } = createPondSocket();
|
|
28
|
+
expect(server).toBeDefined();
|
|
29
|
+
const endpoint = socket.createEndpoint('/api/:path', (req, res) => {
|
|
30
|
+
expect(req.params.path).toBe('socket');
|
|
31
|
+
res.accept();
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
endpoint.closeConnection(req.clientId);
|
|
34
|
+
}, 100);
|
|
35
|
+
});
|
|
36
|
+
await (0, superwstest_1.default)(server)
|
|
37
|
+
.ws('/api/socket')
|
|
38
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
39
|
+
.wait(200)
|
|
40
|
+
.expectClosed();
|
|
41
|
+
server.close();
|
|
42
|
+
});
|
|
43
|
+
it('should be able to list connections', async () => {
|
|
44
|
+
const { socket, server } = createPondSocket();
|
|
45
|
+
let connectionsCount = 0;
|
|
46
|
+
expect(server).toBeDefined();
|
|
47
|
+
const endpoint = socket.createEndpoint('/api/:path', (req, res) => {
|
|
48
|
+
expect(req.params.path).toBe('socket');
|
|
49
|
+
connectionsCount = endpoint.listConnections().length;
|
|
50
|
+
res.accept();
|
|
51
|
+
});
|
|
52
|
+
await (0, superwstest_1.default)(server)
|
|
53
|
+
.ws('/api/socket')
|
|
54
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101));
|
|
55
|
+
await (0, superwstest_1.default)(server)
|
|
56
|
+
.ws('/api/socket')
|
|
57
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101));
|
|
58
|
+
server.close(); // Close the server to stop the connection from being kept alive
|
|
59
|
+
expect(connectionsCount).toBe(1);
|
|
60
|
+
expect(endpoint.listConnections().length).toBe(2); // The connections are still in the list
|
|
61
|
+
});
|
|
62
|
+
it('should be capable of sending messages to all clients', async () => {
|
|
63
|
+
const { socket, server } = createPondSocket();
|
|
64
|
+
expect(server).toBeDefined();
|
|
65
|
+
let users = 0;
|
|
66
|
+
const endpoint = socket.createEndpoint('/api/:room', (req, res) => {
|
|
67
|
+
users++;
|
|
68
|
+
res.send('Hello', { room: req.params.room });
|
|
69
|
+
if (users > 0)
|
|
70
|
+
endpoint.broadcast('TEST', { message: 'Hello everyone' });
|
|
71
|
+
});
|
|
72
|
+
await (0, superwstest_1.default)(server)
|
|
73
|
+
.ws('/api/socket')
|
|
74
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
75
|
+
.expectJson({
|
|
76
|
+
action: 'MESSAGE', event: 'Hello', channelName: 'SERVER', payload: {
|
|
77
|
+
room: 'socket'
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.expectJson({
|
|
81
|
+
action: 'MESSAGE', event: 'TEST', channelName: `ENDPOINT`, payload: {
|
|
82
|
+
message: 'Hello everyone'
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
await (0, superwstest_1.default)(server)
|
|
86
|
+
.ws('/api/secondSocket')
|
|
87
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
88
|
+
.expectJson({
|
|
89
|
+
action: 'MESSAGE', event: 'Hello', channelName: 'SERVER', payload: {
|
|
90
|
+
room: 'secondSocket'
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
.expectJson({
|
|
94
|
+
action: 'MESSAGE', event: 'TEST', channelName: 'ENDPOINT', payload: {
|
|
95
|
+
message: 'Hello everyone'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
server.close();
|
|
99
|
+
});
|
|
100
|
+
it('should be able to accept connections on this handler', async () => {
|
|
101
|
+
const { socket, server } = createPondSocket();
|
|
102
|
+
expect(server).toBeDefined();
|
|
103
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
104
|
+
res.accept();
|
|
105
|
+
});
|
|
106
|
+
endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
107
|
+
expect(req.params.room).toBeDefined();
|
|
108
|
+
res.accept({
|
|
109
|
+
presence: {
|
|
110
|
+
status: 'online',
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
endpoint.createChannel('/socket/:room', (req, res, _) => {
|
|
115
|
+
expect(req.params.room).toBeDefined();
|
|
116
|
+
res.accept({
|
|
117
|
+
presence: {
|
|
118
|
+
status: 'online socket',
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
const message = {
|
|
123
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
124
|
+
};
|
|
125
|
+
await (0, superwstest_1.default)(server)
|
|
126
|
+
.ws('/api/socket')
|
|
127
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
128
|
+
.sendJson(message)
|
|
129
|
+
.expectJson(); // receives a presence message, this can not be matched because the payload is dynamic
|
|
130
|
+
await (0, superwstest_1.default)(server)
|
|
131
|
+
.ws('/api/socket')
|
|
132
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
133
|
+
.sendJson({
|
|
134
|
+
...message, channelName: '/socket/socket'
|
|
135
|
+
})
|
|
136
|
+
.expectJson(); // receives a presence message, this can not be matched because the payload is dynamic
|
|
137
|
+
expect([...endpoint['_channels'].generator()]).toHaveLength(2);
|
|
138
|
+
server.close();
|
|
139
|
+
});
|
|
140
|
+
it('should refuse connections if there are no handlers', async () => {
|
|
141
|
+
const { socket, server } = createPondSocket();
|
|
142
|
+
expect(server).toBeDefined();
|
|
143
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
144
|
+
res.accept();
|
|
145
|
+
});
|
|
146
|
+
endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
147
|
+
expect(req.params.room).toBeDefined();
|
|
148
|
+
res.accept({
|
|
149
|
+
presence: {
|
|
150
|
+
status: 'online',
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
const message = {
|
|
155
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
156
|
+
};
|
|
157
|
+
await (0, superwstest_1.default)(server)
|
|
158
|
+
.ws('/api/socket')
|
|
159
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
160
|
+
.sendJson(message)
|
|
161
|
+
.expectJson(); // receives a presence message, this can not be matched because the payload is dynamic
|
|
162
|
+
await (0, superwstest_1.default)(server)
|
|
163
|
+
.ws('/api/socket')
|
|
164
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
165
|
+
.sendJson({
|
|
166
|
+
...message, channelName: '/socket/socket' // This channel handler does not exist
|
|
167
|
+
})
|
|
168
|
+
.expectJson(); // receives a presence message, this can not be matched because the payload is dynamic
|
|
169
|
+
expect([...endpoint['_channels'].generator()]).toHaveLength(1);
|
|
170
|
+
server.close();
|
|
171
|
+
});
|
|
172
|
+
it('should send an error when we send an incomplete message', async () => {
|
|
173
|
+
const { socket, server } = createPondSocket();
|
|
174
|
+
expect(server).toBeDefined();
|
|
175
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
176
|
+
res.accept();
|
|
177
|
+
});
|
|
178
|
+
endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
179
|
+
expect(req.params.room).toBeDefined();
|
|
180
|
+
res.accept({
|
|
181
|
+
presence: {
|
|
182
|
+
status: 'online',
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
const message = {
|
|
187
|
+
action: enums_1.ClientActions.LEAVE_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
188
|
+
};
|
|
189
|
+
await (0, superwstest_1.default)(server)
|
|
190
|
+
.ws('/api/socket')
|
|
191
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
192
|
+
.sendJson(message)
|
|
193
|
+
.expectJson({
|
|
194
|
+
action: enums_1.ServerActions.ERROR,
|
|
195
|
+
event: "error",
|
|
196
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
197
|
+
payload: {
|
|
198
|
+
message: "Channel /test/socket does not exist"
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
await (0, superwstest_1.default)(server)
|
|
202
|
+
.ws('/api/socket')
|
|
203
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
204
|
+
.sendJson({
|
|
205
|
+
...message, action: null
|
|
206
|
+
})
|
|
207
|
+
.expectJson({
|
|
208
|
+
action: enums_1.ServerActions.ERROR,
|
|
209
|
+
event: "error",
|
|
210
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
211
|
+
payload: {
|
|
212
|
+
message: "No action provided",
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
await (0, superwstest_1.default)(server)
|
|
216
|
+
.ws('/api/socket')
|
|
217
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
218
|
+
.sendJson({
|
|
219
|
+
...message, action: enums_1.ClientActions.BROADCAST, channelName: null
|
|
220
|
+
})
|
|
221
|
+
.expectJson({
|
|
222
|
+
action: enums_1.ServerActions.ERROR,
|
|
223
|
+
event: "error",
|
|
224
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
225
|
+
payload: {
|
|
226
|
+
message: "No channel name provided",
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
await (0, superwstest_1.default)(server)
|
|
230
|
+
.ws('/api/socket')
|
|
231
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
232
|
+
.sendJson({
|
|
233
|
+
...message, action: enums_1.ClientActions.BROADCAST_FROM, payload: null
|
|
234
|
+
})
|
|
235
|
+
.expectJson({
|
|
236
|
+
action: enums_1.ServerActions.ERROR,
|
|
237
|
+
event: "error",
|
|
238
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
239
|
+
payload: {
|
|
240
|
+
message: "No payload provided",
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
// send incorrect Json message
|
|
244
|
+
await (0, superwstest_1.default)(server)
|
|
245
|
+
.ws('/api/socket')
|
|
246
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
247
|
+
.send('"action": "JOIN_CHANNEL", "channelName": "/test/socket", "event": "TEST", "payload": {}}')
|
|
248
|
+
.expectJson({
|
|
249
|
+
action: enums_1.ServerActions.ERROR,
|
|
250
|
+
event: "error",
|
|
251
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
252
|
+
payload: {
|
|
253
|
+
message: "Invalid JSON",
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
expect([...endpoint['_channels'].generator()]).toHaveLength(1);
|
|
257
|
+
server.close();
|
|
258
|
+
});
|
|
259
|
+
it('should send an error when the channel exists but other things happen', async () => {
|
|
260
|
+
const { socket, server } = createPondSocket();
|
|
261
|
+
expect(server).toBeDefined();
|
|
262
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
263
|
+
res.accept();
|
|
264
|
+
});
|
|
265
|
+
const channel = endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
266
|
+
expect(req.params.room).toBeDefined();
|
|
267
|
+
res.accept();
|
|
268
|
+
});
|
|
269
|
+
channel.on('/test/:room', (req, res, _) => {
|
|
270
|
+
if (req.params.room === 'TEST') {
|
|
271
|
+
res.accept();
|
|
272
|
+
}
|
|
273
|
+
else if (req.params.room === 'TEST2') {
|
|
274
|
+
res.reject();
|
|
275
|
+
}
|
|
276
|
+
else if (req.params.room === 'TEST3') {
|
|
277
|
+
res.reject('choke on my balls');
|
|
278
|
+
}
|
|
279
|
+
else
|
|
280
|
+
res.reject('TEST');
|
|
281
|
+
});
|
|
282
|
+
const message = {
|
|
283
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
284
|
+
};
|
|
285
|
+
await (0, superwstest_1.default)(server)
|
|
286
|
+
.ws('/api/socket')
|
|
287
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
288
|
+
.sendJson(message)
|
|
289
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
290
|
+
.sendJson({
|
|
291
|
+
...message, event: '/test/TEST2', action: enums_1.ClientActions.BROADCAST,
|
|
292
|
+
})
|
|
293
|
+
.expectJson({
|
|
294
|
+
action: "ERROR", event: "error", channelName: "/test/socket", payload: {
|
|
295
|
+
message: "Message rejected", code: 403
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
.sendJson({
|
|
299
|
+
...message, channelName: "/test/socket", action: enums_1.ClientActions.BROADCAST,
|
|
300
|
+
})
|
|
301
|
+
.expectJson({
|
|
302
|
+
action: enums_1.ServerActions.MESSAGE, payload: {}, event: "TEST", channelName: "/test/socket"
|
|
303
|
+
})
|
|
304
|
+
.sendJson({
|
|
305
|
+
...message, action: enums_1.ClientActions.SEND_MESSAGE_TO_USER,
|
|
306
|
+
})
|
|
307
|
+
.expectJson({
|
|
308
|
+
action: enums_1.ServerActions.ERROR,
|
|
309
|
+
event: "error",
|
|
310
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
311
|
+
payload: {
|
|
312
|
+
message: "Error while executing event 'TEST' on channel '/test/socket': No addresses provided"
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
expect(endpoint.listChannels()).toHaveLength(1);
|
|
316
|
+
server.close();
|
|
317
|
+
});
|
|
318
|
+
it('should be capable of sending messages to a specific user', async () => {
|
|
319
|
+
const { socket, server } = createPondSocket();
|
|
320
|
+
expect(server).toBeDefined();
|
|
321
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
322
|
+
res.accept();
|
|
323
|
+
});
|
|
324
|
+
const channel = endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
325
|
+
expect(req.params.room).toBeDefined();
|
|
326
|
+
res.accept();
|
|
327
|
+
});
|
|
328
|
+
channel.on('/test/:room', (req, res, _) => {
|
|
329
|
+
if (req.params.room === 'TEST') {
|
|
330
|
+
res.accept();
|
|
331
|
+
}
|
|
332
|
+
else if (req.params.room === 'TEST2') {
|
|
333
|
+
res.reject();
|
|
334
|
+
}
|
|
335
|
+
else if (req.params.room === 'TEST3') {
|
|
336
|
+
res.reject('choke on my balls');
|
|
337
|
+
}
|
|
338
|
+
else
|
|
339
|
+
res.reject('TEST');
|
|
340
|
+
});
|
|
341
|
+
const message = {
|
|
342
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
343
|
+
};
|
|
344
|
+
await (0, superwstest_1.default)(server)
|
|
345
|
+
.ws('/api/socket')
|
|
346
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
347
|
+
.sendJson(message)
|
|
348
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
349
|
+
.sendJson({
|
|
350
|
+
...message, action: enums_1.ClientActions.BROADCAST_FROM, payload: {
|
|
351
|
+
message: {
|
|
352
|
+
action: enums_1.ServerActions.MESSAGE, payload: {}, event: "TEST", channelName: "/test/socket"
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
expect(endpoint.listChannels()).toHaveLength(1);
|
|
357
|
+
server.close();
|
|
358
|
+
});
|
|
359
|
+
it('should be able to update user presence on user demand', async () => {
|
|
360
|
+
const { socket, server } = createPondSocket();
|
|
361
|
+
expect(server).toBeDefined();
|
|
362
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
363
|
+
res.accept();
|
|
364
|
+
});
|
|
365
|
+
endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
366
|
+
expect(req.params.room).toBeDefined();
|
|
367
|
+
res.accept();
|
|
368
|
+
});
|
|
369
|
+
const message = {
|
|
370
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
371
|
+
};
|
|
372
|
+
await (0, superwstest_1.default)(server)
|
|
373
|
+
.ws('/api/socket')
|
|
374
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
375
|
+
.sendJson(message)
|
|
376
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
377
|
+
.sendJson({
|
|
378
|
+
...message, action: enums_1.ClientActions.UPDATE_PRESENCE, payload: {
|
|
379
|
+
presence: {
|
|
380
|
+
status: 'online'
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
385
|
+
.sendJson({
|
|
386
|
+
...message, action: enums_1.ClientActions.SEND_MESSAGE_TO_USER, addresses: [], payload: {}
|
|
387
|
+
})
|
|
388
|
+
.expectJson({
|
|
389
|
+
action: enums_1.ServerActions.ERROR,
|
|
390
|
+
event: "error",
|
|
391
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
392
|
+
payload: {
|
|
393
|
+
message: "Error while executing event 'TEST' on channel '/test/socket': No addresses provided"
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
.sendJson({
|
|
397
|
+
...message, action: enums_1.ClientActions.SEND_MESSAGE_TO_USER, addresses: ['hello'], payload: {}
|
|
398
|
+
})
|
|
399
|
+
.expectJson({
|
|
400
|
+
action: enums_1.ServerActions.ERROR,
|
|
401
|
+
event: "error",
|
|
402
|
+
channelName: enums_1.PondSenders.ENDPOINT,
|
|
403
|
+
payload: {
|
|
404
|
+
message: "Error while executing event 'TEST' on channel '/test/socket': Client(s) with clientId(s) hello were not found in channel /test/socket"
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
.sendJson({
|
|
408
|
+
...message, action: enums_1.ClientActions.UPDATE_PRESENCE, payload: {
|
|
409
|
+
assigns: {
|
|
410
|
+
status: 'online'
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
})
|
|
414
|
+
.close()
|
|
415
|
+
.expectClosed();
|
|
416
|
+
expect(endpoint.listChannels()).toHaveLength(1); // the channel has not been removed yet
|
|
417
|
+
await (0, superwstest_1.default)(server)
|
|
418
|
+
.ws('/api/newSocket')
|
|
419
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
420
|
+
.sendJson({
|
|
421
|
+
...message, channelName: '/test/socket2',
|
|
422
|
+
})
|
|
423
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
424
|
+
.sendJson({
|
|
425
|
+
...message, action: enums_1.ClientActions.LEAVE_CHANNEL,
|
|
426
|
+
channelName: '/test/socket2',
|
|
427
|
+
})
|
|
428
|
+
.expectJson();
|
|
429
|
+
expect(endpoint.listChannels()).toHaveLength(0); // by now the first channel should have been removed; and since we gracefully closed the connection, the second channel should have been removed as well
|
|
430
|
+
server.close();
|
|
431
|
+
});
|
|
432
|
+
it('should ba able to send messages to a specific user', async () => {
|
|
433
|
+
const { socket, server } = createPondSocket();
|
|
434
|
+
expect(server).toBeDefined();
|
|
435
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
436
|
+
res.accept();
|
|
437
|
+
});
|
|
438
|
+
const channel = endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
439
|
+
expect(req.params.room).toBeDefined();
|
|
440
|
+
res.accept();
|
|
441
|
+
});
|
|
442
|
+
channel.on(':room', (req, res, _) => {
|
|
443
|
+
if (req.params.room === 'TEST') {
|
|
444
|
+
endpoint.send(req.client.clientId, 'Test', { message: 'hello' });
|
|
445
|
+
res.accept();
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
const message = {
|
|
449
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
450
|
+
};
|
|
451
|
+
await (0, superwstest_1.default)(server)
|
|
452
|
+
.ws('/api/socket')
|
|
453
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
454
|
+
.sendJson(message)
|
|
455
|
+
.expectJson() // receives a presence message, this can not be matched because the payload is dynamic
|
|
456
|
+
.sendJson({
|
|
457
|
+
...message, action: enums_1.ClientActions.BROADCAST_FROM, payload: {
|
|
458
|
+
message: {
|
|
459
|
+
action: enums_1.ServerActions.MESSAGE, payload: {}, event: "TEST", channelName: "/test/socket"
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}).expectJson({
|
|
463
|
+
action: enums_1.ServerActions.MESSAGE,
|
|
464
|
+
event: 'Test', channelName: enums_1.PondSenders.ENDPOINT,
|
|
465
|
+
payload: {
|
|
466
|
+
message: 'hello'
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
expect(endpoint.listChannels()).toHaveLength(1);
|
|
470
|
+
server.close();
|
|
471
|
+
});
|
|
472
|
+
it('should be able ot manage error from the client side', async () => {
|
|
473
|
+
const { socket, server } = createPondSocket();
|
|
474
|
+
expect(server).toBeDefined();
|
|
475
|
+
const endpoint = socket.createEndpoint('/api/:room', (_, res) => {
|
|
476
|
+
res.accept();
|
|
477
|
+
});
|
|
478
|
+
const channel = endpoint.createChannel('/test/:room', (req, res, _) => {
|
|
479
|
+
expect(req.params.room).toBeDefined();
|
|
480
|
+
res.accept();
|
|
481
|
+
});
|
|
482
|
+
channel.on(':room', (req, res) => {
|
|
483
|
+
if (req.params.room === 'TEST') {
|
|
484
|
+
res.reject('TEST');
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
const message = {
|
|
488
|
+
action: enums_1.ClientActions.JOIN_CHANNEL, channelName: '/test/socket', event: 'TEST', payload: {}
|
|
489
|
+
};
|
|
490
|
+
const functionToTest = (ws) => {
|
|
491
|
+
try {
|
|
492
|
+
ws.emit('error', {});
|
|
493
|
+
}
|
|
494
|
+
catch (e) {
|
|
495
|
+
console.log(e);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
try {
|
|
499
|
+
await (0, superwstest_1.default)(server)
|
|
500
|
+
.ws('/api/socket')
|
|
501
|
+
.expectUpgrade(res => expect(res.statusCode).toBe(101))
|
|
502
|
+
.sendJson(message)
|
|
503
|
+
.exec(functionToTest)
|
|
504
|
+
.expectClosed();
|
|
505
|
+
}
|
|
506
|
+
catch (e) {
|
|
507
|
+
console.log(e);
|
|
508
|
+
}
|
|
509
|
+
expect(endpoint.listChannels()).toHaveLength(0); // the socket should have been removed
|
|
510
|
+
expect(endpoint['_findChannel']('/test/socket')).toBeUndefined();
|
|
511
|
+
server.close();
|
|
512
|
+
});
|
|
513
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum ServerActions {
|
|
2
|
+
ERROR = "ERROR",
|
|
3
|
+
MESSAGE = "MESSAGE",
|
|
4
|
+
PRESENCE = "PRESENCE",
|
|
5
|
+
CLOSE = "CLOSE"
|
|
6
|
+
}
|
|
7
|
+
export declare enum ClientActions {
|
|
8
|
+
JOIN_CHANNEL = "JOIN_CHANNEL",
|
|
9
|
+
LEAVE_CHANNEL = "LEAVE_CHANNEL",
|
|
10
|
+
UPDATE_PRESENCE = "UPDATE_PRESENCE",
|
|
11
|
+
BROADCAST_FROM = "BROADCAST_FROM",
|
|
12
|
+
BROADCAST = "BROADCAST",
|
|
13
|
+
SEND_MESSAGE_TO_USER = "SEND_MESSAGE_TO_USER"
|
|
14
|
+
}
|
|
15
|
+
export declare enum PondSenders {
|
|
16
|
+
SERVER = "SERVER",
|
|
17
|
+
ENDPOINT = "ENDPOINT",
|
|
18
|
+
POND_CHANNEL = "POND_CHANNEL"
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PondSenders = exports.ClientActions = exports.ServerActions = void 0;
|
|
4
|
+
var ServerActions;
|
|
5
|
+
(function (ServerActions) {
|
|
6
|
+
ServerActions["ERROR"] = "ERROR";
|
|
7
|
+
ServerActions["MESSAGE"] = "MESSAGE";
|
|
8
|
+
ServerActions["PRESENCE"] = "PRESENCE";
|
|
9
|
+
ServerActions["CLOSE"] = "CLOSE";
|
|
10
|
+
})(ServerActions = exports.ServerActions || (exports.ServerActions = {}));
|
|
11
|
+
var ClientActions;
|
|
12
|
+
(function (ClientActions) {
|
|
13
|
+
ClientActions["JOIN_CHANNEL"] = "JOIN_CHANNEL";
|
|
14
|
+
ClientActions["LEAVE_CHANNEL"] = "LEAVE_CHANNEL";
|
|
15
|
+
ClientActions["UPDATE_PRESENCE"] = "UPDATE_PRESENCE";
|
|
16
|
+
ClientActions["BROADCAST_FROM"] = "BROADCAST_FROM";
|
|
17
|
+
ClientActions["BROADCAST"] = "BROADCAST";
|
|
18
|
+
ClientActions["SEND_MESSAGE_TO_USER"] = "SEND_MESSAGE_TO_USER";
|
|
19
|
+
})(ClientActions = exports.ClientActions || (exports.ClientActions = {}));
|
|
20
|
+
var PondSenders;
|
|
21
|
+
(function (PondSenders) {
|
|
22
|
+
PondSenders["SERVER"] = "SERVER";
|
|
23
|
+
PondSenders["ENDPOINT"] = "ENDPOINT";
|
|
24
|
+
PondSenders["POND_CHANNEL"] = "POND_CHANNEL";
|
|
25
|
+
})(PondSenders = exports.PondSenders || (exports.PondSenders = {}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./channel"), exports);
|
|
18
|
+
__exportStar(require("./endpoint"), exports);
|
|
19
|
+
__exportStar(require("./pondChannel"), exports);
|
|
20
|
+
__exportStar(require("./pondSocket"), exports);
|
|
21
|
+
__exportStar(require("./types"), exports);
|
|
22
|
+
__exportStar(require("./pondResponse"), exports);
|
|
23
|
+
__exportStar(require("./enums"), exports);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {BaseClass, default_t, PondPath} from "../pondBase";
|
|
2
|
+
import {Channel, ChannelInfo} from "./channel";
|
|
3
|
+
import {IncomingChannelMessage, IncomingJoinMessage, PondMessage, PondResponseAssigns, SocketCache} from "./types";
|
|
4
|
+
import {PondResponse} from "./pondResponse";
|
|
5
|
+
|
|
6
|
+
export declare type PondChannelHandler = (req: IncomingJoinMessage, res: PondResponse, channel: Channel) => void;
|
|
7
|
+
|
|
8
|
+
export declare class PondChannel extends BaseClass {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @desc Gets a list of all the channels in the endpoint.
|
|
12
|
+
*/
|
|
13
|
+
get info(): ChannelInfo[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @desc A listener for a channel event
|
|
17
|
+
* @param event - The event to listen for, can be a regex
|
|
18
|
+
* @param callback - The callback to call when the event is received
|
|
19
|
+
*/
|
|
20
|
+
on(event: PondPath, callback: (req: IncomingChannelMessage, res: PondResponse, channel: Channel) => void): void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @desc Add new user to channel
|
|
24
|
+
* @param user - The user to add to the channel
|
|
25
|
+
* @param channelName - The name of the channel
|
|
26
|
+
* @param joinParams - The params to join the channel with
|
|
27
|
+
*/
|
|
28
|
+
addUser(user: SocketCache, channelName: string, joinParams: default_t): void;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @desc Sends a message to a channel in the endpoint.
|
|
32
|
+
* @param channelName - The name of the channel to send the message to.
|
|
33
|
+
* @param event - The event to send the message with.
|
|
34
|
+
* @param message - The message to send.
|
|
35
|
+
*/
|
|
36
|
+
broadcastToChannel(channelName: string, event: string, message: PondMessage): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @desc Closes a client connection to a channel in the endpoint.
|
|
40
|
+
* @param channelName - The name of the channel to close the connection to.
|
|
41
|
+
* @param clientId - The id of the client to close the connection to.
|
|
42
|
+
*/
|
|
43
|
+
closeFromChannel(channelName: string, clientId: string | string[]): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @desc Modify the presence of a client in a channel on the endpoint.
|
|
47
|
+
* @param channelName - The name of the channel to modify the presence of.
|
|
48
|
+
* @param clientId - The id of the client to modify the presence of.
|
|
49
|
+
* @param assigns - The assigns to modify the presence with.
|
|
50
|
+
*/
|
|
51
|
+
modifyPresence(channelName: string, clientId: string, assigns: PondResponseAssigns): void;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @desc Gets the information of the channel
|
|
55
|
+
* @param channelName - The name of the channel to get the information of.
|
|
56
|
+
*/
|
|
57
|
+
getChannelInfo(channelName: string): ChannelInfo;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @desc Sends a message to the channel
|
|
61
|
+
* @param channelName - The name of the channel to send the message to.
|
|
62
|
+
* @param clientId - The clientId to send the message to, can be an array of clientIds
|
|
63
|
+
* @param event - The event to send the message to
|
|
64
|
+
* @param message - The message to send
|
|
65
|
+
*/
|
|
66
|
+
send(channelName: string, clientId: string | string[], event: string, message: default_t): void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @desc Searches for a channel in the endpoint.
|
|
70
|
+
* @param channelName - The name of the channel to search for.
|
|
71
|
+
*/
|
|
72
|
+
getChannel(channelName: string): Channel | null;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @desc removes a user from all channels
|
|
76
|
+
* @param clientId - The id of the client to remove
|
|
77
|
+
*/
|
|
78
|
+
removeUser(clientId: string): void;
|
|
79
|
+
}
|