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

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 (95) hide show
  1. package/coverage/tmp/coverage-39338-1663949520416-0.json +1 -0
  2. package/dist/bootstrap/init.js +2 -1
  3. package/dist/bootstrap/init.js.map +1 -1
  4. package/dist/config.d.ts +7 -1
  5. package/dist/config.js +6 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/index.d.ts +1 -2
  8. package/dist/index.js +7 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/janitor.d.ts +27 -12
  11. package/dist/janitor.js +97 -66
  12. package/dist/janitor.js.map +1 -1
  13. package/dist/listener.d.ts +4 -1
  14. package/dist/listener.js +8 -5
  15. package/dist/listener.js.map +1 -1
  16. package/dist/middleware/create-activity-object.d.ts +3 -1
  17. package/dist/middleware/create-activity-object.js.map +1 -1
  18. package/dist/middleware/expand-activity-stream.d.ts +2 -1
  19. package/dist/middleware/expand-activity-stream.js +4 -1
  20. package/dist/middleware/expand-activity-stream.js.map +1 -1
  21. package/dist/middleware/expand-activity-stream.test.data.js +4 -4
  22. package/dist/middleware/expand-activity-stream.test.data.js.map +1 -1
  23. package/dist/middleware/store-credentials.d.ts +3 -3
  24. package/dist/middleware/store-credentials.js +2 -12
  25. package/dist/middleware/store-credentials.js.map +1 -1
  26. package/dist/middleware/validate.d.ts +2 -2
  27. package/dist/middleware/validate.js +1 -3
  28. package/dist/middleware/validate.js.map +1 -1
  29. package/dist/middleware/validate.test.data.js +5 -5
  30. package/dist/middleware/validate.test.data.js.map +1 -1
  31. package/dist/middleware.d.ts +14 -3
  32. package/dist/middleware.js +3 -1
  33. package/dist/middleware.js.map +1 -1
  34. package/dist/platform-instance.d.ts +11 -10
  35. package/dist/platform-instance.js +77 -62
  36. package/dist/platform-instance.js.map +1 -1
  37. package/dist/platform.js +93 -104
  38. package/dist/platform.js.map +1 -1
  39. package/dist/process-manager.js +7 -3
  40. package/dist/process-manager.js.map +1 -1
  41. package/dist/routes.d.ts +1 -1
  42. package/dist/routes.js +1 -1
  43. package/dist/routes.js.map +1 -1
  44. package/dist/sockethub.d.ts +1 -22
  45. package/dist/sockethub.js +19 -26
  46. package/dist/sockethub.js.map +1 -1
  47. package/package.json +30 -36
  48. package/src/bootstrap/init.d.ts +17 -7
  49. package/src/bootstrap/init.ts +2 -1
  50. package/src/config.ts +9 -1
  51. package/src/index.ts +3 -2
  52. package/src/janitor.test.ts +189 -0
  53. package/src/janitor.ts +110 -65
  54. package/src/listener.ts +11 -7
  55. package/src/middleware/create-activity-object.ts +5 -2
  56. package/src/middleware/expand-activity-stream.test.data.ts +5 -5
  57. package/src/middleware/expand-activity-stream.test.ts +2 -2
  58. package/src/middleware/expand-activity-stream.ts +12 -7
  59. package/src/middleware/store-credentials.test.ts +4 -6
  60. package/src/middleware/store-credentials.ts +8 -14
  61. package/src/middleware/validate.test.data.ts +5 -5
  62. package/src/middleware/validate.ts +4 -6
  63. package/src/middleware.ts +28 -11
  64. package/src/platform-instance.test.ts +18 -18
  65. package/src/platform-instance.ts +98 -73
  66. package/src/platform.ts +79 -101
  67. package/src/process-manager.ts +1 -1
  68. package/src/routes.ts +3 -2
  69. package/src/sockethub.ts +29 -57
  70. package/views/examples/dummy.ejs +3 -1
  71. package/views/examples/shared.js +1 -1
  72. package/views/examples/xmpp.ejs +60 -34
  73. package/coverage/tmp/coverage-93126-1649152190997-0.json +0 -1
  74. package/dist/common.d.ts +0 -3
  75. package/dist/common.js +0 -20
  76. package/dist/common.js.map +0 -1
  77. package/dist/crypto.d.ts +0 -10
  78. package/dist/crypto.js +0 -38
  79. package/dist/crypto.js.map +0 -1
  80. package/dist/store.d.ts +0 -5
  81. package/dist/store.js +0 -17
  82. package/dist/store.js.map +0 -1
  83. package/src/common.test.ts +0 -54
  84. package/src/common.ts +0 -14
  85. package/src/config.d.ts +0 -2
  86. package/src/crypto.d.ts +0 -5
  87. package/src/crypto.test.ts +0 -41
  88. package/src/crypto.ts +0 -41
  89. package/src/janitor.d.ts +0 -8
  90. package/src/middleware/validate.d.ts +0 -1
  91. package/src/middleware.d.ts +0 -21
  92. package/src/sockethub.d.ts +0 -1
  93. package/src/store.test.ts +0 -28
  94. package/src/store.ts +0 -17
  95. package/test/queue.functional.test.js +0 -0
@@ -1,16 +1,10 @@
1
- import { IActivityStream } from "@sockethub/schemas";
2
- import { ISecureStoreInstance } from "../store";
1
+ import {IActivityStream, CallbackInterface} from "@sockethub/schemas";
2
+ import { CredentialsStore } from "@sockethub/data-layer";
3
3
 
4
- export default function storeCredentials(store: ISecureStoreInstance, sessionLog: Function) {
5
- return (creds: IActivityStream, done: Function) => {
6
- store.save(creds.actor.id, creds, (err) => {
7
- if (err) {
8
- sessionLog('error saving credentials to store ' + err);
9
- done(err);
10
- } else {
11
- sessionLog('credentials encrypted and saved');
12
- done();
13
- }
14
- });
4
+ export default function storeCredentials(
5
+ credentialsStore: CredentialsStore
6
+ ) {
7
+ return (creds: IActivityStream, done: CallbackInterface) => {
8
+ credentialsStore.save(creds.actor.id, creds, done);
15
9
  };
16
- };
10
+ }
@@ -130,10 +130,10 @@ export default [
130
130
  "image":{
131
131
  "height":250,
132
132
  "mediaType":"image/jpeg",
133
- "url":"http://example.org/image.jpg",
133
+ "url":"https://example.org/image.jpg",
134
134
  "width":250
135
135
  },
136
- "url":"http://sockethub.org"
136
+ "url":"https://sockethub.org"
137
137
  },
138
138
  "output":"same"
139
139
  },
@@ -145,7 +145,7 @@ export default [
145
145
  "id":"irc://sh-9K3Vk@irc.freenode.net",
146
146
  "type":"person",
147
147
  "name":"sh-9K3Vk",
148
- "url":"http://sockethub.org"
148
+ "url":"https://sockethub.org"
149
149
  },
150
150
  "output":"same"
151
151
  },
@@ -211,7 +211,7 @@ export default [
211
211
  "context":"fake",
212
212
  "target": { "id": "irc://irc.dooder.net/a-room", "type": "room" }
213
213
  },
214
- "error": "Error: activity stream: must have required property \'type\'"
214
+ "error": "Error: activity stream: must have required property 'type'"
215
215
  },
216
216
  {
217
217
  "name":"invalid context property",
@@ -234,7 +234,7 @@ export default [
234
234
  "context":"fake",
235
235
  "target": { "id": "irc://irc.dooder.net/a-room", "type": "room" }
236
236
  },
237
- "error": "Error: activity stream: must have required property \'actor\'"
237
+ "error": "Error: activity stream: must have required property 'actor'"
238
238
  },
239
239
  {
240
240
  "name":"traditional message",
@@ -2,10 +2,8 @@
2
2
  * responsible for handling the validation and expansion (when applicable) of all incoming objects
3
3
  */
4
4
  import debug from 'debug';
5
- import schemas from '@sockethub/schemas';
6
- import { IActivityStream } from "@sockethub/schemas";
5
+ import schemas, {IActivityStream, CallbackActivityStreamInterface} from '@sockethub/schemas';
7
6
 
8
- // @ts-ignore
9
7
  import init from "../bootstrap/init";
10
8
 
11
9
  init.platforms.forEach((platform) => {
@@ -18,8 +16,8 @@ init.platforms.forEach((platform) => {
18
16
  // called when registered with the middleware function, define the type of validation
19
17
  // that will be called when the middleware eventually does.
20
18
  export default function validate(type: string, sockethubId: string) {
21
- const sessionLog = debug(`sockethub:validate:${sockethubId}`);
22
- return (msg: IActivityStream, done: Function) => {
19
+ const sessionLog = debug(`sockethub:server:validate:${sockethubId}`);
20
+ return (msg: IActivityStream, done: CallbackActivityStreamInterface) => {
23
21
  sessionLog('applying schema validation for ' + type);
24
22
  if (type === 'activity-object') {
25
23
  const err = schemas.validateActivityObject(msg);
@@ -46,4 +44,4 @@ export default function validate(type: string, sockethubId: string) {
46
44
  }
47
45
  }
48
46
  };
49
- };
47
+ }
package/src/middleware.ts CHANGED
@@ -1,28 +1,43 @@
1
1
  import { debug } from 'debug';
2
+ import {IActivityStream} from "@sockethub/schemas";
2
3
 
3
4
  export default function middleware(name: string): MiddlewareChain {
4
5
  return new MiddlewareChain(name);
5
6
  }
6
7
 
8
+ export interface MiddlewareChainInterface {
9
+ (error: IActivityStream | Error,
10
+ data?: IActivityStream | MiddlewareChainInterface,
11
+ next?: MiddlewareChainInterface): void;
12
+ }
13
+
14
+ interface ErrorHandlerInterface {
15
+ (err: Error, data?: unknown, cb?: unknown): void;
16
+ }
17
+
18
+ export interface LogErrorInterface {
19
+ (msg: Error): void;
20
+ }
21
+
7
22
  export class MiddlewareChain {
8
23
  public name: string;
9
- private chain: Array<Function> = [];
10
- private errHandler: Function = (err: Error) => { throw err; };
11
- private logger: Function;
24
+ private chain: Array<MiddlewareChainInterface> = [];
25
+ private errHandler: ErrorHandlerInterface = (err: Error) => { throw err; };
26
+ private readonly logger: LogErrorInterface;
12
27
 
13
28
  constructor(name: string) {
14
29
  this.name = name;
15
30
  this.logger = debug(`sockethub:middleware:${name}`);
16
31
  }
17
32
 
18
- use(func: Function): this {
33
+ use(func: ErrorHandlerInterface | MiddlewareChainInterface): this {
19
34
  if (typeof func !== 'function') {
20
35
  throw new Error('middleware use() can only take a function as an argument');
21
36
  }
22
37
  if (func.length === 3) {
23
- this.errHandler = func;
38
+ this.errHandler = func as ErrorHandlerInterface;
24
39
  } else if (func.length === 2) {
25
- this.chain.push(func);
40
+ this.chain.push(func as MiddlewareChainInterface);
26
41
  } else {
27
42
  throw new Error(
28
43
  'middleware function provided with incorrect number of params: ' + func.length);
@@ -31,19 +46,21 @@ export class MiddlewareChain {
31
46
  }
32
47
 
33
48
  done() {
34
- return (data: any, callback: Function) => {
49
+ return (data: unknown, callback: MiddlewareChainInterface) => {
35
50
  let position = 0;
36
51
  if (typeof callback !== 'function') {
37
- callback = () => {};
52
+ callback = () => {
53
+ // ensure we have a callback function
54
+ };
38
55
  }
39
- const next = (_data: any) => {
56
+ const next = (_data: unknown) => {
40
57
  if (_data instanceof Error) {
41
58
  this.logger(_data);
42
59
  this.errHandler(_data, data, callback);
43
60
  } else if (typeof this.chain[position] === 'function') {
44
- this.chain[position++](_data, next);
61
+ this.chain[position++](_data as IActivityStream, next);
45
62
  } else {
46
- callback(_data);
63
+ callback(_data as IActivityStream);
47
64
  }
48
65
  };
49
66
  next(data);
@@ -19,13 +19,13 @@ describe("PlatformInstance", () => {
19
19
  getSocketFake = sinon.fake.resolves(socketMock);
20
20
 
21
21
  const PlatformInstanceMod = proxyquire('./platform-instance', {
22
- 'bull': sandbox.stub().returns({
23
- on: sandbox.stub()
24
- }),
25
- './store': {
26
- redisConfig: {
27
- createClient: () => {}
28
- }
22
+ '@sockethub/data-layer': {
23
+ JobQueue: sandbox.stub().returns({
24
+ shutdown: sandbox.stub(),
25
+ on: sandbox.stub(),
26
+ getJob: sandbox.stub(),
27
+ initResultEvents: sandbox.stub()
28
+ })
29
29
  },
30
30
  'child_process': {
31
31
  fork: forkFake,
@@ -51,7 +51,7 @@ describe("PlatformInstance", () => {
51
51
  });
52
52
 
53
53
  describe('private instance per-actor', () => {
54
- it("is set as non-global when an actor is provided", () => {
54
+ it("is set as non-global when an actor is provided", async () => {
55
55
  const pi = new PlatformInstance({
56
56
  identifier: 'id',
57
57
  platform: 'name',
@@ -60,7 +60,7 @@ describe("PlatformInstance", () => {
60
60
  });
61
61
  expect(pi.global).to.be.equal(false);
62
62
  sandbox.assert.calledWith(forkFake, FORK_PATH, ['parentId', 'name', 'id']);
63
- pi.destroy();
63
+ await pi.shutdown();
64
64
  });
65
65
  });
66
66
 
@@ -82,8 +82,8 @@ describe("PlatformInstance", () => {
82
82
  };
83
83
  });
84
84
 
85
- afterEach(() => {
86
- pi.destroy();
85
+ afterEach(async () => {
86
+ await pi.shutdown();
87
87
  });
88
88
 
89
89
  it('has expected properties', () => {
@@ -123,23 +123,23 @@ describe("PlatformInstance", () => {
123
123
  expect(pi.sessions.has('my session id')).to.be.equal(true);
124
124
  pi.reportError('my session id', 'an error message');
125
125
  pi.sendToClient = sandbox.stub();
126
- pi.destroy = sandbox.stub();
126
+ pi.shutdown = sandbox.stub();
127
127
  expect(pi.sessions.size).to.be.equal(0);
128
128
  });
129
129
  });
130
130
 
131
131
  it('initializes the job queue', () => {
132
- expect(pi.queue).to.be.undefined;
132
+ expect(pi.jobQueue).to.be.undefined;
133
133
  pi.initQueue('a secret');
134
- expect(pi.queue).to.be.ok;
134
+ expect(pi.jobQueue).to.be.ok;
135
135
  });
136
136
 
137
- it("cleans up its references when destroyed", async () => {
137
+ it("cleans up its references when shutdown", async () => {
138
138
  pi.initQueue('a secret');
139
- expect(pi.queue).to.be.ok;
139
+ expect(pi.jobQueue).to.be.ok;
140
140
  expect(platformInstances.has('platform identifier')).to.be.true;
141
- await pi.destroy();
142
- expect(pi.queue).not.to.be.ok;
141
+ await pi.shutdown();
142
+ expect(pi.jobQueue).not.to.be.ok;
143
143
  expect(platformInstances.has('platform identifier')).to.be.false;
144
144
  });
145
145
 
@@ -1,13 +1,12 @@
1
- import { ChildProcess, fork } from 'child_process';
1
+ import {ChildProcess, fork } from 'child_process';
2
2
  import { join } from 'path';
3
3
  import { debug, Debugger } from 'debug';
4
- import Queue from 'bull';
5
- import { IActivityStream } from '@sockethub/schemas';
4
+ import {IActivityStream, CompletedJobHandler} from "@sockethub/schemas";
5
+ import {JobQueue, JobDataDecrypted} from "@sockethub/data-layer";
6
6
 
7
7
  import config from "./config";
8
- import { JobDataDecrypted, JobEncrypted } from "./sockethub";
9
8
  import { getSocket } from "./listener";
10
- import { decryptJobData } from "./common";
9
+ import nconf from "nconf";
11
10
 
12
11
  // collection of platform instances, stored by `id`
13
12
  export const platformInstances = new Map<string, PlatformInstance>();
@@ -19,9 +18,16 @@ export interface PlatformInstanceParams {
19
18
  actor?: string;
20
19
  }
21
20
 
21
+ type EnvFormat = {
22
+ DEBUG?: string,
23
+ REDIS_URL?: string,
24
+ REDIS_HOST?: string,
25
+ REDIS_PORT?: string
26
+ }
27
+
22
28
  interface MessageFromPlatform extends Array<string | IActivityStream>{
23
29
  0: string, 1: IActivityStream, 2: string}
24
- export interface MessageFromParent extends Array<string|any>{0: string, 1: any}
30
+ export interface MessageFromParent extends Array<string|unknown>{0: string, 1: unknown}
25
31
 
26
32
  interface PlatformConfig {
27
33
  persist?: boolean;
@@ -29,11 +35,13 @@ interface PlatformConfig {
29
35
  }
30
36
 
31
37
  export default class PlatformInstance {
32
- flaggedForTermination: boolean = false;
33
38
  id: string;
34
- queue: Queue;
35
- completedJobHandlers: Map<string, Function> = new Map();
36
- config: PlatformConfig = {};
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 = {};
37
45
  readonly name: string;
38
46
  readonly process: ChildProcess;
39
47
  readonly debug: Debugger;
@@ -43,7 +51,6 @@ export default class PlatformInstance {
43
51
  'close': (() => new Map())(),
44
52
  'message': (() => new Map())()
45
53
  };
46
- public readonly global?: boolean = false;
47
54
  private readonly actor?: string;
48
55
 
49
56
  constructor(params: PlatformInstanceParams) {
@@ -56,60 +63,68 @@ export default class PlatformInstance {
56
63
  this.global = true;
57
64
  }
58
65
 
59
- this.debug = debug(`sockethub:platform-instance:${this.id}`);
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;
70
+ }
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;
76
+ }
77
+
60
78
  // spin off a process
61
- const env = config.get('redis:url') ? { REDIS_URL: config.get('redis:url') }
62
- : { REDIS_HOST: config.get('redis:host'), REDIS_PORT: config.get('redis:port') };
63
79
  this.process = fork(
64
80
  join(__dirname, 'platform.js'),
65
81
  [this.parentId, this.name, this.id],
66
- { env: env });
82
+ { env: env }
83
+ );
67
84
  }
68
85
 
69
86
  /**
70
87
  * Destroys all references to this platform instance, internal listeners and controlled processes
71
88
  */
72
- public async destroy() {
73
- this.debug(`cleaning up`);
89
+ public async shutdown() {
90
+ this.debug('shutdown');
74
91
  this.flaggedForTermination = true;
92
+
75
93
  try {
76
- await this.queue.removeAllListeners();
77
- } catch (e) { }
78
- try {
79
- await this.queue.obliterate({ force: true });
80
- } catch (e) { }
81
- try {
82
- delete this.queue;
83
94
  await this.process.removeAllListeners('close');
84
95
  await this.process.unref();
85
- await this.process.kill();
86
- } catch (e) { }
87
- platformInstances.delete(this.id);
96
+ this.process.kill();
97
+ } catch (e) {
98
+ // needs to happen
99
+ }
100
+
101
+ try {
102
+ await this.jobQueue.shutdown();
103
+ delete this.jobQueue;
104
+ } catch (e) {
105
+ // this needs to happen
106
+ }
107
+
108
+ try {
109
+ platformInstances.delete(this.id);
110
+ } catch (e) {
111
+ // this needs to happen
112
+ }
88
113
  }
89
114
 
90
115
  /**
91
116
  * When jobs are completed or failed, we prepare the results and send them to the client socket
92
117
  */
93
118
  public initQueue(secret: string) {
94
- this.queue = new Queue(this.parentId + this.id, { redis: config.get('redis') });
95
-
96
- this.queue.on('global:completed', (jobId, resultString) => {
97
- const result = resultString ? JSON.parse(resultString) : "";
98
- this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
99
- await this.handleJobResult('completed', decryptJobData(job, secret), result);
100
- await job.remove();
101
- });
102
- });
119
+ this.jobQueue = new JobQueue(this.parentId, this.id, secret, nconf.get('redis'));
120
+ this.jobQueue.initResultEvents();
103
121
 
104
- this.queue.on('global:error', (jobId, result) => {
105
- this.debug("unknown queue error", jobId, result);
122
+ this.jobQueue.on('global:completed', async (job: JobDataDecrypted, result: string) => {
123
+ await this.handleJobResult('completed', job, result);
106
124
  });
107
125
 
108
- this.queue.on('global:failed', (jobId, result) => {
109
- this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
110
- await this.handleJobResult('failed', decryptJobData(job, secret), result);
111
- await job.remove();
112
- });
126
+ this.jobQueue.on('global:failed', async (job: JobDataDecrypted, result: string) => {
127
+ await this.handleJobResult('failed', job, result);
113
128
  });
114
129
  }
115
130
 
@@ -120,7 +135,7 @@ export default class PlatformInstance {
120
135
  public registerSession(sessionId: string) {
121
136
  if (! this.sessions.has(sessionId)) {
122
137
  this.sessions.add(sessionId);
123
- for (let type of Object.keys(this.sessionCallbacks)) {
138
+ for (const type of Object.keys(this.sessionCallbacks)) {
124
139
  const cb = this.callbackFunction(type, sessionId);
125
140
  this.process.on(type, cb);
126
141
  this.sessionCallbacks[type].set(sessionId, cb);
@@ -139,19 +154,20 @@ export default class PlatformInstance {
139
154
  try {
140
155
  // this property should never be exposed externally
141
156
  delete msg.sessionSecret;
142
- } catch (e) {}
143
- msg.context = this.name;
144
- if ((msg.type === 'error') && (typeof msg.actor === 'undefined') && (this.actor)) {
145
- // ensure an actor is present if not otherwise defined
146
- msg.actor = { id: this.actor, type: 'unknown' };
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' };
162
+ }
163
+ socket.emit('message', msg);
147
164
  }
148
- socket.emit('message', msg);
149
165
  }, (err) => this.debug(`sendToClient ${err}`));
150
166
  }
151
167
 
152
168
  // send message to every connected socket associated with this platform instance.
153
169
  private async broadcastToSharedPeers(sessionId: string, msg: IActivityStream) {
154
- for (let sid of this.sessions.values()) {
170
+ for (const sid of this.sessions.values()) {
155
171
  if (sid !== sessionId) {
156
172
  this.debug(`broadcasting message to ${sid}`);
157
173
  await this.sendToClient(sid, msg);
@@ -160,30 +176,39 @@ export default class PlatformInstance {
160
176
  }
161
177
 
162
178
  // handle job results coming in on the queue from platform instances
163
- private async handleJobResult(type: string, jobData: JobDataDecrypted, result) {
164
- this.debug(`${type} job ${jobData.title}`);
165
- delete jobData.msg.sessionSecret;
166
- let msg = jobData.msg;
179
+ private async handleJobResult(type: string, job: JobDataDecrypted, result) {
180
+ const msg = job.msg;
167
181
  if (type === 'failed') {
168
182
  msg.error = result ? result : "job failed for unknown reason";
169
- if ((this.config.persist) && (this.config.requireCredentials.includes(jobData.msg.type))) {
170
- this.debug(`critical job type ${jobData.msg.type} failed, terminating platform instance`);
171
- await this.destroy();
172
- }
183
+ this.debug(`${job.title} ${type}: ${msg.error}`);
184
+
173
185
  }
174
186
 
175
187
  // send result to client
176
- const callback = this.completedJobHandlers.get(jobData.title);
188
+ const callback = this.completedJobHandlers.get(job.title);
177
189
  if (callback) {
178
190
  callback(msg);
179
- this.completedJobHandlers.delete(jobData.title);
191
+ this.completedJobHandlers.delete(job.title);
180
192
  } else {
181
- await this.sendToClient(jobData.sessionId, msg);
193
+ await this.sendToClient(job.sessionId, msg);
182
194
  }
183
195
 
184
196
  // let all related peers know of result as an independent message
185
197
  // (not as part of a job completion, or failure)
186
- await this.broadcastToSharedPeers(jobData.sessionId, msg);
198
+ await this.broadcastToSharedPeers(job.sessionId, msg);
199
+
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
+ }
211
+ }
187
212
  }
188
213
 
189
214
  /**
@@ -191,7 +216,7 @@ export default class PlatformInstance {
191
216
  * @param sessionId
192
217
  * @param errorMessage
193
218
  */
194
- private async reportError(sessionId: string, errorMessage: any) {
219
+ private async reportError(sessionId: string, errorMessage: string) {
195
220
  const errorObject: IActivityStream = {
196
221
  context: this.name,
197
222
  type: 'error',
@@ -200,7 +225,7 @@ export default class PlatformInstance {
200
225
  };
201
226
  this.sendToClient(sessionId, errorObject);
202
227
  this.sessions.clear();
203
- await this.destroy();
228
+ await this.shutdown();
204
229
  }
205
230
 
206
231
  /**
@@ -221,19 +246,19 @@ export default class PlatformInstance {
221
246
  */
222
247
  private callbackFunction(listener: string, sessionId: string) {
223
248
  const funcs = {
224
- 'close': (e: object) => {
249
+ 'close': async (e: object) => {
225
250
  this.debug(`close even triggered ${this.id}: ${e}`);
226
- this.reportError(sessionId, `Error: session thread closed unexpectedly: ${e}`);
251
+ await this.reportError(sessionId, `Error: session thread closed unexpectedly: ${e}`);
227
252
  },
228
- 'message': (data: MessageFromPlatform) => {
229
- if (data[0] === 'updateActor') {
253
+ 'message': async ([first, second, third]: MessageFromPlatform) => {
254
+ if (first === 'updateActor') {
230
255
  // We need to update the key to the store in order to find it in the future.
231
- this.updateIdentifier(data[2]);
232
- } else if (data[0] === 'error') {
233
- this.reportError(sessionId, data[1]);
256
+ this.updateIdentifier(third);
257
+ } else if ((first === 'error') && (typeof second === "string")) {
258
+ await this.reportError(sessionId, second);
234
259
  } else {
235
260
  // treat like a message to clients
236
- this.sendToClient(sessionId, data[1]);
261
+ this.sendToClient(sessionId, second);
237
262
  }
238
263
  }
239
264
  };