@sockethub/server 5.0.0-alpha.4 → 5.0.0-alpha.6

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 (105) hide show
  1. package/README.md +54 -60
  2. package/bin/sockethub +4 -3
  3. package/package.json +42 -54
  4. package/res/socket.io.js +4908 -0
  5. package/res/sockethub-client.js +602 -0
  6. package/res/sockethub-client.min.js +19 -0
  7. package/sockethub.config.example.json +2 -3
  8. package/src/bootstrap/init.d.ts +16 -13
  9. package/src/bootstrap/init.test.ts +211 -0
  10. package/src/bootstrap/init.ts +152 -76
  11. package/src/bootstrap/load-platforms.ts +151 -0
  12. package/src/config.test.ts +27 -22
  13. package/src/config.ts +82 -86
  14. package/src/defaults.json +24 -16
  15. package/src/index.ts +61 -22
  16. package/src/janitor.test.ts +191 -169
  17. package/src/janitor.ts +141 -118
  18. package/src/listener.ts +148 -58
  19. package/src/middleware/create-activity-object.test.ts +28 -8
  20. package/src/middleware/create-activity-object.ts +16 -10
  21. package/src/middleware/expand-activity-stream.test.data.ts +331 -345
  22. package/src/middleware/expand-activity-stream.test.ts +65 -66
  23. package/src/middleware/expand-activity-stream.ts +26 -21
  24. package/src/middleware/store-credentials.test.ts +74 -60
  25. package/src/middleware/store-credentials.ts +14 -8
  26. package/src/middleware/validate.test.data.ts +240 -242
  27. package/src/middleware/validate.test.ts +39 -78
  28. package/src/middleware/validate.ts +62 -36
  29. package/src/middleware.test.ts +168 -138
  30. package/src/middleware.ts +57 -55
  31. package/src/platform-instance.test.ts +508 -214
  32. package/src/platform-instance.ts +324 -231
  33. package/src/platform.test.ts +375 -0
  34. package/src/platform.ts +306 -117
  35. package/src/process-manager.ts +75 -51
  36. package/src/routes.test.ts +43 -89
  37. package/src/routes.ts +40 -78
  38. package/src/sentry.test.ts +106 -0
  39. package/src/sentry.ts +19 -0
  40. package/src/sockethub.ts +190 -129
  41. package/src/util.ts +5 -0
  42. package/coverage/tmp/coverage-39338-1663949520416-0.json +0 -1
  43. package/dist/bootstrap/init.d.ts +0 -18
  44. package/dist/bootstrap/init.js +0 -64
  45. package/dist/bootstrap/init.js.map +0 -1
  46. package/dist/bootstrap/platforms.js +0 -75
  47. package/dist/config.d.ts +0 -12
  48. package/dist/config.js +0 -107
  49. package/dist/config.js.map +0 -1
  50. package/dist/defaults.json +0 -28
  51. package/dist/index.d.ts +0 -1
  52. package/dist/index.js +0 -29
  53. package/dist/index.js.map +0 -1
  54. package/dist/janitor.d.ts +0 -30
  55. package/dist/janitor.js +0 -120
  56. package/dist/janitor.js.map +0 -1
  57. package/dist/listener.d.ts +0 -31
  58. package/dist/listener.js +0 -94
  59. package/dist/listener.js.map +0 -1
  60. package/dist/middleware/create-activity-object.d.ts +0 -8
  61. package/dist/middleware/create-activity-object.js +0 -19
  62. package/dist/middleware/create-activity-object.js.map +0 -1
  63. package/dist/middleware/expand-activity-stream.d.ts +0 -3
  64. package/dist/middleware/expand-activity-stream.js +0 -36
  65. package/dist/middleware/expand-activity-stream.js.map +0 -1
  66. package/dist/middleware/expand-activity-stream.test.data.d.ts +0 -480
  67. package/dist/middleware/expand-activity-stream.test.data.js +0 -360
  68. package/dist/middleware/expand-activity-stream.test.data.js.map +0 -1
  69. package/dist/middleware/store-credentials.d.ts +0 -3
  70. package/dist/middleware/store-credentials.js +0 -9
  71. package/dist/middleware/store-credentials.js.map +0 -1
  72. package/dist/middleware/validate.d.ts +0 -2
  73. package/dist/middleware/validate.js +0 -56
  74. package/dist/middleware/validate.js.map +0 -1
  75. package/dist/middleware/validate.test.data.d.ts +0 -532
  76. package/dist/middleware/validate.test.data.js +0 -263
  77. package/dist/middleware/validate.test.data.js.map +0 -1
  78. package/dist/middleware.d.ts +0 -21
  79. package/dist/middleware.js +0 -56
  80. package/dist/middleware.js.map +0 -1
  81. package/dist/platform-instance.d.ts +0 -78
  82. package/dist/platform-instance.js +0 -226
  83. package/dist/platform-instance.js.map +0 -1
  84. package/dist/platform.d.ts +0 -6
  85. package/dist/platform.js +0 -176
  86. package/dist/platform.js.map +0 -1
  87. package/dist/process-manager.d.ts +0 -11
  88. package/dist/process-manager.js +0 -82
  89. package/dist/process-manager.js.map +0 -1
  90. package/dist/routes.d.ts +0 -13
  91. package/dist/routes.js +0 -83
  92. package/dist/routes.js.map +0 -1
  93. package/dist/sockethub.d.ts +0 -18
  94. package/dist/sockethub.js +0 -112
  95. package/dist/sockethub.js.map +0 -1
  96. package/src/bootstrap/platforms.js +0 -75
  97. package/test/init-suite.js +0 -41
  98. package/test/sockethub-suite.js +0 -25
  99. package/tsconfig.json +0 -18
  100. package/views/examples/dummy.ejs +0 -95
  101. package/views/examples/feeds.ejs +0 -90
  102. package/views/examples/irc.ejs +0 -239
  103. package/views/examples/shared.js +0 -72
  104. package/views/examples/xmpp.ejs +0 -217
  105. package/views/index.ejs +0 -17
@@ -1,267 +1,360 @@
1
- import {ChildProcess, fork } from 'child_process';
2
- import { join } from 'path';
3
- import { debug, Debugger } from 'debug';
4
- import {IActivityStream, CompletedJobHandler} from "@sockethub/schemas";
5
- import {JobQueue, JobDataDecrypted} from "@sockethub/data-layer";
1
+ import { type ChildProcess, fork } from "node:child_process";
2
+ import { join } from "node:path";
3
+ import debug from "debug";
6
4
 
7
- import config from "./config";
8
- import { getSocket } from "./listener";
9
- import nconf from "nconf";
5
+ import { type JobDataDecrypted, JobQueue } from "@sockethub/data-layer";
6
+ import type {
7
+ ActivityStream,
8
+ CompletedJobHandler,
9
+ InternalActivityStream,
10
+ Logger,
11
+ PlatformConfig,
12
+ } from "@sockethub/schemas";
13
+ import type { Socket } from "socket.io";
14
+
15
+ import config from "./config.js";
16
+ import { getSocket } from "./listener.js";
17
+ import { __dirname } from "./util.js";
10
18
 
11
19
  // collection of platform instances, stored by `id`
12
20
  export const platformInstances = new Map<string, PlatformInstance>();
13
21
 
14
22
  export interface PlatformInstanceParams {
15
- identifier: string;
16
- platform: string;
17
- parentId?: string;
18
- actor?: string;
23
+ identifier: string;
24
+ platform: string;
25
+ parentId?: string;
26
+ actor?: string;
19
27
  }
20
28
 
21
29
  type EnvFormat = {
22
- DEBUG?: string,
23
- REDIS_URL?: string,
24
- REDIS_HOST?: string,
25
- REDIS_PORT?: string
26
- }
30
+ DEBUG?: string;
31
+ REDIS_URL: string;
32
+ };
27
33
 
28
- interface MessageFromPlatform extends Array<string | IActivityStream>{
29
- 0: string, 1: IActivityStream, 2: string}
30
- export interface MessageFromParent extends Array<string|unknown>{0: string, 1: unknown}
34
+ interface MessageFromPlatform extends Array<string | ActivityStream> {
35
+ 0: string;
36
+ 1: ActivityStream;
37
+ 2: string;
38
+ }
31
39
 
32
- interface PlatformConfig {
33
- persist?: boolean;
34
- requireCredentials?: Array<string>;
40
+ export interface MessageFromParent extends Array<string | unknown> {
41
+ 0: string;
42
+ 1: unknown;
35
43
  }
36
44
 
37
45
  export default class PlatformInstance {
38
- id: string;
39
- flaggedForTermination = false;
40
- initialized = false;
41
- jobQueue: JobQueue;
42
- readonly global: boolean = false;
43
- readonly completedJobHandlers: Map<string, CompletedJobHandler> = new Map();
44
- readonly config: PlatformConfig = {};
45
- readonly name: string;
46
- readonly process: ChildProcess;
47
- readonly debug: Debugger;
48
- readonly parentId: string;
49
- readonly sessions: Set<string> = new Set();
50
- readonly sessionCallbacks: object = {
51
- 'close': (() => new Map())(),
52
- 'message': (() => new Map())()
53
- };
54
- private readonly actor?: string;
55
-
56
- constructor(params: PlatformInstanceParams) {
57
- this.id = params.identifier;
58
- this.name = params.platform;
59
- this.parentId = params.parentId;
60
- if (params.actor) {
61
- this.actor = params.actor;
62
- } else {
63
- this.global = true;
46
+ id: string;
47
+ flaggedForTermination = false;
48
+ queue: JobQueue;
49
+ JobQueue: typeof JobQueue;
50
+ getSocket: typeof getSocket;
51
+ readonly global: boolean = false;
52
+ readonly completedJobHandlers: Map<string, CompletedJobHandler> = new Map();
53
+ config: PlatformConfig;
54
+ readonly name: string;
55
+ process: ChildProcess;
56
+ readonly debug: Logger;
57
+ readonly parentId: string;
58
+ readonly sessions: Set<string> = new Set();
59
+ readonly sessionCallbacks: object = {
60
+ close: (() => new Map())(),
61
+ message: (() => new Map())(),
62
+ };
63
+ private readonly actor?: string;
64
+
65
+ constructor(params: PlatformInstanceParams) {
66
+ this.id = params.identifier;
67
+ this.name = params.platform;
68
+ this.parentId = params.parentId;
69
+ if (params.actor) {
70
+ this.actor = params.actor;
71
+ } else {
72
+ this.global = true;
73
+ }
74
+
75
+ this.debug = debug(`sockethub:server:platform-instance:${this.id}`);
76
+ const env: EnvFormat = {
77
+ REDIS_URL: config.get("redis:url") as string,
78
+ };
79
+ if (process.env.DEBUG) {
80
+ env.DEBUG = process.env.DEBUG;
81
+ }
82
+
83
+ this.createQueue();
84
+ this.initProcess(this.parentId, this.name, this.id, env);
85
+ this.createGetSocket();
64
86
  }
65
87
 
66
- this.debug = debug(`sockethub:server:platform-instance:${this.id}`);
67
- const env: EnvFormat = {};
68
- if (process.env.DEBUG) {
69
- env.DEBUG = process.env.DEBUG;
88
+ createQueue() {
89
+ this.JobQueue = JobQueue;
70
90
  }
71
- if (config.get('redis:url')) {
72
- env.REDIS_URL = config.get('redis:url') as string;
73
- } else {
74
- env.REDIS_HOST = config.get('redis:host') as string;
75
- env.REDIS_PORT = config.get('redis:port') as string;
91
+
92
+ initProcess(parentId: string, name: string, id: string, env: EnvFormat) {
93
+ // spin off a process
94
+ this.process = fork(
95
+ join(__dirname, "platform.js"),
96
+ [parentId, name, id],
97
+ { env: env },
98
+ );
76
99
  }
77
100
 
78
- // spin off a process
79
- this.process = fork(
80
- join(__dirname, 'platform.js'),
81
- [this.parentId, this.name, this.id],
82
- { env: env }
83
- );
84
- }
85
-
86
- /**
87
- * Destroys all references to this platform instance, internal listeners and controlled processes
88
- */
89
- public async shutdown() {
90
- this.debug('shutdown');
91
- this.flaggedForTermination = true;
92
-
93
- try {
94
- await this.process.removeAllListeners('close');
95
- await this.process.unref();
96
- this.process.kill();
97
- } catch (e) {
98
- // needs to happen
101
+ createGetSocket() {
102
+ this.getSocket = getSocket;
99
103
  }
100
104
 
101
- try {
102
- await this.jobQueue.shutdown();
103
- delete this.jobQueue;
104
- } catch (e) {
105
- // this needs to happen
105
+ /**
106
+ * Destroys all references to this platform instance, internal listeners and controlled processes
107
+ */
108
+ public async shutdown() {
109
+ this.debug("platform process shutdown");
110
+ this.flaggedForTermination = true;
111
+
112
+ try {
113
+ this.process.removeAllListeners("close");
114
+ this.process.unref();
115
+ this.process.kill();
116
+ } catch (e) {
117
+ // needs to happen
118
+ }
119
+
120
+ try {
121
+ await this.queue.shutdown();
122
+ this.queue = undefined;
123
+ } catch (e) {
124
+ // this needs to happen
125
+ }
126
+
127
+ try {
128
+ platformInstances.delete(this.id);
129
+ } catch (e) {
130
+ // this needs to happen
131
+ }
106
132
  }
107
133
 
108
- try {
109
- platformInstances.delete(this.id);
110
- } catch (e) {
111
- // this needs to happen
134
+ /**
135
+ * When jobs are completed or failed, we prepare the results and send them to the client socket
136
+ */
137
+ public initQueue(secret: string) {
138
+ this.queue = new this.JobQueue(
139
+ this.parentId,
140
+ this.id,
141
+ secret,
142
+ config.get("redis"),
143
+ );
144
+
145
+ this.queue.on(
146
+ "completed",
147
+ async (
148
+ job: JobDataDecrypted,
149
+ result: ActivityStream | undefined,
150
+ ) => {
151
+ await this.handleJobResult("completed", job, result);
152
+ },
153
+ );
154
+
155
+ this.queue.on(
156
+ "failed",
157
+ async (
158
+ job: JobDataDecrypted,
159
+ result: ActivityStream | undefined,
160
+ ) => {
161
+ await this.handleJobResult("failed", job, result);
162
+ },
163
+ );
112
164
  }
113
- }
114
-
115
- /**
116
- * When jobs are completed or failed, we prepare the results and send them to the client socket
117
- */
118
- public initQueue(secret: string) {
119
- this.jobQueue = new JobQueue(this.parentId, this.id, secret, nconf.get('redis'));
120
- this.jobQueue.initResultEvents();
121
-
122
- this.jobQueue.on('global:completed', async (job: JobDataDecrypted, result: string) => {
123
- await this.handleJobResult('completed', job, result);
124
- });
125
-
126
- this.jobQueue.on('global:failed', async (job: JobDataDecrypted, result: string) => {
127
- await this.handleJobResult('failed', job, result);
128
- });
129
- }
130
-
131
- /**
132
- * Register listener to be called when the process emits a message.
133
- * @param sessionId ID of socket connection that will receive messages from platform emits
134
- */
135
- public registerSession(sessionId: string) {
136
- if (! this.sessions.has(sessionId)) {
137
- this.sessions.add(sessionId);
138
- for (const type of Object.keys(this.sessionCallbacks)) {
139
- const cb = this.callbackFunction(type, sessionId);
140
- this.process.on(type, cb);
141
- this.sessionCallbacks[type].set(sessionId, cb);
142
- }
165
+
166
+ /**
167
+ * Register listener to be called when the process emits a message.
168
+ * @param sessionId ID of socket connection that will receive messages from platform emits
169
+ */
170
+ public registerSession(sessionId: string) {
171
+ if (!this.sessions.has(sessionId)) {
172
+ this.sessions.add(sessionId);
173
+ for (const type of Object.keys(this.sessionCallbacks)) {
174
+ const cb = this.callbackFunction(type, sessionId);
175
+ this.process.on(type, cb);
176
+ this.sessionCallbacks[type].set(sessionId, cb);
177
+ }
178
+ }
143
179
  }
144
- }
145
-
146
- /**
147
- * Sends a message to client (user), can be registered with an event emitted from the platform
148
- * process.
149
- * @param sessionId ID of the socket connection to send the message to
150
- * @param msg ActivityStream object to send to client
151
- */
152
- public sendToClient(sessionId: string, msg: IActivityStream) {
153
- getSocket(sessionId).then((socket) => {
154
- try {
155
- // this property should never be exposed externally
156
- delete msg.sessionSecret;
157
- } finally {
158
- msg.context = this.name;
159
- if ((msg.type === 'error') && (typeof msg.actor === 'undefined') && (this.actor)) {
160
- // ensure an actor is present if not otherwise defined
161
- msg.actor = { id: this.actor, type: 'unknown' };
180
+
181
+ /**
182
+ * Sends a message to client (user), can be registered with an event emitted from the platform
183
+ * process.
184
+ * @param sessionId ID of the socket connection to send the message to
185
+ * @param msg ActivityStream object to send to client
186
+ */
187
+ public async sendToClient(sessionId: string, msg: InternalActivityStream) {
188
+ return this.getSocket(sessionId).then(
189
+ (socket: Socket) => {
190
+ try {
191
+ // this property should never be exposed externally
192
+ // biome-ignore lint/performance/noDelete: <explanation>
193
+ delete msg.sessionSecret;
194
+ } finally {
195
+ msg.context = this.name;
196
+ if (
197
+ msg.type === "error" &&
198
+ typeof msg.actor === "undefined" &&
199
+ this.actor
200
+ ) {
201
+ // ensure an actor is present if not otherwise defined
202
+ msg.actor = { id: this.actor, type: "unknown" };
203
+ }
204
+ socket.emit("message", msg as ActivityStream);
205
+ }
206
+ },
207
+ (err) => this.debug(`sendToClient ${err}`),
208
+ );
209
+ }
210
+
211
+ // send message to every connected socket associated with this platform instance.
212
+ private broadcastToSharedPeers(sessionId: string, msg: ActivityStream) {
213
+ for (const sid of this.sessions.values()) {
214
+ if (sid !== sessionId) {
215
+ this.debug(`broadcasting message to ${sid}`);
216
+ this.sendToClient(sid, msg);
217
+ }
162
218
  }
163
- socket.emit('message', msg);
164
- }
165
- }, (err) => this.debug(`sendToClient ${err}`));
166
- }
167
-
168
- // send message to every connected socket associated with this platform instance.
169
- private async broadcastToSharedPeers(sessionId: string, msg: IActivityStream) {
170
- for (const sid of this.sessions.values()) {
171
- if (sid !== sessionId) {
172
- this.debug(`broadcasting message to ${sid}`);
173
- await this.sendToClient(sid, msg);
174
- }
175
219
  }
176
- }
177
220
 
178
- // handle job results coming in on the queue from platform instances
179
- private async handleJobResult(type: string, job: JobDataDecrypted, result) {
180
- const msg = job.msg;
181
- if (type === 'failed') {
182
- msg.error = result ? result : "job failed for unknown reason";
183
- this.debug(`${job.title} ${type}: ${msg.error}`);
221
+ // handle job results coming in on the queue from platform instances
222
+ private async handleJobResult(
223
+ state: string,
224
+ job: JobDataDecrypted,
225
+ result: ActivityStream | undefined,
226
+ ) {
227
+ let payload = result; // some platforms return new AS objects as result
228
+ if (state === "failed") {
229
+ payload = job.msg; // failures always use original AS job object
230
+ payload.error = result
231
+ ? result.toString()
232
+ : "job failed for unknown reason";
233
+ }
234
+ this.debug(
235
+ `${job.title} ${state}${payload?.error ? `: ${payload.error}` : ""}`,
236
+ );
237
+
238
+ if (!payload || typeof payload === "string") {
239
+ payload = job.msg;
240
+ }
241
+
242
+ // send result to client
243
+ const callback = this.completedJobHandlers.get(job.title);
244
+ if (callback) {
245
+ callback(payload);
246
+ this.completedJobHandlers.delete(job.title);
247
+ } else {
248
+ await this.sendToClient(job.sessionId, payload);
249
+ }
250
+
251
+ if (payload) {
252
+ // let all related peers know of result as an independent message
253
+ // (not as part of a job completion, or failure)
254
+ this.broadcastToSharedPeers(job.sessionId, payload);
255
+ }
184
256
 
257
+ // persistent
258
+ if (
259
+ this.config.persist &&
260
+ this.config.requireCredentials?.includes(job.msg.type)
261
+ ) {
262
+ if (state === "failed") {
263
+ // Only terminate if platform is not yet initialized
264
+ // If already initialized, credential failures are non-fatal (wrong session credentials)
265
+ if (!this.config.initialized) {
266
+ this.debug(
267
+ `critical job type ${job.msg.type} failed during initialization, flagging for termination`,
268
+ );
269
+ await this.queue.pause();
270
+ this.config.initialized = false;
271
+ this.flaggedForTermination = true;
272
+ } else {
273
+ this.debug(
274
+ `credential job ${job.msg.type} failed on initialized platform, not flagged for termination`,
275
+ );
276
+ // Platform stays alive - error sent to client via sendToClient above
277
+ }
278
+ } else {
279
+ this.debug("persistent platform initialized");
280
+ await this.queue.resume();
281
+ this.config.initialized = true;
282
+ this.flaggedForTermination = false;
283
+ }
284
+ }
185
285
  }
186
286
 
187
- // send result to client
188
- const callback = this.completedJobHandlers.get(job.title);
189
- if (callback) {
190
- callback(msg);
191
- this.completedJobHandlers.delete(job.title);
192
- } else {
193
- await this.sendToClient(job.sessionId, msg);
287
+ /**
288
+ * Sends error message to client and clears all references to this class.
289
+ * @param sessionId
290
+ * @param errorMessage
291
+ */
292
+ private async reportError(sessionId: string, errorMessage: string) {
293
+ const errorObject: ActivityStream = {
294
+ context: this.name,
295
+ type: "error",
296
+ actor: { id: this.actor, type: "unknown" },
297
+ error: errorMessage,
298
+ };
299
+
300
+ // Only attempt to send to client if we have a valid session
301
+ try {
302
+ if (sessionId && this.sessions.has(sessionId)) {
303
+ await this.sendToClient(sessionId, errorObject);
304
+ }
305
+ } catch (err) {
306
+ this.debug(`Failed to send error to client: ${err.message}`);
307
+ }
308
+
309
+ this.sessions.clear();
310
+ await this.shutdown();
194
311
  }
195
312
 
196
- // let all related peers know of result as an independent message
197
- // (not as part of a job completion, or failure)
198
- await this.broadcastToSharedPeers(job.sessionId, msg);
313
+ /**
314
+ * Updates the instance with a new identifier, updating the platformInstances mapping as well.
315
+ * @param identifier
316
+ */
317
+ private updateIdentifier(identifier: string) {
318
+ platformInstances.delete(this.id);
319
+ this.id = identifier;
320
+ platformInstances.set(this.id, this);
321
+ }
199
322
 
200
- if ((this.config.persist) && (this.config.requireCredentials.includes(job.msg.type))) {
201
- if (type === 'failed') {
202
- this.debug(`critical job type ${job.msg.type} failed, flagging for termination`);
203
- await this.jobQueue.pause();
204
- this.initialized = false;
205
- this.flaggedForTermination = true;
206
- } else {
207
- await this.jobQueue.resume();
208
- this.initialized = true;
209
- this.flaggedForTermination = false;
210
- }
323
+ /**
324
+ * Generates a function tied to a given client session (socket connection), the generated
325
+ * function will be called for each session ID registered, for every platform emit.
326
+ * @param listener
327
+ * @param sessionId
328
+ */
329
+ private callbackFunction(listener: string, sessionId: string) {
330
+ const funcs = {
331
+ close: async (e: object) => {
332
+ this.debug(`close event triggered ${this.id}: ${e}`);
333
+ // Check if process is still connected before attempting error reporting
334
+ if (this.process?.connected && !this.flaggedForTermination) {
335
+ await this.reportError(
336
+ sessionId,
337
+ `Error: session thread closed unexpectedly: ${e}`,
338
+ );
339
+ } else {
340
+ this.debug(
341
+ "Process already disconnected or flagged for termination, skipping error report",
342
+ );
343
+ await this.shutdown();
344
+ }
345
+ },
346
+ message: async ([first, second, third]: MessageFromPlatform) => {
347
+ if (first === "updateActor") {
348
+ // We need to update the key to the store in order to find it in the future.
349
+ this.updateIdentifier(third);
350
+ } else if (first === "error" && typeof second === "string") {
351
+ await this.reportError(sessionId, second);
352
+ } else {
353
+ // treat like a message to clients
354
+ await this.sendToClient(sessionId, second);
355
+ }
356
+ },
357
+ };
358
+ return funcs[listener];
211
359
  }
212
- }
213
-
214
- /**
215
- * Sends error message to client and clears all references to this class.
216
- * @param sessionId
217
- * @param errorMessage
218
- */
219
- private async reportError(sessionId: string, errorMessage: string) {
220
- const errorObject: IActivityStream = {
221
- context: this.name,
222
- type: 'error',
223
- actor: { id: this.actor, type: 'unknown' },
224
- error: errorMessage
225
- };
226
- this.sendToClient(sessionId, errorObject);
227
- this.sessions.clear();
228
- await this.shutdown();
229
- }
230
-
231
- /**
232
- * Updates the instance with a new identifier, updating the platformInstances mapping as well.
233
- * @param identifier
234
- */
235
- private updateIdentifier(identifier: string) {
236
- platformInstances.delete(this.id);
237
- this.id = identifier;
238
- platformInstances.set(this.id, this);
239
- }
240
-
241
- /**
242
- * Generates a function tied to a given client session (socket connection), the generated
243
- * function will be called for each session ID registered, for every platform emit.
244
- * @param listener
245
- * @param sessionId
246
- */
247
- private callbackFunction(listener: string, sessionId: string) {
248
- const funcs = {
249
- 'close': async (e: object) => {
250
- this.debug(`close even triggered ${this.id}: ${e}`);
251
- await this.reportError(sessionId, `Error: session thread closed unexpectedly: ${e}`);
252
- },
253
- 'message': async ([first, second, third]: MessageFromPlatform) => {
254
- if (first === 'updateActor') {
255
- // We need to update the key to the store in order to find it in the future.
256
- this.updateIdentifier(third);
257
- } else if ((first === 'error') && (typeof second === "string")) {
258
- await this.reportError(sessionId, second);
259
- } else {
260
- // treat like a message to clients
261
- this.sendToClient(sessionId, second);
262
- }
263
- }
264
- };
265
- return funcs[listener];
266
- }
267
360
  }