@eleven-am/pondsocket 0.1.197 → 0.1.198

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.
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
12
  if (kind === "m") throw new TypeError("Private method is not writable");
4
13
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
@@ -10,38 +19,68 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
19
  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
20
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
21
  };
13
- var _ChannelEngine_instances, _ChannelEngine_manager, _ChannelEngine_getUsersFromRecipients;
22
+ var __rest = (this && this.__rest) || function (s, e) {
23
+ var t = {};
24
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
25
+ t[p] = s[p];
26
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
27
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
28
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
29
+ t[p[i]] = s[p[i]];
30
+ }
31
+ return t;
32
+ };
33
+ var _ChannelEngine_instances, _ChannelEngine_presenceEngine, _ChannelEngine_assignsCache, _ChannelEngine_userSubscriptions, _ChannelEngine_publisher, _ChannelEngine_name, _ChannelEngine_buildSubscriber, _ChannelEngine_getOrCreatePresenceEngine, _ChannelEngine_getUsersFromRecipients;
14
34
  Object.defineProperty(exports, "__esModule", { value: true });
15
35
  exports.ChannelEngine = void 0;
16
36
  const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
37
+ const presenceEngine_1 = require("./presenceEngine");
17
38
  const httpError_1 = require("../errors/httpError");
18
- const channel_1 = require("../wrappers/channel");
19
39
  class ChannelEngine {
20
- constructor(parent, name, manager) {
40
+ constructor(parent, name) {
21
41
  _ChannelEngine_instances.add(this);
22
42
  this.parent = parent;
23
- this.name = name;
24
- _ChannelEngine_manager.set(this, void 0);
25
- __classPrivateFieldSet(this, _ChannelEngine_manager, manager, "f");
43
+ _ChannelEngine_presenceEngine.set(this, null);
44
+ _ChannelEngine_assignsCache.set(this, new Map());
45
+ _ChannelEngine_userSubscriptions.set(this, new Map());
46
+ _ChannelEngine_publisher.set(this, new pondsocket_common_1.Subject());
47
+ _ChannelEngine_name.set(this, void 0);
48
+ __classPrivateFieldSet(this, _ChannelEngine_name, name, "f");
49
+ }
50
+ get name() {
51
+ return __classPrivateFieldGet(this, _ChannelEngine_name, "f");
26
52
  }
27
53
  get users() {
28
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").userIds;
54
+ return new Set(__classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").keys());
29
55
  }
56
+ /**
57
+ * Adds a user to the channel
58
+ * @param userId - The user ID
59
+ * @param assigns - The user's assigns
60
+ * @param onMessage - Callback for messages
61
+ * @returns Unsubscribe function
62
+ */
30
63
  addUser(userId, assigns, onMessage) {
31
64
  if (this.users.has(userId)) {
32
65
  const message = `ChannelEngine: User with id ${userId} already exists in channel ${this.name}`;
33
- const code = 400;
34
- throw new httpError_1.HttpError(code, message);
66
+ throw new httpError_1.HttpError(400, message);
35
67
  }
36
- __classPrivateFieldGet(this, _ChannelEngine_manager, "f").addUser(userId, assigns, onMessage);
68
+ // Store user assigns
69
+ __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").set(userId, assigns);
70
+ // Subscribe user to messages
71
+ __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_buildSubscriber).call(this, userId, onMessage);
72
+ // Send acknowledgment
37
73
  this.sendMessage(pondsocket_common_1.SystemSender.CHANNEL, [userId], pondsocket_common_1.ServerActions.SYSTEM, pondsocket_common_1.Events.ACKNOWLEDGE, {});
38
- return this.removeUser.bind(this, userId);
74
+ // Return unsubscribe function
75
+ return () => this.removeUser(userId);
39
76
  }
77
+ /**
78
+ * Sends a message to recipients
79
+ */
40
80
  sendMessage(sender, recipient, action, event, payload, requestId = (0, pondsocket_common_1.uuid)()) {
41
81
  if (!this.users.has(sender) && sender !== pondsocket_common_1.SystemSender.CHANNEL) {
42
82
  const message = `ChannelEngine: User with id ${sender} does not exist in channel ${this.name}`;
43
- const code = 404;
44
- throw new httpError_1.HttpError(code, message);
83
+ throw new httpError_1.HttpError(404, message);
45
84
  }
46
85
  const channelEvent = {
47
86
  channelName: this.name,
@@ -52,13 +91,15 @@ class ChannelEngine {
52
91
  };
53
92
  const recipients = __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getUsersFromRecipients).call(this, recipient, sender);
54
93
  const internalEvent = Object.assign(Object.assign({}, channelEvent), { recipients });
55
- __classPrivateFieldGet(this, _ChannelEngine_manager, "f").broadcast(internalEvent);
94
+ __classPrivateFieldGet(this, _ChannelEngine_publisher, "f").publish(internalEvent);
56
95
  }
96
+ /**
97
+ * Broadcasts a message from a user
98
+ */
57
99
  broadcastMessage(userId, message) {
58
100
  if (!this.users.has(userId)) {
59
101
  const message = `ChannelEngine: User with id ${userId} does not exist in channel ${this.name}`;
60
- const code = 404;
61
- throw new httpError_1.HttpError(code, message);
102
+ throw new httpError_1.HttpError(404, message);
62
103
  }
63
104
  const responseEvent = Object.assign(Object.assign({}, message), { sender: userId, action: pondsocket_common_1.ServerActions.BROADCAST });
64
105
  this.parent.middleware.run(responseEvent, this, (error) => {
@@ -68,21 +109,48 @@ class ChannelEngine {
68
109
  }, message.requestId);
69
110
  });
70
111
  }
112
+ /**
113
+ * Tracks a user's presence
114
+ */
71
115
  trackPresence(userId, presence) {
72
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").trackPresence(userId, presence);
116
+ const presenceEngine = __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getOrCreatePresenceEngine).call(this);
117
+ presenceEngine.trackPresence(userId, presence);
73
118
  }
119
+ /**
120
+ * Updates a user's presence
121
+ */
74
122
  updatePresence(userId, presence) {
75
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").updatePresence(userId, presence);
123
+ const presenceEngine = __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getOrCreatePresenceEngine).call(this);
124
+ presenceEngine.updatePresence(userId, presence);
76
125
  }
126
+ /**
127
+ * Removes a user's presence
128
+ */
77
129
  removePresence(userId) {
78
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").removePresence(userId);
130
+ if (__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) {
131
+ __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f").removePresence(userId);
132
+ }
79
133
  }
134
+ /**
135
+ * Adds or updates a user's presence
136
+ */
80
137
  upsertPresence(userId, presence) {
81
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").upsertPresence(userId, presence);
138
+ const presenceEngine = __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getOrCreatePresenceEngine).call(this);
139
+ presenceEngine.upsertPresence(userId, presence);
82
140
  }
141
+ /**
142
+ * Updates a user's assigns
143
+ */
83
144
  updateAssigns(userId, assigns) {
84
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").updateAssigns(userId, assigns);
145
+ if (!__classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").has(userId)) {
146
+ throw new httpError_1.HttpError(404, `User with id ${userId} does not exist in channel ${this.name}`);
147
+ }
148
+ const currentAssigns = __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").get(userId) || {};
149
+ __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").set(userId, Object.assign(Object.assign({}, currentAssigns), assigns));
85
150
  }
151
+ /**
152
+ * Kicks a user from the channel
153
+ */
86
154
  kickUser(userId, reason) {
87
155
  this.sendMessage(pondsocket_common_1.SystemSender.CHANNEL, [userId], pondsocket_common_1.ServerActions.SYSTEM, 'kicked_out', {
88
156
  message: reason,
@@ -94,43 +162,131 @@ class ChannelEngine {
94
162
  reason,
95
163
  });
96
164
  }
165
+ /**
166
+ * Gets all assigns as an object
167
+ */
97
168
  getAssigns() {
98
169
  return Array
99
- .from(__classPrivateFieldGet(this, _ChannelEngine_manager, "f").getAllAssigns().entries())
170
+ .from(__classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").entries())
100
171
  .reduce((acc, [id, assigns]) => {
101
172
  acc[id] = assigns;
102
173
  return acc;
103
174
  }, {});
104
175
  }
176
+ /**
177
+ * Gets all presence data as an object
178
+ */
105
179
  getPresence() {
180
+ if (!__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) {
181
+ return {};
182
+ }
106
183
  return Array
107
- .from(__classPrivateFieldGet(this, _ChannelEngine_manager, "f").getAllPresence().entries())
184
+ .from(__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f").getAllPresence().entries())
108
185
  .reduce((acc, [id, presence]) => {
109
186
  acc[id] = presence;
110
187
  return acc;
111
188
  }, {});
112
189
  }
190
+ /**
191
+ * Destroys the channel
192
+ */
113
193
  destroy(reason) {
114
194
  this.sendMessage(pondsocket_common_1.SystemSender.CHANNEL, pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.ERROR, 'destroyed', {
115
195
  message: reason !== null && reason !== void 0 ? reason : 'Channel has been destroyed',
116
196
  });
117
- __classPrivateFieldGet(this, _ChannelEngine_manager, "f").close();
197
+ this.close();
118
198
  }
199
+ /**
200
+ * Removes a user from the channel
201
+ */
119
202
  removeUser(userId) {
120
- const userData = __classPrivateFieldGet(this, _ChannelEngine_manager, "f").removeUser(userId);
121
- if (this.parent.leaveCallback) {
122
- this.parent.leaveCallback({
123
- user: userData,
124
- channel: new channel_1.Channel(this),
125
- });
203
+ try {
204
+ const userData = this.getUserData(userId);
205
+ const unsubscribe = __classPrivateFieldGet(this, _ChannelEngine_userSubscriptions, "f").get(userId);
206
+ __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").delete(userId);
207
+ if (__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) {
208
+ __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f").removePresence(userId);
209
+ }
210
+ if (unsubscribe) {
211
+ unsubscribe();
212
+ __classPrivateFieldGet(this, _ChannelEngine_userSubscriptions, "f").delete(userId);
213
+ }
214
+ // Trigger leave callback if defined
215
+ if (this.parent.leaveCallback) {
216
+ this.parent.leaveCallback({
217
+ user: userData,
218
+ channel: this.parent.wrapChannel(this),
219
+ });
220
+ }
221
+ // If no users left, close the channel
222
+ if (this.users.size === 0) {
223
+ this.close();
224
+ }
225
+ }
226
+ catch (error) {
227
+ // Ignore cleanup errors
126
228
  }
127
229
  }
128
- getUser(userId) {
129
- return __classPrivateFieldGet(this, _ChannelEngine_manager, "f").getUserData(userId);
230
+ /**
231
+ * Gets user data by ID
232
+ */
233
+ getUserData(userId) {
234
+ var _a;
235
+ const assigns = __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").get(userId);
236
+ const presence = ((_a = __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) === null || _a === void 0 ? void 0 : _a.getPresence(userId)) || null;
237
+ if (!assigns && !presence) {
238
+ const message = `User with id ${userId} does not exist in the channel ${this.name}`;
239
+ throw new httpError_1.HttpError(404, message);
240
+ }
241
+ return {
242
+ assigns: assigns || {},
243
+ presence: presence || {},
244
+ id: userId,
245
+ };
246
+ }
247
+ /**
248
+ * Closes the channel and cleans up resources
249
+ */
250
+ close() {
251
+ // Clear all user subscriptions
252
+ __classPrivateFieldGet(this, _ChannelEngine_userSubscriptions, "f").forEach((unsubscribe) => unsubscribe());
253
+ __classPrivateFieldGet(this, _ChannelEngine_userSubscriptions, "f").clear();
254
+ // Clear assigns
255
+ __classPrivateFieldGet(this, _ChannelEngine_assignsCache, "f").clear();
256
+ // Close presence engine if exists
257
+ if (__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) {
258
+ __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f").close();
259
+ __classPrivateFieldSet(this, _ChannelEngine_presenceEngine, null, "f");
260
+ }
261
+ // Close publisher
262
+ __classPrivateFieldGet(this, _ChannelEngine_publisher, "f").close();
130
263
  }
131
264
  }
132
265
  exports.ChannelEngine = ChannelEngine;
133
- _ChannelEngine_manager = new WeakMap(), _ChannelEngine_instances = new WeakSet(), _ChannelEngine_getUsersFromRecipients = function _ChannelEngine_getUsersFromRecipients(recipients, sender) {
266
+ _ChannelEngine_presenceEngine = new WeakMap(), _ChannelEngine_assignsCache = new WeakMap(), _ChannelEngine_userSubscriptions = new WeakMap(), _ChannelEngine_publisher = new WeakMap(), _ChannelEngine_name = new WeakMap(), _ChannelEngine_instances = new WeakSet(), _ChannelEngine_buildSubscriber = function _ChannelEngine_buildSubscriber(userId, onMessage) {
267
+ const subscription = __classPrivateFieldGet(this, _ChannelEngine_publisher, "f").subscribe((_a) => __awaiter(this, void 0, void 0, function* () {
268
+ var { recipients } = _a, event = __rest(_a, ["recipients"]);
269
+ if (recipients.includes(userId)) {
270
+ if (event.action === pondsocket_common_1.ServerActions.SYSTEM) {
271
+ return onMessage(event);
272
+ }
273
+ const newEvent = yield this.parent.manageOutgoingEvents(event, userId, this);
274
+ if (newEvent) {
275
+ onMessage(newEvent);
276
+ }
277
+ }
278
+ }));
279
+ __classPrivateFieldGet(this, _ChannelEngine_userSubscriptions, "f").set(userId, subscription);
280
+ }, _ChannelEngine_getOrCreatePresenceEngine = function _ChannelEngine_getOrCreatePresenceEngine() {
281
+ if (!__classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f")) {
282
+ __classPrivateFieldSet(this, _ChannelEngine_presenceEngine, new presenceEngine_1.PresenceEngine(this.name), "f");
283
+ // Subscribe to presence events and publish them through the channel publisher
284
+ __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f").subscribe((event) => {
285
+ __classPrivateFieldGet(this, _ChannelEngine_publisher, "f").publish(event);
286
+ });
287
+ }
288
+ return __classPrivateFieldGet(this, _ChannelEngine_presenceEngine, "f");
289
+ }, _ChannelEngine_getUsersFromRecipients = function _ChannelEngine_getUsersFromRecipients(recipients, sender) {
134
290
  const allUsers = Array.from(this.users);
135
291
  let users;
136
292
  switch (recipients) {
@@ -140,21 +296,18 @@ _ChannelEngine_manager = new WeakMap(), _ChannelEngine_instances = new WeakSet()
140
296
  case pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER:
141
297
  if (sender === pondsocket_common_1.SystemSender.CHANNEL) {
142
298
  const message = `ChannelEngine: Invalid sender ${sender} for recipients ${recipients}`;
143
- const code = 400;
144
- throw new httpError_1.HttpError(code, message);
299
+ throw new httpError_1.HttpError(400, message);
145
300
  }
146
301
  users = allUsers.filter((user) => user !== sender);
147
302
  break;
148
303
  default:
149
304
  if (!Array.isArray(recipients)) {
150
305
  const message = `ChannelEngine: Invalid recipients ${recipients} must be an array of user ids or ${pondsocket_common_1.ChannelReceiver.ALL_USERS}`;
151
- const code = 400;
152
- throw new httpError_1.HttpError(code, message);
306
+ throw new httpError_1.HttpError(400, message);
153
307
  }
154
308
  if (recipients.some((user) => !allUsers.includes(user))) {
155
309
  const message = `ChannelEngine: Invalid user ids in recipients ${recipients}`;
156
- const code = 400;
157
- throw new httpError_1.HttpError(code, message);
310
+ throw new httpError_1.HttpError(400, message);
158
311
  }
159
312
  users = recipients;
160
313
  break;
@@ -10,32 +10,32 @@ 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 _EndpointEngine_instances, _EndpointEngine_clientFactory, _EndpointEngine_sockets, _EndpointEngine_middleware, _EndpointEngine_lobbyEngines, _EndpointEngine_handleSocketClose, _EndpointEngine_handleMessage, _EndpointEngine_joinChannel, _EndpointEngine_leaveChannel, _EndpointEngine_retrieveChannel, _EndpointEngine_buildError, _EndpointEngine_broadcastMessage, _EndpointEngine_readMessage;
13
+ var _EndpointEngine_instances, _EndpointEngine_sockets, _EndpointEngine_middleware, _EndpointEngine_lobbyEngines, _EndpointEngine_handleSocketClose, _EndpointEngine_handleMessage, _EndpointEngine_joinChannel, _EndpointEngine_leaveChannel, _EndpointEngine_retrieveChannel, _EndpointEngine_buildError, _EndpointEngine_broadcastMessage, _EndpointEngine_readMessage;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.EndpointEngine = void 0;
16
16
  const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
17
  const lobbyEngine_1 = require("./lobbyEngine");
18
18
  const middleware_1 = require("../abstracts/middleware");
19
19
  const httpError_1 = require("../errors/httpError");
20
- const managerFactory_1 = require("../managers/managerFactory");
21
20
  const matcher_1 = require("../matcher/matcher");
22
21
  const joinRequest_1 = require("../requests/joinRequest");
23
22
  const joinResponse_1 = require("../responses/joinResponse");
24
23
  const pondChannel_1 = require("../wrappers/pondChannel");
25
24
  class EndpointEngine {
26
- constructor(clientFactory) {
25
+ constructor() {
27
26
  _EndpointEngine_instances.add(this);
28
- _EndpointEngine_clientFactory.set(this, void 0);
29
27
  _EndpointEngine_sockets.set(this, void 0);
30
28
  _EndpointEngine_middleware.set(this, void 0);
31
29
  _EndpointEngine_lobbyEngines.set(this, void 0);
32
30
  __classPrivateFieldSet(this, _EndpointEngine_sockets, new Map(), "f");
33
31
  __classPrivateFieldSet(this, _EndpointEngine_lobbyEngines, new Map(), "f");
34
32
  __classPrivateFieldSet(this, _EndpointEngine_middleware, new middleware_1.Middleware(), "f");
35
- __classPrivateFieldSet(this, _EndpointEngine_clientFactory, clientFactory, "f");
36
33
  }
34
+ /**
35
+ * Creates a new channel on a specified path
36
+ */
37
37
  createChannel(path, handler) {
38
- const pondChannel = new lobbyEngine_1.LobbyEngine(this);
38
+ const lobbyEngine = new lobbyEngine_1.LobbyEngine(this);
39
39
  __classPrivateFieldGet(this, _EndpointEngine_middleware, "f").use((user, joinParams, next) => {
40
40
  const event = (0, matcher_1.parseAddress)(path, user.channelName);
41
41
  if (event) {
@@ -45,19 +45,25 @@ class EndpointEngine {
45
45
  params: event,
46
46
  joinParams,
47
47
  };
48
- const channel = pondChannel.getOrCreateChannel(user.channelName);
48
+ const channel = lobbyEngine.getOrCreateChannel(user.channelName);
49
49
  const request = new joinRequest_1.JoinRequest(options, channel);
50
50
  const response = new joinResponse_1.JoinResponse(user, channel);
51
51
  return handler(request, response, next);
52
52
  }
53
53
  next();
54
54
  });
55
- __classPrivateFieldGet(this, _EndpointEngine_lobbyEngines, "f").set(path, pondChannel);
56
- return new pondChannel_1.PondChannel(pondChannel);
55
+ __classPrivateFieldGet(this, _EndpointEngine_lobbyEngines, "f").set(path, lobbyEngine);
56
+ return new pondChannel_1.PondChannel(lobbyEngine);
57
57
  }
58
+ /**
59
+ * Gets all connected clients
60
+ */
58
61
  getClients() {
59
62
  return [...__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").values()];
60
63
  }
64
+ /**
65
+ * Gets a specific user by client ID
66
+ */
61
67
  getUser(clientId) {
62
68
  const user = __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").get(clientId);
63
69
  if (!user) {
@@ -65,6 +71,9 @@ class EndpointEngine {
65
71
  }
66
72
  return user;
67
73
  }
74
+ /**
75
+ * Manages a new WebSocket connection
76
+ */
68
77
  manageSocket(cache) {
69
78
  __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").set(cache.clientId, cache);
70
79
  cache.socket.on('message', (message) => __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_readMessage).call(this, cache, message));
@@ -79,12 +88,15 @@ class EndpointEngine {
79
88
  };
80
89
  this.sendMessage(cache.socket, event);
81
90
  }
82
- createManager(channelName, onLeave) {
83
- return managerFactory_1.ManagerFactory.create(channelName, __classPrivateFieldGet(this, _EndpointEngine_clientFactory, "f"), onLeave);
84
- }
91
+ /**
92
+ * Sends a message to a WebSocket
93
+ */
85
94
  sendMessage(socket, message) {
86
95
  socket.send(JSON.stringify(message));
87
96
  }
97
+ /**
98
+ * Closes one or more client connections
99
+ */
88
100
  closeConnection(clientIds) {
89
101
  const clients = typeof clientIds === 'string' ? [clientIds] : clientIds;
90
102
  this.getClients()
@@ -96,7 +108,7 @@ class EndpointEngine {
96
108
  }
97
109
  }
98
110
  exports.EndpointEngine = EndpointEngine;
99
- _EndpointEngine_clientFactory = new WeakMap(), _EndpointEngine_sockets = new WeakMap(), _EndpointEngine_middleware = new WeakMap(), _EndpointEngine_lobbyEngines = new WeakMap(), _EndpointEngine_instances = new WeakSet(), _EndpointEngine_handleSocketClose = function _EndpointEngine_handleSocketClose(cache) {
111
+ _EndpointEngine_sockets = new WeakMap(), _EndpointEngine_middleware = new WeakMap(), _EndpointEngine_lobbyEngines = new WeakMap(), _EndpointEngine_instances = new WeakSet(), _EndpointEngine_handleSocketClose = function _EndpointEngine_handleSocketClose(cache) {
100
112
  try {
101
113
  __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").delete(cache.clientId);
102
114
  cache.subscriptions.forEach((unsubscribe) => unsubscribe());
@@ -128,10 +140,10 @@ _EndpointEngine_clientFactory = new WeakMap(), _EndpointEngine_sockets = new Wea
128
140
  const engine = __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_retrieveChannel).call(this, channel);
129
141
  engine.removeUser(socket.clientId);
130
142
  }, _EndpointEngine_retrieveChannel = function _EndpointEngine_retrieveChannel(channel) {
131
- for (const [path, manager] of __classPrivateFieldGet(this, _EndpointEngine_lobbyEngines, "f")) {
143
+ for (const [path, lobby] of __classPrivateFieldGet(this, _EndpointEngine_lobbyEngines, "f")) {
132
144
  const event = (0, matcher_1.parseAddress)(path, channel);
133
145
  if (event) {
134
- return manager.getChannel(channel);
146
+ return lobby.getChannel(channel);
135
147
  }
136
148
  }
137
149
  throw new httpError_1.HttpError(404, `GatewayEngine: Channel ${channel} does not exist`);
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
12
  if (kind === "m") throw new TypeError("Private method is not writable");
4
13
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
@@ -10,7 +19,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
19
  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
20
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
21
  };
13
- var _LobbyEngine_instances, _LobbyEngine_channels, _LobbyEngine_getChannel, _LobbyEngine_createChannel;
22
+ var _LobbyEngine_instances, _LobbyEngine_channels, _LobbyEngine_outGoingEvents, _LobbyEngine_getChannel, _LobbyEngine_createChannel;
14
23
  Object.defineProperty(exports, "__esModule", { value: true });
15
24
  exports.LobbyEngine = void 0;
16
25
  const channelEngine_1 = require("./channelEngine");
@@ -19,17 +28,26 @@ const httpError_1 = require("../errors/httpError");
19
28
  const matcher_1 = require("../matcher/matcher");
20
29
  const eventRequest_1 = require("../requests/eventRequest");
21
30
  const eventResponse_1 = require("../responses/eventResponse");
31
+ const channel_1 = require("../wrappers/channel");
22
32
  class LobbyEngine {
23
33
  constructor(parent) {
24
34
  _LobbyEngine_instances.add(this);
25
35
  this.parent = parent;
26
36
  _LobbyEngine_channels.set(this, void 0);
37
+ _LobbyEngine_outGoingEvents.set(this, void 0);
27
38
  this.middleware = new middleware_1.Middleware();
28
39
  __classPrivateFieldSet(this, _LobbyEngine_channels, new Map(), "f");
40
+ __classPrivateFieldSet(this, _LobbyEngine_outGoingEvents, [], "f");
29
41
  }
42
+ /**
43
+ * Sets the callback for when users leave channels
44
+ */
30
45
  onLeave(callback) {
31
46
  this.leaveCallback = callback;
32
47
  }
48
+ /**
49
+ * Attaches a handler for a specific event pattern
50
+ */
33
51
  onEvent(event, handler) {
34
52
  this.middleware.use((requestEvent, channel, next) => {
35
53
  const params = (0, matcher_1.parseAddress)(event, requestEvent.event);
@@ -41,6 +59,60 @@ class LobbyEngine {
41
59
  return next();
42
60
  });
43
61
  }
62
+ /**
63
+ * Attaches a handler for outgoing events
64
+ */
65
+ handleOutgoingEvent(event, handler) {
66
+ const handlerWrapper = (request, channel, userId) => __awaiter(this, void 0, void 0, function* () {
67
+ try {
68
+ const params = (0, matcher_1.parseAddress)(event, request.event);
69
+ if (!params) {
70
+ return true;
71
+ }
72
+ const userData = channel.getUserData(userId);
73
+ const newEvent = {
74
+ channel,
75
+ userData,
76
+ event: params,
77
+ payload: request.payload,
78
+ };
79
+ const response = yield handler(newEvent);
80
+ if (response) {
81
+ return response;
82
+ }
83
+ return false;
84
+ }
85
+ catch (error) {
86
+ return false;
87
+ }
88
+ });
89
+ __classPrivateFieldGet(this, _LobbyEngine_outGoingEvents, "f").push(handlerWrapper);
90
+ }
91
+ /**
92
+ * Internal method to handle outgoing events
93
+ * @param request - The request object
94
+ * @param userId - The user ID
95
+ * @param channel - The channel engine
96
+ */
97
+ manageOutgoingEvents(request, userId, channel) {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ if (!__classPrivateFieldGet(this, _LobbyEngine_outGoingEvents, "f").length) {
100
+ return request;
101
+ }
102
+ const promises = __classPrivateFieldGet(this, _LobbyEngine_outGoingEvents, "f").map((handler) => handler(request, this.wrapChannel(channel), userId));
103
+ const results = yield Promise.all(promises);
104
+ if (results.some((result) => result === false)) {
105
+ return null;
106
+ }
107
+ request.payload = results
108
+ .filter((result) => typeof result !== 'boolean')
109
+ .reduce((acc, result) => Object.assign(acc, result), {});
110
+ return request;
111
+ });
112
+ }
113
+ /**
114
+ * Gets or creates a channel by name
115
+ */
44
116
  getOrCreateChannel(channelName) {
45
117
  const oldChannel = __classPrivateFieldGet(this, _LobbyEngine_instances, "m", _LobbyEngine_getChannel).call(this, channelName);
46
118
  if (oldChannel) {
@@ -48,6 +120,10 @@ class LobbyEngine {
48
120
  }
49
121
  return __classPrivateFieldGet(this, _LobbyEngine_instances, "m", _LobbyEngine_createChannel).call(this, channelName);
50
122
  }
123
+ /**
124
+ * Gets a channel by name
125
+ * @throws HttpError if channel not found
126
+ */
51
127
  getChannel(channelName) {
52
128
  const channel = __classPrivateFieldGet(this, _LobbyEngine_channels, "f").get(channelName);
53
129
  if (!channel) {
@@ -55,14 +131,27 @@ class LobbyEngine {
55
131
  }
56
132
  return channel;
57
133
  }
134
+ /**
135
+ * Creates a Channel wrapper from a ChannelEngine
136
+ * Used by the channel engine for the leave callback
137
+ */
138
+ wrapChannel(engine) {
139
+ return new channel_1.Channel(engine);
140
+ }
58
141
  }
59
142
  exports.LobbyEngine = LobbyEngine;
60
- _LobbyEngine_channels = new WeakMap(), _LobbyEngine_instances = new WeakSet(), _LobbyEngine_getChannel = function _LobbyEngine_getChannel(channelName) {
143
+ _LobbyEngine_channels = new WeakMap(), _LobbyEngine_outGoingEvents = new WeakMap(), _LobbyEngine_instances = new WeakSet(), _LobbyEngine_getChannel = function _LobbyEngine_getChannel(channelName) {
61
144
  return __classPrivateFieldGet(this, _LobbyEngine_channels, "f").get(channelName) || null;
62
145
  }, _LobbyEngine_createChannel = function _LobbyEngine_createChannel(channelName) {
63
- const onManagerClose = __classPrivateFieldGet(this, _LobbyEngine_channels, "f").delete.bind(__classPrivateFieldGet(this, _LobbyEngine_channels, "f"), channelName);
64
- const manager = this.parent.createManager(channelName, onManagerClose);
65
- const channel = new channelEngine_1.ChannelEngine(this, channelName, manager);
146
+ // Create the channel engine
147
+ const channel = new channelEngine_1.ChannelEngine(this, channelName);
148
+ // Add it to the channels map
66
149
  __classPrivateFieldGet(this, _LobbyEngine_channels, "f").set(channelName, channel);
150
+ // Set up a way to remove the channel when it's closed
151
+ // (We'll handle this in the ChannelEngine's close method)
152
+ const handleChannelClosed = () => {
153
+ __classPrivateFieldGet(this, _LobbyEngine_channels, "f").delete(channelName);
154
+ };
155
+ // Return the new channel engine
67
156
  return channel;
68
157
  };