@eleven-am/pondsocket 0.1.50 → 0.1.52

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.
Files changed (54) hide show
  1. package/abstracts/abstractRequest.js +58 -0
  2. package/abstracts/middleware.js +51 -0
  3. package/channel/channel.js +253 -0
  4. package/{server/channel → channel}/eventRequest.js +4 -1
  5. package/channel/eventResponse.js +150 -0
  6. package/client/channel.js +120 -97
  7. package/client.d.ts +2 -3
  8. package/client.js +34 -20
  9. package/endpoint/endpoint.js +233 -0
  10. package/endpoint/response.js +86 -0
  11. package/enums.js +14 -10
  12. package/errors/pondError.js +27 -0
  13. package/express.d.ts +2 -2
  14. package/express.js +3 -3
  15. package/index.d.ts +1 -2
  16. package/index.js +1 -4
  17. package/lobby/joinRequest.js +39 -0
  18. package/lobby/joinResponse.js +125 -0
  19. package/lobby/lobby.js +174 -0
  20. package/matcher/matcher.js +94 -0
  21. package/node.d.ts +2 -3
  22. package/node.js +3 -4
  23. package/package.json +5 -4
  24. package/presence/presence.js +113 -0
  25. package/server/pondSocket.js +123 -0
  26. package/subjects/subject.js +93 -0
  27. package/types.d.ts +274 -323
  28. package/client/channel.test.js +0 -546
  29. package/server/abstracts/abstractRequest.js +0 -40
  30. package/server/abstracts/abstractRequest.test.js +0 -41
  31. package/server/abstracts/middleware.js +0 -38
  32. package/server/abstracts/middleware.test.js +0 -70
  33. package/server/channel/channelEngine.js +0 -280
  34. package/server/channel/channelEngine.test.js +0 -377
  35. package/server/channel/channelRequest.test.js +0 -29
  36. package/server/channel/channelResponse.test.js +0 -164
  37. package/server/channel/eventResponse.js +0 -153
  38. package/server/endpoint/connectionResponse.js +0 -64
  39. package/server/endpoint/endpoint.js +0 -253
  40. package/server/endpoint/endpoint.test.js +0 -428
  41. package/server/endpoint/endpointResponse.test.js +0 -43
  42. package/server/pondChannel/joinRequest.js +0 -29
  43. package/server/pondChannel/joinResponse.js +0 -103
  44. package/server/pondChannel/pondChannel.js +0 -185
  45. package/server/pondChannel/pondChannelResponse.test.js +0 -109
  46. package/server/presence/presenceEngine.js +0 -107
  47. package/server/presence/presenceEngine.test.js +0 -105
  48. package/server/server/pondSocket.js +0 -121
  49. package/server/server/server.test.js +0 -121
  50. package/server/utils/matchPattern.js +0 -108
  51. package/server/utils/matchPattern.test.js +0 -76
  52. package/server/utils/subjectUtils.js +0 -68
  53. package/server/utils/subjectUtils.test.js +0 -128
  54. /package/{server/abstracts → abstracts}/abstractResponse.js +0 -0
@@ -1,185 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PondChannel = void 0;
4
- const joinRequest_1 = require("./joinRequest");
5
- const joinResponse_1 = require("./joinResponse");
6
- const enums_1 = require("../../enums");
7
- const middleware_1 = require("../abstracts/middleware");
8
- const channelEngine_1 = require("../channel/channelEngine");
9
- class PondChannel {
10
- constructor() {
11
- this._authorize = undefined;
12
- this._channels = new Set();
13
- this._middleware = new middleware_1.Middleware();
14
- }
15
- /**
16
- * @desc Authorize a user to join a channel
17
- * @param handler - The handler to authorize the user
18
- * @example
19
- * const pond = new PondChannelEngine();
20
- * pond.onJoinRequest((request, response) => {
21
- * if (request.user.assigns.admin)
22
- * response.accept();
23
- * else
24
- * response.reject('You are not an admin', 403);
25
- * });
26
- */
27
- onJoinRequest(handler) {
28
- this._authorize = handler;
29
- }
30
- /**
31
- * @desc Handles an event request made by a user
32
- * @param event - The event to listen for
33
- * @param handler - The handler to execute when the event is received
34
- * @example
35
- * pond.onEvent('echo', (request, response) => {
36
- * response.send('echo', {
37
- * message: request.event.payload,
38
- * });
39
- * });
40
- */
41
- onEvent(event, handler) {
42
- this._middleware.use((request, response, next) => {
43
- if (request._parseQueries(event)) {
44
- return handler(request, response);
45
- }
46
- next();
47
- });
48
- }
49
- /**
50
- * @desc Broadcasts a message to all users in a channel
51
- * @param event - The event to broadcast
52
- * @param payload - The payload to send
53
- * @param channelName - The channel to broadcast to (if not specified, broadcast to all channels)
54
- * @example
55
- * pond.broadcast('echo', {
56
- * message: 'Hello World',
57
- * timestamp: Date.now(),
58
- * channel: 'my_channel',
59
- *});
60
- */
61
- broadcast(event, payload, channelName) {
62
- if (channelName) {
63
- const channel = this._getChannel(channelName) || this._createChannel(channelName);
64
- channel.sendMessage('channel', 'all_users', enums_1.ServerActions.SYSTEM, event, payload);
65
- }
66
- else {
67
- this._channels.forEach((channel) => {
68
- channel.sendMessage('channel', 'all_users', enums_1.ServerActions.SYSTEM, event, payload);
69
- });
70
- }
71
- }
72
- /**
73
- * @desc Builds a PondChannelManager from the current engine
74
- */
75
- _buildManager() {
76
- return {
77
- addUser: this._addUser.bind(this),
78
- execute: this._execute.bind(this),
79
- removeUser: this._removeUser.bind(this),
80
- getChannels: this._getChannels.bind(this),
81
- listChannels: this._listChannels.bind(this),
82
- };
83
- }
84
- /**
85
- * @desc Adds a user to a channel
86
- * @param user - The user to add
87
- * @private
88
- */
89
- _addUser(user) {
90
- const newChannel = this._getChannel(user.channelName) || this._createChannel(user.channelName);
91
- if (this._authorize) {
92
- const socketCache = {
93
- clientId: user.clientId,
94
- socket: user.socket,
95
- assigns: user.assigns,
96
- };
97
- const request = new joinRequest_1.JoinRequest(user, newChannel);
98
- const response = new joinResponse_1.JoinResponse(socketCache, newChannel);
99
- void this._authorize(request, response);
100
- if (!response.responseSent) {
101
- throw new Error('PondChannelEngine: Response was not resolved');
102
- }
103
- }
104
- else {
105
- newChannel.addUser(user.clientId, user.assigns, (event) => {
106
- user.socket.send(JSON.stringify(event));
107
- });
108
- }
109
- }
110
- /**
111
- * @desc Removes a user from all channels
112
- * @param clientId - The client id of the user to remove
113
- * @private
114
- */
115
- _removeUser(clientId) {
116
- this._channels.forEach((channel) => {
117
- channel.removeUser(clientId, true);
118
- });
119
- }
120
- /**
121
- * @desc Creates a new channel
122
- * @param channelName - The name of the channel to create
123
- * @private
124
- */
125
- _createChannel(channelName) {
126
- const destroyChannel = this._destroyChannel.bind(this, channelName);
127
- const execute = this._middleware.run.bind(this._middleware);
128
- const parentEngine = {
129
- execute,
130
- destroyChannel,
131
- };
132
- const newChannel = new channelEngine_1.ChannelEngine(channelName, parentEngine);
133
- this._channels.add(newChannel);
134
- return newChannel;
135
- }
136
- /**
137
- * @desc Executes a function on a channel
138
- * @param channelName - The name of the channel to execute the function on
139
- * @param handler - The function to execute
140
- * @private
141
- */
142
- _execute(channelName, handler) {
143
- const newChannel = this._getChannel(channelName);
144
- if (newChannel) {
145
- return handler(newChannel);
146
- }
147
- throw new Error(`GatewayEngine: Channel ${channelName} does not exist`);
148
- }
149
- /**
150
- * @desc Gets a channel by name
151
- * @param channelName - The name of the channel to get
152
- * @private
153
- */
154
- _getChannel(channelName) {
155
- return Array.from(this._channels)
156
- .find((channel) => channel.name === channelName);
157
- }
158
- /**
159
- * @desc Destroys a channel
160
- * @param channel - The name of the channel to destroy
161
- * @private
162
- */
163
- _destroyChannel(channel) {
164
- const newChannel = this._getChannel(channel);
165
- if (newChannel) {
166
- this._channels.delete(newChannel);
167
- }
168
- }
169
- /**
170
- * @desc Lists all channels
171
- * @private
172
- */
173
- _listChannels() {
174
- return Array.from(this._channels)
175
- .map((channel) => channel.name);
176
- }
177
- /**
178
- * @desc Gets all channels
179
- * @private
180
- */
181
- _getChannels() {
182
- return Array.from(this._channels);
183
- }
184
- }
185
- exports.PondChannel = PondChannel;
@@ -1,109 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const joinResponse_1 = require("./joinResponse");
4
- const enums_1 = require("../../enums");
5
- const channelEngine_1 = require("../channel/channelEngine");
6
- const channelResponse_test_1 = require("../channel/channelResponse.test");
7
- const createPondResponse = () => {
8
- const channelEngine = (0, channelResponse_test_1.createChannelEngine)();
9
- const socket = {
10
- clientId: 'sender',
11
- assigns: { assign: 'assign' },
12
- socket: {
13
- send: jest.fn(),
14
- },
15
- };
16
- const response = new joinResponse_1.JoinResponse(socket, channelEngine);
17
- return { channelEngine,
18
- socket,
19
- response };
20
- };
21
- /* eslint-disable line-comment-position, no-inline-comments */
22
- describe('pondChannelResponse', () => {
23
- it('should create a new PondChannelResponse', () => {
24
- const { response } = createPondResponse();
25
- expect(response).toBeDefined();
26
- });
27
- it('should return the responseSent', () => {
28
- const { response } = createPondResponse();
29
- expect(response.responseSent).toEqual(false);
30
- });
31
- it('should accept the request', () => {
32
- const { response, channelEngine, socket } = createPondResponse();
33
- // spy on the channelEngine to see if the user was added
34
- jest.spyOn(channelEngine, 'addUser');
35
- response.accept();
36
- // check if the response was sent
37
- expect(response.responseSent).toEqual(true);
38
- expect(response.responseSent).toEqual(true);
39
- expect(channelEngine.addUser).toHaveBeenCalledWith(socket.clientId, socket.assigns, expect.any(Function));
40
- expect(channelEngine.getUserData(socket.clientId)).not.toBeNull();
41
- });
42
- it('should reject the request', () => {
43
- const { response, channelEngine, socket } = createPondResponse();
44
- // spy on the channelEngine to see if the user was added
45
- jest.spyOn(channelEngine, 'addUser');
46
- response.reject();
47
- // check if the response was sent
48
- expect(response.responseSent).toEqual(true);
49
- expect(channelEngine.addUser).not.toHaveBeenCalled();
50
- expect(channelEngine.getUserData(socket.clientId)).toBeUndefined();
51
- // also check if the socket was sent a message
52
- expect(socket.socket.send).toHaveBeenCalledWith(JSON.stringify({
53
- event: enums_1.ErrorTypes.UNAUTHORIZED_JOIN_REQUEST,
54
- payload: {
55
- message: 'Request to join channel test rejected: Unauthorized request',
56
- code: 403,
57
- },
58
- channelName: 'test',
59
- action: channelEngine_1.ServerActions.ERROR,
60
- }));
61
- });
62
- it('should send a direct message', () => {
63
- const { response, channelEngine, socket } = createPondResponse();
64
- // spy on the channelEngine to see if the user was added
65
- jest.spyOn(channelEngine, 'addUser');
66
- response.send('POND_MESSAGE', { message: 'message' });
67
- // check if the response was sent
68
- expect(response.responseSent).toEqual(true);
69
- expect(channelEngine.addUser).toHaveBeenCalled();
70
- expect(channelEngine.getUserData(socket.clientId)).toStrictEqual({ assigns: { assign: 'assign' },
71
- id: 'sender',
72
- presence: {} });
73
- // also check if the socket was sent a message
74
- expect(socket.socket.send).toHaveBeenCalledWith(JSON.stringify({
75
- action: channelEngine_1.ServerActions.SYSTEM,
76
- event: 'POND_MESSAGE',
77
- payload: {
78
- message: 'message',
79
- },
80
- channelName: 'test',
81
- }));
82
- });
83
- // auxiliary functions
84
- it('should send messages to different users', () => {
85
- const { response, channelEngine } = createPondResponse();
86
- // spy on the channelEngine to see if any messages were published
87
- const broadcast = jest.spyOn(channelEngine, 'sendMessage');
88
- // add a second user to the channel
89
- channelEngine.addUser('user2', { assign: 'assign' }, () => { });
90
- // send a message to a single user
91
- expect(() => response.sendToUsers('hello_everyone', { message: 'hello' }, ['user2'])).toThrow(); // this is because the sender does not exist in the channel yet
92
- // clear the spy
93
- broadcast.mockClear();
94
- // add the sender to the channel by using the response.accept() method
95
- response.accept().sendToUsers('hello_everyone', { message: 'hello' }, ['user2']);
96
- // check if the message was sent
97
- expect(broadcast).toHaveBeenCalledWith('sender', ['user2'], channelEngine_1.ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
98
- // clear the spy
99
- broadcast.mockClear();
100
- // send a message to all users
101
- response.broadcast('hello_everyone', { message: 'hello' });
102
- expect(broadcast).toHaveBeenCalledWith('sender', 'all_users', channelEngine_1.ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
103
- // clear the spy
104
- broadcast.mockClear();
105
- // send a message to all users except the sender
106
- response.broadcastFromUser('hello_everyone', { message: 'hello' });
107
- expect(broadcast).toHaveBeenCalledWith('sender', 'all_except_sender', channelEngine_1.ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
108
- });
109
- });
@@ -1,107 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PresenceEngine = void 0;
4
- const enums_1 = require("../../enums");
5
- const subjectUtils_1 = require("../utils/subjectUtils");
6
- class PresenceEngine {
7
- constructor() {
8
- this._presence = new subjectUtils_1.BehaviorSubject();
9
- this._presenceMap = new Map();
10
- }
11
- /**
12
- * @desc Lists all the presence of the users
13
- */
14
- getPresence() {
15
- return Array.from(this._presenceMap.entries())
16
- .reduce((acc, [key, value]) => {
17
- acc[key] = value;
18
- return acc;
19
- }, {});
20
- }
21
- /**
22
- * @desc Returns the presence of a user
23
- * @param userId - The id of the user
24
- */
25
- getUserPresence(userId) {
26
- return this._presenceMap.get(userId);
27
- }
28
- /**
29
- * @desc Removes a presence from the presence engine
30
- * @param presenceKey - The key of the presence
31
- */
32
- removePresence(presenceKey) {
33
- const presence = this._presenceMap.get(presenceKey);
34
- if (presence) {
35
- this._presence.unsubscribe(presenceKey);
36
- this._presenceMap.delete(presenceKey);
37
- if (this._presenceMap.size > 0) {
38
- this._presence.next({
39
- type: enums_1.PresenceEventTypes.LEAVE,
40
- changed: presence,
41
- presence: Array.from(this._presenceMap.values()),
42
- });
43
- }
44
- }
45
- else {
46
- throw new Error(`PresenceEngine: Presence with key ${presenceKey} does not exist`);
47
- }
48
- }
49
- /**
50
- * @desc Updates a presence
51
- * @param presenceKey - The key of the presence
52
- * @param presence - The new presence
53
- */
54
- updatePresence(presenceKey, presence) {
55
- const oldPresence = this._presenceMap.get(presenceKey);
56
- if (oldPresence) {
57
- this._presenceMap.set(presenceKey, Object.assign(Object.assign({}, oldPresence), presence));
58
- this._presence.next({
59
- type: enums_1.PresenceEventTypes.UPDATE,
60
- changed: Object.assign(Object.assign({}, oldPresence), presence),
61
- presence: Array.from(this._presenceMap.values()),
62
- });
63
- }
64
- else {
65
- throw new Error(`PresenceEngine: Presence with key ${presenceKey} does not exist`);
66
- }
67
- }
68
- /**
69
- * @desc Tracks a presence
70
- * @param presenceKey - The key of the presence
71
- * @param presence - The presence
72
- * @param onPresenceChange - The callback to be called when the presence changes
73
- */
74
- trackPresence(presenceKey, presence, onPresenceChange) {
75
- this._insertPresence(presenceKey, presence);
76
- return this._subscribe(presenceKey, onPresenceChange);
77
- }
78
- /**
79
- * @desc Inserts a presence into the presence engine
80
- * @param presenceKey - The key of the presence
81
- * @param presence - The presence
82
- * @private
83
- */
84
- _insertPresence(presenceKey, presence) {
85
- if (!this._presenceMap.has(presenceKey)) {
86
- this._presenceMap.set(presenceKey, presence);
87
- this._presence.next({
88
- type: enums_1.PresenceEventTypes.JOIN,
89
- changed: presence,
90
- presence: Array.from(this._presenceMap.values()),
91
- });
92
- }
93
- else {
94
- throw new Error(`PresenceEngine: Presence with key ${presenceKey} already exists`);
95
- }
96
- }
97
- /**
98
- * @desc Subscribes to the presence engine
99
- * @param identifier - The identifier of the observer
100
- * @param observer - The observer
101
- * @private
102
- */
103
- _subscribe(identifier, observer) {
104
- return this._presence.subscribe(identifier, observer);
105
- }
106
- }
107
- exports.PresenceEngine = PresenceEngine;
@@ -1,105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const presenceEngine_1 = require("./presenceEngine");
4
- const enums_1 = require("../../enums");
5
- /* eslint-disable @typescript-eslint/ban-ts-comment */
6
- describe('PresenceEngine', () => {
7
- let presenceEngine;
8
- let presence;
9
- let presenceKey;
10
- let onPresenceChange;
11
- beforeEach(() => {
12
- presenceEngine = new presenceEngine_1.PresenceEngine();
13
- presence = {
14
- id: 'id',
15
- name: 'name',
16
- color: 'color',
17
- type: 'type',
18
- location: 'location',
19
- };
20
- presenceKey = 'presenceKey';
21
- onPresenceChange = jest.fn();
22
- });
23
- describe('trackPresence', () => {
24
- it('should insert a presence into the presence engine', () => {
25
- // spy on the private method _insertPresence
26
- // @ts-ignore
27
- jest.spyOn(presenceEngine, '_insertPresence');
28
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
29
- // @ts-ignore
30
- expect(presenceEngine._insertPresence).toHaveBeenCalledWith(presenceKey, presence);
31
- expect(onPresenceChange).toHaveBeenCalledWith({
32
- type: enums_1.PresenceEventTypes.JOIN,
33
- changed: presence,
34
- presence: [presence],
35
- });
36
- });
37
- it('should subscribe to the presence engine', () => {
38
- // spy on the private method _subscribe
39
- // @ts-ignore
40
- jest.spyOn(presenceEngine, '_subscribe');
41
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
42
- // @ts-ignore
43
- expect(presenceEngine._subscribe).toHaveBeenCalledWith(presenceKey, onPresenceChange);
44
- expect(onPresenceChange).toHaveBeenCalledWith({
45
- type: enums_1.PresenceEventTypes.JOIN,
46
- changed: presence,
47
- presence: [presence],
48
- });
49
- });
50
- it('should throw an error if the presence already exists', () => {
51
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
52
- expect(() => presenceEngine.trackPresence(presenceKey, presence, onPresenceChange)).toThrowError(`PresenceEngine: Presence with key ${presenceKey} already exists`);
53
- });
54
- });
55
- describe('updatePresence', () => {
56
- it('should update a presence', () => {
57
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
58
- const newPresence = {
59
- id: 'id',
60
- name: 'name',
61
- color: 'color',
62
- type: 'type',
63
- location: 'location',
64
- };
65
- presenceEngine.updatePresence(presenceKey, newPresence);
66
- expect(onPresenceChange).toHaveBeenCalledWith({
67
- type: enums_1.PresenceEventTypes.UPDATE,
68
- changed: Object.assign(Object.assign({}, presence), newPresence),
69
- presence: [newPresence],
70
- });
71
- });
72
- it('should throw an error if the presence does not exist', () => {
73
- expect(() => presenceEngine.updatePresence(presenceKey, presence)).toThrowError(`PresenceEngine: Presence with key ${presenceKey} does not exist`);
74
- });
75
- });
76
- describe('removePresence', () => {
77
- it('should remove a presence from the presence engine', () => {
78
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
79
- presenceEngine.trackPresence('presenceKey2', Object.assign(Object.assign({}, presence), { key: 'presence2' }), onPresenceChange);
80
- presenceEngine.removePresence(presenceKey);
81
- expect(onPresenceChange).toHaveBeenCalledWith({
82
- type: enums_1.PresenceEventTypes.LEAVE,
83
- changed: presence,
84
- presence: [
85
- Object.assign(Object.assign({}, presence), { key: 'presence2' }),
86
- ],
87
- });
88
- // @ts-ignore
89
- onPresenceChange.mockClear();
90
- presenceEngine.removePresence('presenceKey2');
91
- expect(onPresenceChange).not.toHaveBeenCalled();
92
- });
93
- it('should throw an error if the presence does not exist', () => {
94
- expect(() => presenceEngine.removePresence(presenceKey)).toThrowError(`PresenceEngine: Presence with key ${presenceKey} does not exist`);
95
- });
96
- });
97
- describe('getPresence', () => {
98
- it('should return the presence', () => {
99
- presenceEngine.trackPresence(presenceKey, presence, onPresenceChange);
100
- const data = {};
101
- data[presenceKey] = presence;
102
- expect(presenceEngine.getPresence()).toEqual(data);
103
- });
104
- });
105
- });
@@ -1,121 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PondSocket = void 0;
4
- const http_1 = require("http");
5
- const ws_1 = require("ws");
6
- const endpoint_1 = require("../endpoint/endpoint");
7
- const matchPattern_1 = require("../utils/matchPattern");
8
- class PondSocket {
9
- constructor(server, socketServer) {
10
- this._middleware = [];
11
- this._matcher = new matchPattern_1.MatchPattern();
12
- this._server = server !== null && server !== void 0 ? server : new http_1.Server();
13
- this._socketServer = socketServer !== null && socketServer !== void 0 ? socketServer : new ws_1.WebSocketServer({ noServer: true });
14
- this._init();
15
- }
16
- /**
17
- * @desc Specifies the port to listen on
18
- * @param args - the arguments to pass to the server
19
- */
20
- listen(...args) {
21
- return this._server.listen(...args);
22
- }
23
- /**
24
- * @desc Closes the server
25
- * @param callback - the callback to call when the server is closed
26
- */
27
- close(callback) {
28
- return this._server.close(callback);
29
- }
30
- /**
31
- * @desc Accepts a new socket upgrade request on the provided endpoint using the handler function to authenticate the socket
32
- * @param path - the pattern to accept || can also be a regex
33
- * @param handler - the handler function to authenticate the socket
34
- * @example
35
- * const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
36
- * const token = req.query.token;
37
- * if (!token)
38
- * return res.reject("No token provided");
39
- * res.accept({
40
- * assign: {
41
- * token
42
- * }
43
- * });
44
- * })
45
- */
46
- createEndpoint(path, handler) {
47
- const endpoint = new endpoint_1.Endpoint(this._socketServer);
48
- this._middleware.push((req, socket, head, next) => {
49
- const address = req.url || '';
50
- const dataEndpoint = this._matcher.parseEvent(path, address);
51
- if (!dataEndpoint) {
52
- return next();
53
- }
54
- endpoint._authoriseConnection(req, socket, head, dataEndpoint, handler);
55
- });
56
- return endpoint;
57
- }
58
- /**
59
- * @desc Adds a middleware function to the socket server
60
- * @param middleware - the middleware function to add
61
- */
62
- use(middleware) {
63
- this._middleware.push(middleware);
64
- }
65
- /**
66
- * @desc managed the heartbeat of the socket server
67
- * @private
68
- */
69
- _manageHeartbeat() {
70
- this._socketServer.on('connection', (socket) => {
71
- socket.on('pong', () => {
72
- socket.isAlive = true;
73
- });
74
- });
75
- const interval = setInterval(() => {
76
- this._socketServer.clients.forEach((socket) => {
77
- if (socket.isAlive === false) {
78
- return socket.terminate();
79
- }
80
- socket.isAlive = false;
81
- socket.ping(() => { });
82
- });
83
- }, 30000);
84
- this._socketServer.on('close', () => clearInterval(interval));
85
- }
86
- /**
87
- * @desc executes the middleware functions
88
- * @param req - the request object
89
- * @param socket - the socket object
90
- * @param head - the head buffer
91
- * @private
92
- */
93
- _execute(req, socket, head) {
94
- const temp = this._middleware.concat();
95
- const next = () => {
96
- const middleware = temp.shift();
97
- if (middleware) {
98
- middleware(req, socket, head, next);
99
- }
100
- else {
101
- socket.write('HTTP/1.1 400 Bad Request\r\n\r');
102
- socket.destroy();
103
- }
104
- };
105
- next();
106
- }
107
- /**
108
- * @desc initialises the socket server
109
- * @private
110
- */
111
- _init() {
112
- this._manageHeartbeat();
113
- this._server.on('error', (error) => {
114
- throw new Error(error.message);
115
- });
116
- this._server.on('upgrade', (req, socket, head) => {
117
- this._execute(req, socket, head);
118
- });
119
- }
120
- }
121
- exports.PondSocket = PondSocket;