@eleven-am/pondsocket 0.1.141 → 0.1.143
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/README.md +15 -15
- package/abstracts/abstractRequest.js +1 -2
- package/abstracts/abstractRequest.test.js +2 -5
- package/channel/channel.js +118 -97
- package/channel/channel.test.js +86 -61
- package/channel/eventRequest.test.js +3 -3
- package/channel/eventResponse.js +37 -61
- package/channel/eventResponse.test.js +31 -53
- package/endpoint/endpoint.js +182 -100
- package/endpoint/endpoint.test.js +30 -13
- package/endpoint/response.js +48 -14
- package/lobby/JoinRequest.test.js +17 -6
- package/lobby/JoinResponse.test.js +18 -23
- package/lobby/joinResponse.js +70 -31
- package/lobby/lobby.js +18 -53
- package/package.json +8 -8
- package/presence/presence.js +1 -1
- package/presence/presenceEngine.test.js +1 -4
- package/schema.js +0 -1
- package/server/pondSocket.js +8 -5
- package/types.d.ts +296 -227
- package/abstracts/abstractResponse.js +0 -9
|
@@ -6,8 +6,13 @@ const channel_1 = require("./channel");
|
|
|
6
6
|
const channel_test_1 = require("./channel.test");
|
|
7
7
|
const eventResponse_1 = require("./eventResponse");
|
|
8
8
|
const createChannelEngine = () => {
|
|
9
|
-
const parentEngine = (0, channel_test_1.createParentEngine)();
|
|
10
|
-
|
|
9
|
+
const { parentEngine, socket } = (0, channel_test_1.createParentEngine)();
|
|
10
|
+
const channelEngine = new channel_1.ChannelEngine('test', parentEngine);
|
|
11
|
+
return {
|
|
12
|
+
channelEngine,
|
|
13
|
+
parentEngine,
|
|
14
|
+
socket,
|
|
15
|
+
};
|
|
11
16
|
};
|
|
12
17
|
exports.createChannelEngine = createChannelEngine;
|
|
13
18
|
const createChannelEvent = (name) => {
|
|
@@ -18,7 +23,6 @@ const createChannelEvent = (name) => {
|
|
|
18
23
|
},
|
|
19
24
|
sender: 'sender',
|
|
20
25
|
action: pondsocket_common_1.ServerActions.BROADCAST,
|
|
21
|
-
recipients: ['recipient'],
|
|
22
26
|
channelName: name,
|
|
23
27
|
requestId: 'requestId',
|
|
24
28
|
};
|
|
@@ -26,10 +30,11 @@ const createChannelEvent = (name) => {
|
|
|
26
30
|
};
|
|
27
31
|
exports.createChannelEvent = createChannelEvent;
|
|
28
32
|
const createChannelResponse = () => {
|
|
29
|
-
const channelEngine = (0, exports.createChannelEngine)();
|
|
33
|
+
const { channelEngine, socket } = (0, exports.createChannelEngine)();
|
|
30
34
|
const event = (0, exports.createChannelEvent)(channelEngine.name);
|
|
31
|
-
channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
|
|
32
|
-
|
|
35
|
+
const unsub = channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
|
|
36
|
+
socket.subscriptions.set(channelEngine.name, unsub);
|
|
37
|
+
channelEngine.addUser('tester', { assign: 'assign' }, () => { });
|
|
33
38
|
const response = new eventResponse_1.EventResponse(event, channelEngine);
|
|
34
39
|
return {
|
|
35
40
|
channelEngine,
|
|
@@ -42,52 +47,36 @@ describe('ChannelResponse', () => {
|
|
|
42
47
|
const { response } = createChannelResponse();
|
|
43
48
|
expect(response).toBeDefined();
|
|
44
49
|
});
|
|
45
|
-
it('should accept the request', () => {
|
|
46
|
-
const { response, channelEngine } = createChannelResponse();
|
|
47
|
-
jest.spyOn(channelEngine, 'sendMessage');
|
|
48
|
-
response.accept();
|
|
49
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', ['recipient'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
|
|
50
|
-
});
|
|
51
|
-
it('should reject the request', () => {
|
|
52
|
-
const { response, channelEngine, event } = createChannelResponse();
|
|
53
|
-
jest.spyOn(channelEngine, 'sendMessage');
|
|
54
|
-
response.reject();
|
|
55
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', pondsocket_common_1.SystemSender.CHANNEL, [event.sender], pondsocket_common_1.ServerActions.ERROR, pondsocket_common_1.ErrorTypes.UNAUTHORIZED_BROADCAST, {
|
|
56
|
-
message: 'Unauthorized request',
|
|
57
|
-
code: 403,
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
50
|
it('should send a direct message', () => {
|
|
61
51
|
const { response, channelEngine, event } = createChannelResponse();
|
|
62
52
|
jest.spyOn(channelEngine, 'sendMessage');
|
|
63
|
-
response.
|
|
64
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith(
|
|
53
|
+
response.reply('event', { payload: 'payload' });
|
|
54
|
+
expect(channelEngine.sendMessage).toHaveBeenCalledWith(pondsocket_common_1.SystemSender.CHANNEL, [event.sender], pondsocket_common_1.ServerActions.SYSTEM, 'event', { payload: 'payload' }, 'requestId');
|
|
65
55
|
});
|
|
66
56
|
it('should broadcast a message', () => {
|
|
67
57
|
const { response, channelEngine } = createChannelResponse();
|
|
68
58
|
jest.spyOn(channelEngine, 'sendMessage');
|
|
69
59
|
response.broadcast('event', { payload: 'payload' });
|
|
70
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('
|
|
60
|
+
expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
|
|
71
61
|
});
|
|
72
62
|
it('should broadcastFromUser a message', () => {
|
|
73
63
|
const { response, channelEngine } = createChannelResponse();
|
|
74
64
|
jest.spyOn(channelEngine, 'sendMessage');
|
|
75
|
-
response.
|
|
76
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('
|
|
65
|
+
response.broadcastFrom('event', { payload: 'payload' });
|
|
66
|
+
expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
|
|
77
67
|
});
|
|
78
68
|
it('should sendToUsers a message', () => {
|
|
79
69
|
const { response, channelEngine } = createChannelResponse();
|
|
80
70
|
jest.spyOn(channelEngine, 'sendMessage');
|
|
81
|
-
response.
|
|
82
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('
|
|
71
|
+
response.broadcastTo('event', { payload: 'payload' }, 'tester');
|
|
72
|
+
expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', ['tester'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
|
|
73
|
+
channelEngine.sendMessage.mockClear();
|
|
74
|
+
response.broadcastTo('event', { payload: 'payload' }, ['tester', 'sender']);
|
|
75
|
+
expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', ['tester', 'sender'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
|
|
83
76
|
});
|
|
84
77
|
it('should fail to send to non existing users', () => {
|
|
85
|
-
const {
|
|
86
|
-
|
|
87
|
-
event.recipients = ['non_existing_user'];
|
|
88
|
-
expect(() => response.accept()).toThrow('ChannelEngine: Invalid recipients non_existing_user some users do not exist in channel test');
|
|
89
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', event.sender, ['non_existing_user'], pondsocket_common_1.ServerActions.BROADCAST, event.event, event.payload);
|
|
90
|
-
expect(() => response.sendToUsers('event', { payload: 'payload' }, ['non_existing_user']))
|
|
78
|
+
const { response } = createChannelResponse();
|
|
79
|
+
expect(() => response.broadcastTo('event', { payload: 'payload' }, ['non_existing_user']))
|
|
91
80
|
.toThrow('ChannelEngine: Invalid recipients non_existing_user some users do not exist in channel test');
|
|
92
81
|
});
|
|
93
82
|
it('should track a trackPresence', () => {
|
|
@@ -99,7 +88,7 @@ describe('ChannelResponse', () => {
|
|
|
99
88
|
it('should update a users assign data', () => {
|
|
100
89
|
const { response, channelEngine } = createChannelResponse();
|
|
101
90
|
jest.spyOn(channelEngine, 'updateAssigns');
|
|
102
|
-
response.
|
|
91
|
+
response.assign({ assign: 'updated' });
|
|
103
92
|
expect(channelEngine.updateAssigns).toHaveBeenCalledWith('sender', { assign: 'updated' });
|
|
104
93
|
});
|
|
105
94
|
it('should evict a user', () => {
|
|
@@ -109,7 +98,11 @@ describe('ChannelResponse', () => {
|
|
|
109
98
|
expect(channelEngine.kickUser).toHaveBeenCalledWith('sender', 'recipient');
|
|
110
99
|
});
|
|
111
100
|
it('should destroy the channel', () => {
|
|
112
|
-
const {
|
|
101
|
+
const { channelEngine, socket } = (0, exports.createChannelEngine)();
|
|
102
|
+
const event = (0, exports.createChannelEvent)(channelEngine.name);
|
|
103
|
+
const unsub = channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
|
|
104
|
+
socket.subscriptions.set(channelEngine.name, unsub);
|
|
105
|
+
const response = new eventResponse_1.EventResponse(event, channelEngine);
|
|
113
106
|
jest.spyOn(channelEngine, 'destroy');
|
|
114
107
|
response.closeChannel('recipient');
|
|
115
108
|
expect(channelEngine.destroy).toHaveBeenCalledWith('recipient');
|
|
@@ -118,7 +111,6 @@ describe('ChannelResponse', () => {
|
|
|
118
111
|
const { response, channelEngine } = createChannelResponse();
|
|
119
112
|
jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
|
|
120
113
|
expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
|
|
121
|
-
response.accept();
|
|
122
114
|
response.trackPresence({ status: 'online' });
|
|
123
115
|
expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
|
|
124
116
|
});
|
|
@@ -126,7 +118,6 @@ describe('ChannelResponse', () => {
|
|
|
126
118
|
const { response, channelEngine } = createChannelResponse();
|
|
127
119
|
jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
|
|
128
120
|
expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
|
|
129
|
-
response.accept();
|
|
130
121
|
response.trackPresence({ status: 'online' });
|
|
131
122
|
expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
|
|
132
123
|
expect(() => response.trackPresence({ status: 'online' })).toThrow('PresenceEngine: Presence with key sender already exists');
|
|
@@ -135,7 +126,6 @@ describe('ChannelResponse', () => {
|
|
|
135
126
|
const { response, channelEngine } = createChannelResponse();
|
|
136
127
|
jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
|
|
137
128
|
expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
|
|
138
|
-
response.accept();
|
|
139
129
|
expect(() => response.trackPresence({ status: 'online' }, 'non_existent_user'))
|
|
140
130
|
.toThrow('ChannelEngine: Invalid recipients non_existent_user some users do not exist in channel test');
|
|
141
131
|
});
|
|
@@ -144,7 +134,6 @@ describe('ChannelResponse', () => {
|
|
|
144
134
|
const { response, channelEngine } = createChannelResponse();
|
|
145
135
|
jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
|
|
146
136
|
expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
|
|
147
|
-
response.accept();
|
|
148
137
|
response.trackPresence({ status: 'online' });
|
|
149
138
|
expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
|
|
150
139
|
expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
|
|
@@ -159,7 +148,6 @@ describe('ChannelResponse', () => {
|
|
|
159
148
|
const { response, channelEngine } = createChannelResponse();
|
|
160
149
|
jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
|
|
161
150
|
expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
|
|
162
|
-
response.accept();
|
|
163
151
|
response.trackPresence({ status: 'online' });
|
|
164
152
|
expect(() => response.updatePresence({ status: 'online' }, 'non_existent_user'))
|
|
165
153
|
.toThrow('PresenceEngine: Presence with key non_existent_user does not exist');
|
|
@@ -171,7 +159,7 @@ describe('ChannelResponse', () => {
|
|
|
171
159
|
expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
|
|
172
160
|
sender: { status: 'online' },
|
|
173
161
|
});
|
|
174
|
-
response.
|
|
162
|
+
response.removePresence();
|
|
175
163
|
expect((_b = channelEngine.presenceEngine) === null || _b === void 0 ? void 0 : _b.getPresence()).toEqual({});
|
|
176
164
|
});
|
|
177
165
|
it('should throw an error if unTrackPresence is called for a non existing user', () => {
|
|
@@ -181,17 +169,7 @@ describe('ChannelResponse', () => {
|
|
|
181
169
|
expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
|
|
182
170
|
sender: { status: 'online' },
|
|
183
171
|
});
|
|
184
|
-
expect(() => response.
|
|
172
|
+
expect(() => response.removePresence('non_existent_user'))
|
|
185
173
|
.toThrow('PresenceEngine: Presence with key non_existent_user does not exist');
|
|
186
174
|
});
|
|
187
|
-
it('should throw an error if accept, reject / send is called more than once', () => {
|
|
188
|
-
const { response, channelEngine } = createChannelResponse();
|
|
189
|
-
jest.spyOn(channelEngine, 'sendMessage');
|
|
190
|
-
expect(channelEngine.sendMessage).not.toHaveBeenCalled();
|
|
191
|
-
response.accept();
|
|
192
|
-
expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', ['recipient'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
|
|
193
|
-
expect(() => response.accept()).toThrow('Event response has already been executed');
|
|
194
|
-
expect(() => response.reject()).toThrow('Event response has already been executed');
|
|
195
|
-
expect(() => response.send('event', { payload: 'payload' })).toThrow('Event response has already been executed');
|
|
196
|
-
});
|
|
197
175
|
});
|
package/endpoint/endpoint.js
CHANGED
|
@@ -10,9 +10,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var
|
|
13
|
+
var _EndpointEngine_instances, _EndpointEngine_middleware, _EndpointEngine_channels, _EndpointEngine_sockets, _EndpointEngine_parentEngine, _EndpointEngine_sendMessage, _EndpointEngine_joinChannel, _EndpointEngine_execute, _EndpointEngine_retrieveChannel, _EndpointEngine_handleMessage, _EndpointEngine_readMessage, _EndpointEngine_buildError, _EndpointEngine_leaveChannel, _Endpoint_engine;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.Endpoint = void 0;
|
|
15
|
+
exports.Endpoint = exports.EndpointEngine = void 0;
|
|
16
16
|
const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
|
|
17
17
|
const zod_1 = require("zod");
|
|
18
18
|
const middleware_1 = require("../abstracts/middleware");
|
|
@@ -22,15 +22,20 @@ const joinResponse_1 = require("../lobby/joinResponse");
|
|
|
22
22
|
const lobby_1 = require("../lobby/lobby");
|
|
23
23
|
const matcher_1 = require("../matcher/matcher");
|
|
24
24
|
const schema_1 = require("../schema");
|
|
25
|
-
class
|
|
26
|
-
constructor() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
__classPrivateFieldSet(this,
|
|
33
|
-
__classPrivateFieldSet(this,
|
|
25
|
+
class EndpointEngine {
|
|
26
|
+
constructor(parent) {
|
|
27
|
+
_EndpointEngine_instances.add(this);
|
|
28
|
+
_EndpointEngine_middleware.set(this, void 0);
|
|
29
|
+
_EndpointEngine_channels.set(this, void 0);
|
|
30
|
+
_EndpointEngine_sockets.set(this, void 0);
|
|
31
|
+
_EndpointEngine_parentEngine.set(this, void 0);
|
|
32
|
+
__classPrivateFieldSet(this, _EndpointEngine_sockets, new Map(), "f");
|
|
33
|
+
__classPrivateFieldSet(this, _EndpointEngine_middleware, new middleware_1.Middleware(), "f");
|
|
34
|
+
__classPrivateFieldSet(this, _EndpointEngine_channels, new Set(), "f");
|
|
35
|
+
__classPrivateFieldSet(this, _EndpointEngine_parentEngine, parent, "f");
|
|
36
|
+
}
|
|
37
|
+
get parent() {
|
|
38
|
+
return __classPrivateFieldGet(this, _EndpointEngine_parentEngine, "f");
|
|
34
39
|
}
|
|
35
40
|
/**
|
|
36
41
|
* @desc Adds a new PondChannel to this path on this endpoint
|
|
@@ -47,8 +52,8 @@ class Endpoint {
|
|
|
47
52
|
* });
|
|
48
53
|
*/
|
|
49
54
|
createChannel(path, handler) {
|
|
50
|
-
const pondChannel = new lobby_1.LobbyEngine();
|
|
51
|
-
__classPrivateFieldGet(this,
|
|
55
|
+
const pondChannel = new lobby_1.LobbyEngine(this);
|
|
56
|
+
__classPrivateFieldGet(this, _EndpointEngine_middleware, "f").use((user, joinParams, next) => {
|
|
52
57
|
const event = (0, matcher_1.parseAddress)(path, user.channelName);
|
|
53
58
|
if (event) {
|
|
54
59
|
const newChannel = pondChannel.getChannel(user.channelName) || pondChannel.createChannel(user.channelName);
|
|
@@ -60,20 +65,14 @@ class Endpoint {
|
|
|
60
65
|
}
|
|
61
66
|
next();
|
|
62
67
|
});
|
|
63
|
-
__classPrivateFieldGet(this,
|
|
68
|
+
__classPrivateFieldGet(this, _EndpointEngine_channels, "f").add(pondChannel);
|
|
64
69
|
return new lobby_1.PondChannel(pondChannel);
|
|
65
70
|
}
|
|
66
|
-
/**
|
|
67
|
-
* @desc List all clients connected to this endpoint
|
|
68
|
-
*/
|
|
69
|
-
listConnections() {
|
|
70
|
-
return [...__classPrivateFieldGet(this, _Endpoint_sockets, "f")].map(({ clientId }) => clientId);
|
|
71
|
-
}
|
|
72
71
|
/**
|
|
73
72
|
* @desc Gets all clients connected to this endpoint
|
|
74
73
|
*/
|
|
75
74
|
getClients() {
|
|
76
|
-
return [...__classPrivateFieldGet(this,
|
|
75
|
+
return [...__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").values()];
|
|
77
76
|
}
|
|
78
77
|
/**
|
|
79
78
|
* @desc Broadcasts a message to all clients connected to this endpoint
|
|
@@ -81,7 +80,7 @@ class Endpoint {
|
|
|
81
80
|
* @param payload - The payload to broadcast
|
|
82
81
|
*/
|
|
83
82
|
broadcast(event, payload) {
|
|
84
|
-
__classPrivateFieldGet(this,
|
|
83
|
+
__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").forEach(({ socket }) => {
|
|
85
84
|
const message = {
|
|
86
85
|
event,
|
|
87
86
|
payload,
|
|
@@ -89,7 +88,7 @@ class Endpoint {
|
|
|
89
88
|
action: pondsocket_common_1.ServerActions.BROADCAST,
|
|
90
89
|
channelName: pondsocket_common_1.SystemSender.ENDPOINT,
|
|
91
90
|
};
|
|
92
|
-
__classPrivateFieldGet(this,
|
|
91
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_sendMessage).call(this, socket, message);
|
|
93
92
|
});
|
|
94
93
|
}
|
|
95
94
|
/**
|
|
@@ -110,98 +109,88 @@ class Endpoint {
|
|
|
110
109
|
* @param cache - The socket cache
|
|
111
110
|
*/
|
|
112
111
|
manageSocket(cache) {
|
|
113
|
-
__classPrivateFieldGet(this,
|
|
112
|
+
__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").set(cache.clientId, cache);
|
|
114
113
|
const socket = cache.socket;
|
|
115
114
|
socket.addEventListener('message', (message) => {
|
|
116
|
-
__classPrivateFieldGet(this,
|
|
115
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_readMessage).call(this, cache, message.data);
|
|
117
116
|
});
|
|
118
117
|
socket.addEventListener('close', () => {
|
|
119
|
-
|
|
120
|
-
.forEach((manager) => manager.removeUser(cache.clientId));
|
|
118
|
+
cache.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
121
119
|
});
|
|
122
120
|
socket.addEventListener('error', () => {
|
|
123
|
-
|
|
124
|
-
.forEach((manager) => manager.removeUser(cache.clientId));
|
|
121
|
+
cache.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
125
122
|
});
|
|
126
123
|
}
|
|
127
124
|
/**
|
|
128
|
-
* @desc
|
|
129
|
-
* @param
|
|
125
|
+
* @desc Retrieves a user from the endpoint
|
|
126
|
+
* @param clientId - The id of the user to retrieve
|
|
130
127
|
* @private
|
|
131
128
|
*/
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
channelName: pondsocket_common_1.SystemSender.ENDPOINT,
|
|
137
|
-
requestId: (0, pondsocket_common_1.uuid)(),
|
|
138
|
-
payload: {},
|
|
139
|
-
};
|
|
140
|
-
if (error instanceof SyntaxError) {
|
|
141
|
-
event.payload = {
|
|
142
|
-
message: 'Invalid JSON',
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
else if (error instanceof Error) {
|
|
146
|
-
event.event = pondsocket_common_1.ErrorTypes.INTERNAL_SERVER_ERROR;
|
|
147
|
-
event.payload = {
|
|
148
|
-
message: error.message,
|
|
149
|
-
};
|
|
129
|
+
getUser(clientId) {
|
|
130
|
+
const user = __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").get(clientId);
|
|
131
|
+
if (!user) {
|
|
132
|
+
throw new pondError_1.EndpointError(`GatewayEngine: User ${clientId} does not exist`, 404);
|
|
150
133
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
134
|
+
return user;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* @desc Subscribes a user to a channel, Will join the channel if it exists or add to pending subscriptions
|
|
138
|
+
* @param userId - The id of the user to subscribe
|
|
139
|
+
* @param channel - The name of the channel to subscribe to
|
|
140
|
+
*/
|
|
141
|
+
subscribeTo(userId, channel) {
|
|
142
|
+
const user = this.getUser(userId);
|
|
143
|
+
const channelEngine = __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_retrieveChannel).call(this, channel);
|
|
144
|
+
if (!channelEngine) {
|
|
145
|
+
user.pendingSubscriptions.add(channel);
|
|
159
146
|
}
|
|
160
|
-
else
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
message: error.message,
|
|
165
|
-
code: error.code,
|
|
166
|
-
};
|
|
147
|
+
else {
|
|
148
|
+
user.subscriptions.set(channel, channelEngine.addUser(userId, user.assigns, (event) => {
|
|
149
|
+
user.socket.send(JSON.stringify(event));
|
|
150
|
+
}));
|
|
167
151
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @desc Unsubscribes a user from a channel
|
|
155
|
+
* @param userId - The id of the user to unsubscribe
|
|
156
|
+
* @param channel - The name of the channel to unsubscribe from
|
|
157
|
+
*/
|
|
158
|
+
unsubscribeFrom(userId, channel) {
|
|
159
|
+
const user = this.getUser(userId);
|
|
160
|
+
const unsubscribe = user.subscriptions.get(channel);
|
|
161
|
+
if (unsubscribe) {
|
|
162
|
+
unsubscribe();
|
|
163
|
+
user.subscriptions.delete(channel);
|
|
174
164
|
}
|
|
175
|
-
else if (
|
|
176
|
-
|
|
177
|
-
if ('expected' in error && 'received' in error) {
|
|
178
|
-
return `Expected ${error.path.join('.')} to be ${error.expected}, but received ${error.received}`;
|
|
179
|
-
}
|
|
180
|
-
return `${error.path.join('.')} ${error.message}`;
|
|
181
|
-
}).join(', ');
|
|
182
|
-
event.payload = {
|
|
183
|
-
message,
|
|
184
|
-
code: 400,
|
|
185
|
-
};
|
|
165
|
+
else if (user.pendingSubscriptions.has(channel)) {
|
|
166
|
+
user.pendingSubscriptions.delete(channel);
|
|
186
167
|
}
|
|
187
168
|
else {
|
|
188
|
-
|
|
189
|
-
message: 'Unknown error',
|
|
190
|
-
};
|
|
169
|
+
throw new pondError_1.EndpointError(`GatewayEngine: User ${userId} is not subscribed to ${channel}`, 404);
|
|
191
170
|
}
|
|
192
|
-
|
|
171
|
+
}
|
|
172
|
+
subscribePendingUsers(channel) {
|
|
173
|
+
const users = [...__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").values()]
|
|
174
|
+
.filter(({ pendingSubscriptions }) => pendingSubscriptions.has(channel.name));
|
|
175
|
+
users.forEach(({ clientId, pendingSubscriptions, subscriptions, socket, assigns }) => {
|
|
176
|
+
const unsubscribe = channel.addUser(clientId, assigns, (event) => {
|
|
177
|
+
socket.send(JSON.stringify(event));
|
|
178
|
+
});
|
|
179
|
+
subscriptions.set(channel.name, unsubscribe);
|
|
180
|
+
pendingSubscriptions.delete(channel.name);
|
|
181
|
+
});
|
|
193
182
|
}
|
|
194
183
|
}
|
|
195
|
-
exports.
|
|
196
|
-
|
|
184
|
+
exports.EndpointEngine = EndpointEngine;
|
|
185
|
+
_EndpointEngine_middleware = new WeakMap(), _EndpointEngine_channels = new WeakMap(), _EndpointEngine_sockets = new WeakMap(), _EndpointEngine_parentEngine = new WeakMap(), _EndpointEngine_instances = new WeakSet(), _EndpointEngine_sendMessage = function _EndpointEngine_sendMessage(socket, message) {
|
|
197
186
|
socket.send(JSON.stringify(message));
|
|
198
|
-
},
|
|
187
|
+
}, _EndpointEngine_joinChannel = function _EndpointEngine_joinChannel(channel, socket, joinParams, requestId) {
|
|
199
188
|
const cache = Object.assign(Object.assign({}, socket), { requestId, channelName: channel });
|
|
200
|
-
__classPrivateFieldGet(this,
|
|
189
|
+
__classPrivateFieldGet(this, _EndpointEngine_middleware, "f").run(cache, joinParams, () => {
|
|
201
190
|
throw new pondError_1.EndpointError(`GatewayEngine: Channel ${channel} does not exist`, 404);
|
|
202
191
|
});
|
|
203
|
-
},
|
|
204
|
-
for (const manager of __classPrivateFieldGet(this,
|
|
192
|
+
}, _EndpointEngine_execute = function _EndpointEngine_execute(channel, handler) {
|
|
193
|
+
for (const manager of __classPrivateFieldGet(this, _EndpointEngine_channels, "f")) {
|
|
205
194
|
const isPresent = manager.listChannels()
|
|
206
195
|
.includes(channel);
|
|
207
196
|
if (isPresent) {
|
|
@@ -209,31 +198,124 @@ _Endpoint_middleware = new WeakMap(), _Endpoint_channels = new WeakMap(), _Endpo
|
|
|
209
198
|
}
|
|
210
199
|
}
|
|
211
200
|
throw new Error(`GatewayEngine: Channel ${channel} does not exist`);
|
|
212
|
-
},
|
|
201
|
+
}, _EndpointEngine_retrieveChannel = function _EndpointEngine_retrieveChannel(channel) {
|
|
202
|
+
for (const manager of __classPrivateFieldGet(this, _EndpointEngine_channels, "f")) {
|
|
203
|
+
const isPresent = manager.listChannels()
|
|
204
|
+
.includes(channel);
|
|
205
|
+
if (isPresent) {
|
|
206
|
+
return manager.getChannel(channel);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}, _EndpointEngine_handleMessage = function _EndpointEngine_handleMessage(cache, message) {
|
|
213
210
|
switch (message.action) {
|
|
214
211
|
case pondsocket_common_1.ClientActions.JOIN_CHANNEL:
|
|
215
|
-
__classPrivateFieldGet(this,
|
|
212
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_joinChannel).call(this, message.channelName, cache, message.payload, message.requestId);
|
|
216
213
|
break;
|
|
217
214
|
case pondsocket_common_1.ClientActions.LEAVE_CHANNEL:
|
|
218
|
-
__classPrivateFieldGet(this,
|
|
219
|
-
channel.removeUser(cache.clientId, true);
|
|
220
|
-
});
|
|
215
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_leaveChannel).call(this, message.channelName, cache);
|
|
221
216
|
break;
|
|
222
217
|
case pondsocket_common_1.ClientActions.BROADCAST:
|
|
223
|
-
__classPrivateFieldGet(this,
|
|
218
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_execute).call(this, message.channelName, (channel) => {
|
|
224
219
|
channel.broadcastMessage(cache.clientId, message);
|
|
225
220
|
});
|
|
226
221
|
break;
|
|
227
222
|
default:
|
|
228
223
|
throw new Error(`GatewayEngine: Action ${message.action} does not exist`);
|
|
229
224
|
}
|
|
230
|
-
},
|
|
225
|
+
}, _EndpointEngine_readMessage = function _EndpointEngine_readMessage(cache, message) {
|
|
231
226
|
try {
|
|
232
227
|
const data = JSON.parse(message);
|
|
233
228
|
const result = schema_1.clientMessageSchema.parse(data);
|
|
234
|
-
__classPrivateFieldGet(this,
|
|
229
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_handleMessage).call(this, cache, result);
|
|
235
230
|
}
|
|
236
231
|
catch (e) {
|
|
237
|
-
__classPrivateFieldGet(this,
|
|
232
|
+
__classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_sendMessage).call(this, cache.socket, __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_buildError).call(this, e));
|
|
233
|
+
}
|
|
234
|
+
}, _EndpointEngine_buildError = function _EndpointEngine_buildError(error) {
|
|
235
|
+
const event = {
|
|
236
|
+
event: pondsocket_common_1.ErrorTypes.INVALID_MESSAGE,
|
|
237
|
+
action: pondsocket_common_1.ServerActions.ERROR,
|
|
238
|
+
channelName: pondsocket_common_1.SystemSender.ENDPOINT,
|
|
239
|
+
requestId: (0, pondsocket_common_1.uuid)(),
|
|
240
|
+
payload: {},
|
|
241
|
+
};
|
|
242
|
+
if (error instanceof SyntaxError) {
|
|
243
|
+
event.payload = {
|
|
244
|
+
message: 'Invalid JSON',
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
else if (error instanceof Error) {
|
|
248
|
+
event.event = pondsocket_common_1.ErrorTypes.INTERNAL_SERVER_ERROR;
|
|
249
|
+
event.payload = {
|
|
250
|
+
message: error.message,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
else if (error instanceof pondError_1.PresenceError) {
|
|
254
|
+
event.event = pondsocket_common_1.ErrorTypes.PRESENCE_ERROR;
|
|
255
|
+
event.channelName = error.channel;
|
|
256
|
+
event.payload = {
|
|
257
|
+
message: error.message,
|
|
258
|
+
code: error.code,
|
|
259
|
+
action: error.event,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
else if (error instanceof pondError_1.ChannelError) {
|
|
263
|
+
event.event = pondsocket_common_1.ErrorTypes.CHANNEL_ERROR;
|
|
264
|
+
event.channelName = error.channel;
|
|
265
|
+
event.payload = {
|
|
266
|
+
message: error.message,
|
|
267
|
+
code: error.code,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
else if (error instanceof pondError_1.EndpointError) {
|
|
271
|
+
event.event = pondsocket_common_1.ErrorTypes.ENDPOINT_ERROR;
|
|
272
|
+
event.payload = {
|
|
273
|
+
message: error.message,
|
|
274
|
+
code: error.code,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
else if (error instanceof zod_1.ZodError) {
|
|
278
|
+
const message = error.errors.map((error) => {
|
|
279
|
+
if ('expected' in error && 'received' in error) {
|
|
280
|
+
return `Expected ${error.path.join('.')} to be ${error.expected}, but received ${error.received}`;
|
|
281
|
+
}
|
|
282
|
+
return `${error.path.join('.')} ${error.message}`;
|
|
283
|
+
}).join(', ');
|
|
284
|
+
event.payload = {
|
|
285
|
+
message,
|
|
286
|
+
code: 400,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
event.payload = {
|
|
291
|
+
message: 'Unknown error',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return event;
|
|
295
|
+
}, _EndpointEngine_leaveChannel = function _EndpointEngine_leaveChannel(channel, socket) {
|
|
296
|
+
const unsubscribe = socket.subscriptions.get(channel);
|
|
297
|
+
if (!unsubscribe) {
|
|
298
|
+
throw new pondError_1.EndpointError(`GatewayEngine: Channel ${channel} does not exist`, 404);
|
|
238
299
|
}
|
|
300
|
+
unsubscribe();
|
|
239
301
|
};
|
|
302
|
+
class Endpoint {
|
|
303
|
+
constructor(engine) {
|
|
304
|
+
_Endpoint_engine.set(this, void 0);
|
|
305
|
+
__classPrivateFieldSet(this, _Endpoint_engine, engine, "f");
|
|
306
|
+
}
|
|
307
|
+
createChannel(path, handler) {
|
|
308
|
+
return __classPrivateFieldGet(this, _Endpoint_engine, "f").createChannel(path, handler);
|
|
309
|
+
}
|
|
310
|
+
broadcast(event, payload) {
|
|
311
|
+
__classPrivateFieldGet(this, _Endpoint_engine, "f").broadcast(event, payload);
|
|
312
|
+
}
|
|
313
|
+
closeConnection(clientIds) {
|
|
314
|
+
__classPrivateFieldGet(this, _Endpoint_engine, "f").closeConnection(clientIds);
|
|
315
|
+
}
|
|
316
|
+
getClients() {
|
|
317
|
+
return __classPrivateFieldGet(this, _Endpoint_engine, "f").getClients().map(({ socket }) => socket);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
exports.Endpoint = Endpoint;
|
|
321
|
+
_Endpoint_engine = new WeakMap();
|