@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,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createChannel = void 0;
|
|
4
|
+
const channel_1 = require("./channel");
|
|
5
|
+
const channelMiddleWare_1 = require("./channelMiddleWare");
|
|
6
|
+
const pondBase_1 = require("../pondBase");
|
|
7
|
+
const enums_1 = require("./enums");
|
|
8
|
+
const createChannel = (name) => {
|
|
9
|
+
const user = {
|
|
10
|
+
client: {
|
|
11
|
+
clientId: 'test',
|
|
12
|
+
socket: {
|
|
13
|
+
send: jest.fn(),
|
|
14
|
+
on: jest.fn(),
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
presence: {
|
|
18
|
+
status: 'online',
|
|
19
|
+
lastSeenDate: new Date(),
|
|
20
|
+
},
|
|
21
|
+
assigns: {},
|
|
22
|
+
channelData: {}
|
|
23
|
+
};
|
|
24
|
+
const removeDoc = jest.fn();
|
|
25
|
+
const middleware = new channelMiddleWare_1.ChannelMiddleware();
|
|
26
|
+
const channel = new channel_1.Channel(name, middleware, removeDoc);
|
|
27
|
+
return { channel, removeDoc, user };
|
|
28
|
+
};
|
|
29
|
+
exports.createChannel = createChannel;
|
|
30
|
+
describe('Channel', () => {
|
|
31
|
+
it('should exist', () => {
|
|
32
|
+
expect(channel_1.Channel).toBeDefined();
|
|
33
|
+
});
|
|
34
|
+
it('should be a class', () => {
|
|
35
|
+
expect(channel_1.Channel).toBeInstanceOf(Function);
|
|
36
|
+
});
|
|
37
|
+
// Functionality tests
|
|
38
|
+
it('should add a user to the channel', () => {
|
|
39
|
+
const lastSeenDate = new Date();
|
|
40
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
41
|
+
const user = {
|
|
42
|
+
client: {
|
|
43
|
+
clientId: 'test',
|
|
44
|
+
socket: {
|
|
45
|
+
send: jest.fn(),
|
|
46
|
+
on: jest.fn(),
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
presence: {
|
|
50
|
+
status: 'online',
|
|
51
|
+
lastSeen: lastSeenDate
|
|
52
|
+
},
|
|
53
|
+
assigns: {},
|
|
54
|
+
channelData: {}
|
|
55
|
+
};
|
|
56
|
+
channel.addUser(user);
|
|
57
|
+
expect(channel.getUserInfo('test')).toEqual({
|
|
58
|
+
presence: {
|
|
59
|
+
id: 'test',
|
|
60
|
+
status: 'online',
|
|
61
|
+
lastSeen: lastSeenDate
|
|
62
|
+
},
|
|
63
|
+
assigns: {},
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
it('should remove a user from the channel', () => {
|
|
67
|
+
const lastSeenDate = new Date();
|
|
68
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
69
|
+
user.presence.lastSeenDate = lastSeenDate;
|
|
70
|
+
channel.addUser(user);
|
|
71
|
+
channel.removeUser('test');
|
|
72
|
+
expect(channel.getUserInfo('test')).toBeNull();
|
|
73
|
+
});
|
|
74
|
+
it('should update a user in the channel', () => {
|
|
75
|
+
const lastSeenDate = new Date();
|
|
76
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
77
|
+
user.presence.lastSeenDate = lastSeenDate;
|
|
78
|
+
channel.addUser(user);
|
|
79
|
+
expect(channel.getUserInfo('test')).toEqual({
|
|
80
|
+
presence: {
|
|
81
|
+
id: 'test',
|
|
82
|
+
status: 'online',
|
|
83
|
+
lastSeenDate: lastSeenDate
|
|
84
|
+
},
|
|
85
|
+
assigns: {},
|
|
86
|
+
});
|
|
87
|
+
// replace both presence and assigns
|
|
88
|
+
channel.updateUser('test', {
|
|
89
|
+
status: 'offline'
|
|
90
|
+
}, {
|
|
91
|
+
test: 'test'
|
|
92
|
+
});
|
|
93
|
+
expect(channel.getUserInfo('test')).toEqual({
|
|
94
|
+
presence: {
|
|
95
|
+
id: 'test',
|
|
96
|
+
status: 'offline',
|
|
97
|
+
lastSeenDate: lastSeenDate
|
|
98
|
+
},
|
|
99
|
+
assigns: {
|
|
100
|
+
test: 'test'
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
// replace only presence
|
|
104
|
+
channel.updateUser('test', {
|
|
105
|
+
status: 'online'
|
|
106
|
+
}, {});
|
|
107
|
+
expect(channel.getUserInfo('test')).toEqual({
|
|
108
|
+
presence: {
|
|
109
|
+
id: 'test',
|
|
110
|
+
status: 'online',
|
|
111
|
+
lastSeenDate: lastSeenDate
|
|
112
|
+
},
|
|
113
|
+
assigns: {
|
|
114
|
+
test: 'test'
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
// replace only assigns
|
|
118
|
+
channel.updateUser('test', {}, {
|
|
119
|
+
test: 'test2'
|
|
120
|
+
});
|
|
121
|
+
expect(channel.getUserInfo('test')).toEqual({
|
|
122
|
+
presence: {
|
|
123
|
+
id: 'test',
|
|
124
|
+
status: 'online',
|
|
125
|
+
lastSeenDate: lastSeenDate
|
|
126
|
+
},
|
|
127
|
+
assigns: {
|
|
128
|
+
test: 'test2'
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
it('should throw when you add a user with an existing id', () => {
|
|
133
|
+
const lastSeenDate = new Date();
|
|
134
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
135
|
+
user.presence.lastSeenDate = lastSeenDate;
|
|
136
|
+
channel.addUser(user);
|
|
137
|
+
expect(() => channel.addUser(user)).toThrow();
|
|
138
|
+
});
|
|
139
|
+
it('should broadcast a message when a user is added', () => {
|
|
140
|
+
const lastSeenDate = new Date();
|
|
141
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
142
|
+
user.presence.lastSeenDate = lastSeenDate.toString();
|
|
143
|
+
const messages = [];
|
|
144
|
+
channel.onPresenceChange((message) => {
|
|
145
|
+
messages.push(message.event);
|
|
146
|
+
});
|
|
147
|
+
channel.addUser(user);
|
|
148
|
+
channel.removeUser('test'); // this broadcast will not be received by the subscription as it unsubscribes after the first message
|
|
149
|
+
expect(channel.getUserInfo('test')).toBeNull();
|
|
150
|
+
expect(messages).toHaveLength(2);
|
|
151
|
+
expect(messages).toEqual([pondBase_1.PondBaseActions.ADD_TO_POND, pondBase_1.PondBaseActions.REMOVE_FROM_POND]);
|
|
152
|
+
});
|
|
153
|
+
it('should set and get the channel data', () => {
|
|
154
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
155
|
+
channel.data = {
|
|
156
|
+
test: 'test'
|
|
157
|
+
};
|
|
158
|
+
expect(channel.data).toStrictEqual({
|
|
159
|
+
test: 'test'
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
it('should get channel info', () => {
|
|
163
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
164
|
+
channel.addUser({
|
|
165
|
+
client: {
|
|
166
|
+
clientId: 'test1',
|
|
167
|
+
},
|
|
168
|
+
presence: { status: 'online' },
|
|
169
|
+
assigns: {},
|
|
170
|
+
channelData: { name: 'test1' }
|
|
171
|
+
});
|
|
172
|
+
expect(channel.info).toStrictEqual({
|
|
173
|
+
name: 'test',
|
|
174
|
+
presence: [
|
|
175
|
+
{
|
|
176
|
+
id: 'test1',
|
|
177
|
+
status: 'online',
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
assigns: [{}],
|
|
181
|
+
channelData: {
|
|
182
|
+
name: 'test1'
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
channel.data = {
|
|
186
|
+
test: 'test'
|
|
187
|
+
};
|
|
188
|
+
expect(channel.info).toStrictEqual({
|
|
189
|
+
name: 'test',
|
|
190
|
+
presence: [
|
|
191
|
+
{
|
|
192
|
+
id: 'test1',
|
|
193
|
+
status: 'online',
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
assigns: [{}],
|
|
197
|
+
channelData: {
|
|
198
|
+
name: 'test1',
|
|
199
|
+
test: 'test'
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
it('should get the presence of all the users in the class', () => {
|
|
204
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
205
|
+
expect(channel.presence).toStrictEqual([]);
|
|
206
|
+
channel.addUser({
|
|
207
|
+
client: {
|
|
208
|
+
clientId: 'test1',
|
|
209
|
+
},
|
|
210
|
+
presence: { status: 'online' },
|
|
211
|
+
assigns: {},
|
|
212
|
+
channelData: { name: 'test1' }
|
|
213
|
+
});
|
|
214
|
+
expect(channel.presence).toStrictEqual([
|
|
215
|
+
{
|
|
216
|
+
id: 'test1',
|
|
217
|
+
status: 'online',
|
|
218
|
+
}
|
|
219
|
+
]);
|
|
220
|
+
});
|
|
221
|
+
it('should be possible to remove multiple users at once', () => {
|
|
222
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
223
|
+
const user1 = { ...user };
|
|
224
|
+
user1.client.clientId = 'test1';
|
|
225
|
+
channel.addUser(user1);
|
|
226
|
+
const user2 = { ...user };
|
|
227
|
+
user2.client.clientId = 'test2';
|
|
228
|
+
channel.addUser(user2);
|
|
229
|
+
expect(channel.info.presence.length).toBe(2);
|
|
230
|
+
channel.removeUser(['test1', 'test2']);
|
|
231
|
+
expect(channel.info.presence.length).toBe(0);
|
|
232
|
+
});
|
|
233
|
+
it('should broadcast a message to all users in the channel except the sender', () => {
|
|
234
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
235
|
+
let addresses = [];
|
|
236
|
+
// mock of a socket connection subscribed to the channel
|
|
237
|
+
// in a real world scenario, addresses.push = socket.send
|
|
238
|
+
// _message is the message to be JSON.stringified and sent to the socket
|
|
239
|
+
const sub = channel.subscribeToMessages('test1', (_message) => {
|
|
240
|
+
addresses.push('test1');
|
|
241
|
+
});
|
|
242
|
+
const user1 = {
|
|
243
|
+
client: {
|
|
244
|
+
clientId: 'test1',
|
|
245
|
+
},
|
|
246
|
+
presence: {},
|
|
247
|
+
assigns: {},
|
|
248
|
+
channelData: {}
|
|
249
|
+
};
|
|
250
|
+
const user2 = {
|
|
251
|
+
client: {
|
|
252
|
+
clientId: 'test2',
|
|
253
|
+
},
|
|
254
|
+
presence: {},
|
|
255
|
+
assigns: {},
|
|
256
|
+
channelData: {}
|
|
257
|
+
};
|
|
258
|
+
// we add the listener first to make sure that the user gets updates on their own join
|
|
259
|
+
channel.addUser(user1);
|
|
260
|
+
// unlike a normal subscription, this subscription will receive messages when the channel's presence is updated
|
|
261
|
+
// this is useful for the client to know when a user joins / leaves the channel
|
|
262
|
+
// This subscribers cannot block the channel from broadcasting messages
|
|
263
|
+
const sub2 = channel.subscribeToMessages('test2', () => {
|
|
264
|
+
addresses.push('test2');
|
|
265
|
+
});
|
|
266
|
+
channel.addUser(user2);
|
|
267
|
+
expect(channel.info.presence.length).toBe(2);
|
|
268
|
+
expect(addresses.length).toBe(3); // 3 joins messages because the first user receives the join message from the second user as well as their own
|
|
269
|
+
addresses = [];
|
|
270
|
+
channel.broadcastFrom('testEvent', { test: 'test' }, 'test1');
|
|
271
|
+
expect(addresses.length).toBe(1);
|
|
272
|
+
expect(addresses[0]).toBe('test2'); // the message was sent to the second user only: test1
|
|
273
|
+
// when your broadcastFrom is called with a user that is not in the channel,
|
|
274
|
+
// An error will be thrown
|
|
275
|
+
expect(() => {
|
|
276
|
+
channel.broadcastFrom('testEvent', { test: 'test' }, 'test3');
|
|
277
|
+
}).toThrowError(`Client with clientId test3 does not exist in channel test`);
|
|
278
|
+
// when your broadcast is called with a user that is not in the channel,
|
|
279
|
+
// An error will be thrown
|
|
280
|
+
expect(() => {
|
|
281
|
+
channel.broadcast('testEvent', { test: 'test' }, 'test3');
|
|
282
|
+
}).toThrowError(`Client with clientId test3 does not exist in channel test`);
|
|
283
|
+
sub.unsubscribe();
|
|
284
|
+
sub2.unsubscribe();
|
|
285
|
+
});
|
|
286
|
+
it('should provide an onMessage callback', () => {
|
|
287
|
+
const { channel } = (0, exports.createChannel)('test');
|
|
288
|
+
const messages = [];
|
|
289
|
+
channel.onMessage((message) => {
|
|
290
|
+
messages.push(message.event);
|
|
291
|
+
});
|
|
292
|
+
expect(() => channel.broadcast('testEvent', { test: 'test' }, 'test1')).toThrow();
|
|
293
|
+
expect(messages).toHaveLength(0);
|
|
294
|
+
});
|
|
295
|
+
it('should be able to hook up to the onMessage callback', () => {
|
|
296
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
297
|
+
const messages = [];
|
|
298
|
+
channel.addUser(user);
|
|
299
|
+
channel.onMessage((req, res) => {
|
|
300
|
+
expect(req.client.clientId).toEqual(enums_1.PondSenders.POND_CHANNEL);
|
|
301
|
+
if (req.event === 'testEvent') {
|
|
302
|
+
messages.push(req.event);
|
|
303
|
+
res.send('test', { test: 'test' });
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
channel.subscribeToMessages('test1', (message) => {
|
|
307
|
+
messages.push(message.event);
|
|
308
|
+
});
|
|
309
|
+
expect(() => channel.broadcast('testEvent', { test: 'test' })).toThrow(); // the handler always replies to a testEvent message
|
|
310
|
+
// since the sender is the channel itself, the send function throws an error
|
|
311
|
+
expect(messages).toHaveLength(1);
|
|
312
|
+
expect(messages).toEqual(['testEvent']); // this is because the broadcaster is the channel itself
|
|
313
|
+
});
|
|
314
|
+
it('should be able to hook up to the onMessage callback and send a message to the sender', () => {
|
|
315
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
316
|
+
const messages = [];
|
|
317
|
+
channel.addUser(user);
|
|
318
|
+
channel.onMessage((req, res) => {
|
|
319
|
+
expect(req.client.clientId).toEqual('test');
|
|
320
|
+
if (req.event === 'testEvent')
|
|
321
|
+
res.send('test', { test: 'test' });
|
|
322
|
+
});
|
|
323
|
+
channel.subscribeToMessages('test', (message) => {
|
|
324
|
+
messages.push(message.event);
|
|
325
|
+
});
|
|
326
|
+
channel.broadcast('testEvent', { test: 'test' }, 'test');
|
|
327
|
+
expect(messages).toHaveLength(2);
|
|
328
|
+
expect(messages).toEqual(['test', 'testEvent']); // this is because the broadcast is made on behalf of the user
|
|
329
|
+
// the message sent in the handler always gets to the user before the message sent by the broadcaster
|
|
330
|
+
});
|
|
331
|
+
it('should not call further onMessage callbacks if the callback rejects', (done) => {
|
|
332
|
+
const { channel, user } = (0, exports.createChannel)('test');
|
|
333
|
+
let messages = [];
|
|
334
|
+
channel.addUser(user);
|
|
335
|
+
channel.onMessage((req, res) => {
|
|
336
|
+
if (req.event === 'testEvent')
|
|
337
|
+
return;
|
|
338
|
+
messages.push(req.event);
|
|
339
|
+
res.reject('error message', 213);
|
|
340
|
+
});
|
|
341
|
+
channel.onMessage((req, res) => {
|
|
342
|
+
if (req.event === 'testEvent') {
|
|
343
|
+
messages.push(req.event);
|
|
344
|
+
res.send('test', { test: 'onMessage' });
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
channel.subscribeToMessages('test', (message) => {
|
|
348
|
+
messages.push(message.event);
|
|
349
|
+
});
|
|
350
|
+
channel.sendTo('test', { test: 'test' }, 'test', ['test']);
|
|
351
|
+
expect(messages).toHaveLength(2);
|
|
352
|
+
// The first callback rejects the message, so the second callback is never called
|
|
353
|
+
// The user does not receive the message either because the message was rejected
|
|
354
|
+
// however, the user does receive the rejection message so
|
|
355
|
+
// 1 rejection callback receives the message + 1 rejection message
|
|
356
|
+
expect(messages).toEqual(['test', 'error']);
|
|
357
|
+
messages = [];
|
|
358
|
+
channel.sendTo('testEvent', { test: 'broadcast' }, 'test', ['test']);
|
|
359
|
+
// The first callback does not reject the message, so the second callback is called
|
|
360
|
+
// The user receives the message because the message was not rejected
|
|
361
|
+
// however, the user also receives a second message because the second callback sends a message as well
|
|
362
|
+
// 1 on message callback , 1 initial message, 1 message from the callback
|
|
363
|
+
setTimeout(() => {
|
|
364
|
+
expect(messages).toHaveLength(3); // Sometimes because of the async nature of the tests, the messages are not received in the correct order
|
|
365
|
+
expect(messages).toEqual(['testEvent', 'test', 'testEvent']);
|
|
366
|
+
done();
|
|
367
|
+
}, 10);
|
|
368
|
+
// when sendTo is called for a user that is not in the channel,
|
|
369
|
+
// An error will be thrown
|
|
370
|
+
expect(() => {
|
|
371
|
+
channel.sendTo('testEvent', { test: 'test' }, 'test3', ['test']);
|
|
372
|
+
}).toThrow();
|
|
373
|
+
expect(() => {
|
|
374
|
+
channel.sendTo('testEvent', { test: 'test' }, 'test', ['test3']);
|
|
375
|
+
}).toThrow();
|
|
376
|
+
});
|
|
377
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {PondAssigns, PondPresence} from "./types";
|
|
2
|
+
import {Channel} from "./channel";
|
|
3
|
+
import {PondResponse} from "./pondResponse";
|
|
4
|
+
import {default_t} from "../pondBase";
|
|
5
|
+
|
|
6
|
+
export declare type ChannelEvent = {
|
|
7
|
+
client: {
|
|
8
|
+
clientId: string;
|
|
9
|
+
clientAssigns: PondAssigns;
|
|
10
|
+
clientPresence: PondPresence;
|
|
11
|
+
};
|
|
12
|
+
channel: Channel;
|
|
13
|
+
payload: default_t;
|
|
14
|
+
event: string;
|
|
15
|
+
};
|
|
16
|
+
export declare type IncomingMiddlewareRequest = {
|
|
17
|
+
channelName: string;
|
|
18
|
+
event: string;
|
|
19
|
+
message: default_t;
|
|
20
|
+
client: {
|
|
21
|
+
clientId: string;
|
|
22
|
+
clientAssigns: PondAssigns;
|
|
23
|
+
clientPresence: PondPresence;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export declare type ChannelHandler = (req: IncomingMiddlewareRequest, res: PondResponse, channel: Channel) => void | Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChannelMiddleware = void 0;
|
|
4
|
+
const pondResponse_1 = require("./pondResponse");
|
|
5
|
+
class ChannelMiddleware {
|
|
6
|
+
constructor() {
|
|
7
|
+
this._handlers = [];
|
|
8
|
+
}
|
|
9
|
+
use(handler) {
|
|
10
|
+
this._handlers.push(handler);
|
|
11
|
+
}
|
|
12
|
+
merge(second) {
|
|
13
|
+
this._handlers.push(...second._handlers);
|
|
14
|
+
}
|
|
15
|
+
run(data, action) {
|
|
16
|
+
const middlewareFunctions = this._handlers.concat();
|
|
17
|
+
const request = {
|
|
18
|
+
channelName: data.channel.name,
|
|
19
|
+
message: data.payload,
|
|
20
|
+
event: data.event,
|
|
21
|
+
client: data.client
|
|
22
|
+
};
|
|
23
|
+
const response = new pondResponse_1.ChannelResponse(data.client.clientId, data.channel, action);
|
|
24
|
+
const next = () => {
|
|
25
|
+
const handler = middlewareFunctions.shift();
|
|
26
|
+
if (!handler)
|
|
27
|
+
return action(false);
|
|
28
|
+
void handler(request, response, data.channel);
|
|
29
|
+
if (response.hasExecuted)
|
|
30
|
+
return;
|
|
31
|
+
next();
|
|
32
|
+
};
|
|
33
|
+
next();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.ChannelMiddleware = ChannelMiddleware;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
import {IncomingConnection} from "./types";
|
|
5
|
+
import internal from "stream";
|
|
6
|
+
import {WebSocket, WebSocketServer} from "ws";
|
|
7
|
+
import {IncomingMessage} from "http";
|
|
8
|
+
import {BaseClass, default_t, PondPath, Resolver, ResponsePicker} from "../pondBase";
|
|
9
|
+
import {PondChannel, PondChannelHandler} from "./pondChannel";
|
|
10
|
+
import {ChannelInfo} from "./channel";
|
|
11
|
+
import {PondResponse} from "./pondResponse";
|
|
12
|
+
|
|
13
|
+
export declare type EndpointHandler = (req: IncomingConnection, res: PondResponse<ResponsePicker.POND>, endpoint: Endpoint) => void;
|
|
14
|
+
|
|
15
|
+
export declare class Endpoint extends BaseClass {
|
|
16
|
+
constructor(server: WebSocketServer, handler: EndpointHandler);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @desc Accepts a new socket join request to the room provided using the handler function to authorise the socket
|
|
20
|
+
* @param path - the pattern to accept || can also be a regex
|
|
21
|
+
* @param handler - the handler function to authenticate the socket
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const channel = endpoint.createChannel('channel:*', (req, res) => {
|
|
25
|
+
* const isAdmin = req.clientAssigns.admin;
|
|
26
|
+
* if (!isAdmin)
|
|
27
|
+
* return res.reject("You are not an admin");
|
|
28
|
+
*
|
|
29
|
+
* res.accept({
|
|
30
|
+
* assign: {
|
|
31
|
+
* admin: true,
|
|
32
|
+
* joinedDate: new Date()
|
|
33
|
+
* },
|
|
34
|
+
* presence: {state: 'online'},
|
|
35
|
+
* channelData: {private: true}
|
|
36
|
+
* });
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* channel.on('ping', (req, res, channel) => {
|
|
40
|
+
* const users = channel.getPresence();
|
|
41
|
+
* res.assign({
|
|
42
|
+
* assign: {
|
|
43
|
+
* pingDate: new Date(),
|
|
44
|
+
* users: users.length
|
|
45
|
+
* }
|
|
46
|
+
* });
|
|
47
|
+
* })
|
|
48
|
+
*/
|
|
49
|
+
createChannel(path: PondPath, handler: PondChannelHandler): PondChannel;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @desc Authenticates the client to the endpoint
|
|
53
|
+
* @param request - Incoming request
|
|
54
|
+
* @param socket - Incoming socket
|
|
55
|
+
* @param head - Incoming head
|
|
56
|
+
* @param data - Incoming the data resolved from the handler
|
|
57
|
+
*/
|
|
58
|
+
authoriseConnection(request: IncomingMessage, socket: internal.Duplex, head: Buffer, data: Resolver): void;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @desc Closes a client connection to the endpoint.
|
|
62
|
+
* @param clientId - The id of the client to close the connection to.
|
|
63
|
+
*/
|
|
64
|
+
closeConnection(clientId: string): void;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @desc Sends a message to a client on the endpoint.
|
|
68
|
+
* @param clientId - The id of the client to send the message to.
|
|
69
|
+
* @param event - The event to send the message with.
|
|
70
|
+
* @param message - The message to send.
|
|
71
|
+
*/
|
|
72
|
+
send(clientId: string | string[], event: string, message: default_t): void;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @desc lists all the channels in the endpoint
|
|
76
|
+
*/
|
|
77
|
+
listChannels(): ChannelInfo[];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @desc lists all the clients in the endpoint
|
|
81
|
+
*/
|
|
82
|
+
listConnections(): WebSocket[];
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @desc Broadcasts a message to all clients in the endpoint.
|
|
86
|
+
* @param event - The event to broadcast.
|
|
87
|
+
* @param message - The message to broadcast.
|
|
88
|
+
*/
|
|
89
|
+
broadcast(event: string, message: default_t): void;
|
|
90
|
+
}
|