sockethub 5.0.0-alpha.2 → 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 (101) hide show
  1. package/bin/sockethub +2 -29
  2. package/build.js +21 -0
  3. package/package.json +15 -65
  4. package/{dist/defaults.json → sockethub.config.json} +8 -7
  5. package/tsconfig.json +6 -68
  6. package/README.md +0 -98
  7. package/config.json.example +0 -32
  8. package/dist/bootstrap/init.js +0 -74
  9. package/dist/bootstrap/init.js.map +0 -1
  10. package/dist/bootstrap/platforms.js +0 -103
  11. package/dist/common.js +0 -20
  12. package/dist/common.js.map +0 -1
  13. package/dist/config.js +0 -60
  14. package/dist/config.js.map +0 -1
  15. package/dist/crypto.js +0 -38
  16. package/dist/crypto.js.map +0 -1
  17. package/dist/janitor.js +0 -98
  18. package/dist/janitor.js.map +0 -1
  19. package/dist/middleware/create-activity-object.js +0 -19
  20. package/dist/middleware/create-activity-object.js.map +0 -1
  21. package/dist/middleware/expand-activity-stream.js +0 -33
  22. package/dist/middleware/expand-activity-stream.js.map +0 -1
  23. package/dist/middleware/expand-activity-stream.test.data.js +0 -360
  24. package/dist/middleware/expand-activity-stream.test.data.js.map +0 -1
  25. package/dist/middleware/store-credentials.js +0 -19
  26. package/dist/middleware/store-credentials.js.map +0 -1
  27. package/dist/middleware/validate.js +0 -77
  28. package/dist/middleware/validate.js.map +0 -1
  29. package/dist/middleware/validate.test.data.js +0 -321
  30. package/dist/middleware/validate.test.data.js.map +0 -1
  31. package/dist/middleware.js +0 -54
  32. package/dist/middleware.js.map +0 -1
  33. package/dist/platform-instance.js +0 -226
  34. package/dist/platform-instance.js.map +0 -1
  35. package/dist/platform.js +0 -186
  36. package/dist/platform.js.map +0 -1
  37. package/dist/process-manager.js +0 -78
  38. package/dist/process-manager.js.map +0 -1
  39. package/dist/routes.js +0 -84
  40. package/dist/routes.js.map +0 -1
  41. package/dist/serve.js +0 -102
  42. package/dist/serve.js.map +0 -1
  43. package/dist/sockethub-client.js +0 -2604
  44. package/dist/sockethub-client.js.map +0 -1
  45. package/dist/sockethub-client.min.js +0 -2
  46. package/dist/sockethub-client.min.js.LICENSE.txt +0 -24
  47. package/dist/sockethub.js +0 -130
  48. package/dist/sockethub.js.map +0 -1
  49. package/dist/store.js +0 -17
  50. package/dist/store.js.map +0 -1
  51. package/src/bootstrap/init.d.ts +0 -8
  52. package/src/bootstrap/init.ts +0 -91
  53. package/src/bootstrap/platforms.js +0 -103
  54. package/src/common.test.ts +0 -54
  55. package/src/common.ts +0 -14
  56. package/src/config.d.ts +0 -2
  57. package/src/config.test.ts +0 -28
  58. package/src/config.ts +0 -72
  59. package/src/crypto.d.ts +0 -5
  60. package/src/crypto.test.ts +0 -41
  61. package/src/crypto.ts +0 -41
  62. package/src/defaults.json +0 -32
  63. package/src/janitor.d.ts +0 -8
  64. package/src/janitor.ts +0 -89
  65. package/src/middleware/create-activity-object.test.ts +0 -10
  66. package/src/middleware/create-activity-object.ts +0 -13
  67. package/src/middleware/expand-activity-stream.test.data.ts +0 -365
  68. package/src/middleware/expand-activity-stream.test.ts +0 -78
  69. package/src/middleware/expand-activity-stream.ts +0 -27
  70. package/src/middleware/store-credentials.test.ts +0 -72
  71. package/src/middleware/store-credentials.ts +0 -16
  72. package/src/middleware/validate.d.ts +0 -1
  73. package/src/middleware/validate.test.data.ts +0 -320
  74. package/src/middleware/validate.test.ts +0 -47
  75. package/src/middleware/validate.ts +0 -49
  76. package/src/middleware.d.ts +0 -21
  77. package/src/middleware.test.ts +0 -148
  78. package/src/middleware.ts +0 -52
  79. package/src/platform-instance.test.ts +0 -237
  80. package/src/platform-instance.ts +0 -236
  81. package/src/platform.ts +0 -189
  82. package/src/process-manager.ts +0 -64
  83. package/src/routes.test.ts +0 -100
  84. package/src/routes.ts +0 -93
  85. package/src/serve.ts +0 -79
  86. package/src/sockethub-client.test.ts +0 -235
  87. package/src/sockethub-client.ts +0 -164
  88. package/src/sockethub.d.ts +0 -1
  89. package/src/sockethub.ts +0 -184
  90. package/src/store.test.ts +0 -26
  91. package/src/store.ts +0 -17
  92. package/test/init-suite.js +0 -41
  93. package/test/sockethub-suite.js +0 -25
  94. package/views/examples/dummy.ejs +0 -93
  95. package/views/examples/feeds.ejs +0 -90
  96. package/views/examples/irc.ejs +0 -239
  97. package/views/examples/shared.js +0 -72
  98. package/views/examples/xmpp.ejs +0 -191
  99. package/views/index.ejs +0 -17
  100. package/webpack.minified.config.js +0 -14
  101. package/webpack.normal.config.js +0 -14
@@ -1,148 +0,0 @@
1
- import { expect } from 'chai';
2
- import * as sinon from 'sinon';
3
-
4
- import middleware, { MiddlewareChain } from "./middleware";
5
-
6
- describe("Middleware", () => {
7
- it("middleware() is a function", () => {
8
- expect(typeof middleware).to.be.equal('function');
9
- });
10
-
11
- it('returns a MiddlewareChain instance', () => {
12
- const mw = middleware('testa');
13
- expect(mw).to.be.instanceof(MiddlewareChain);
14
- const mwc = new MiddlewareChain('testa');
15
- expect(mw.name).to.be.eql(mwc.name);
16
- });
17
-
18
- it("only accepts functions", () => {
19
- const mw = middleware('test');
20
- // @ts-ignore
21
- expect(()=>{mw.use('foobar');}).to.throw(
22
- 'middleware use() can only take a function as an argument');
23
- });
24
-
25
- it("only accepts functions that expect 2 or 3 params", () => {
26
- const mw = middleware('test');
27
- // @ts-ignore
28
- expect(()=>{mw.use((one, two, three, four) => {});}).to.throw(
29
- 'middleware function provided with incorrect number of params: 4');
30
- });
31
-
32
- it("calls each member of call list", (done) => {
33
- const callback = (data, cb) => { cb(data); };
34
- const funcs = [ sinon.spy(callback), sinon.spy(callback), sinon.spy(callback) ];
35
- const mw = middleware('test');
36
- for (let func of funcs) {
37
- mw.use(func);
38
- }
39
- mw.done()('some data', (data) => {
40
- expect(data).to.eql('some data');
41
- funcs.unshift(callback);
42
- for (let i = 1; i < funcs.length; i++) {
43
- expect(funcs[i].calledOnce).to.be.true;
44
- expect(funcs[i].calledWith('foobar', funcs[i - 1]));
45
- }
46
- done();
47
- });
48
- });
49
-
50
- it("does not throw exception on error with no callback provided", (done) => {
51
- let errorHandlerCalled = false;
52
- const callbackError = (data, cb) => {
53
- cb(new Error('some error')); };
54
- const funcs = [ sinon.spy(callbackError) ];
55
- const mw = middleware('test');
56
- for (let func of funcs) {
57
- const entry = mw.use(func);
58
- }
59
- mw.use((err, data, next) => {
60
- expect(err.toString()).to.equal('Error: some error');
61
- errorHandlerCalled = true;
62
- next(err);
63
- });
64
- mw.done()('foobar', () => {
65
- expect(errorHandlerCalled).to.be.true;
66
- done();
67
- });
68
- });
69
-
70
- it("aborts call stack on error - calls error handler, and callback", (done) => {
71
- let errorHandlerCalled = false;
72
- const callback = (data, cb) => { cb(data); };
73
- const callbackError = (data, cb) => { cb(new Error('some error')); };
74
- const funcs = [ sinon.spy(callback), sinon.spy(callbackError), sinon.spy(callback) ];
75
- const mw = middleware('test');
76
- for (let func of funcs) {
77
- mw.use(func);
78
- }
79
- mw.use((err, data, next) => {
80
- expect(err.toString()).to.equal('Error: some error');
81
- errorHandlerCalled = true;
82
- next(err);
83
- });
84
- mw.done()('foobar', (data) => {
85
- // FIXME -- We need to also handle socket.io callbacks!
86
- expect(data instanceof Error).to.be.true;
87
- expect(funcs[0].calledOnce).to.be.true;
88
- expect(funcs[0].calledWith('foobar', callback));
89
- expect(funcs[1].calledOnce).to.be.true;
90
- expect(funcs[1].calledWith('foobar', funcs[0]));
91
- expect(funcs[2].calledOnce).to.be.false;
92
- expect(errorHandlerCalled).to.be.true;
93
- done();
94
- });
95
- });
96
-
97
- it("error handler receives error and no callback provided", (done) => {
98
- let errorHandlerCalled = false;
99
- const callback = (data, cb) => { cb(data); };
100
- const callbackError = (data, cb) => { cb(new Error('some error')); };
101
- const funcs = [ sinon.spy(callback), sinon.spy(callback), sinon.spy(callbackError) ];
102
- const mw = middleware('test');
103
- for (let func of funcs) {
104
- mw.use(func);
105
- }
106
- mw.use((err, data, next) => {
107
- expect(err instanceof Error).to.be.true;
108
- expect(err.toString()).to.equal('Error: some error');
109
- errorHandlerCalled = true;
110
- expect(funcs[0].calledOnce).to.be.true;
111
- expect(funcs[0].calledWith('foobar', callback));
112
- expect(funcs[1].calledOnce).to.be.true;
113
- expect(funcs[1].calledWith('foobar', funcs[0]));
114
- expect(funcs[2].calledOnce).to.be.true;
115
- expect(funcs[2].calledWith('foobar', funcs[1]));
116
- expect(errorHandlerCalled).to.be.true;
117
- setTimeout(done, 0);
118
- });
119
- mw.done()('foobar', () => {});
120
- });
121
-
122
- it("calls each member of chain (50)", (done) => {
123
- let errorHandlerCalled = false;
124
- const callback = (data, cb) => { cb(data); };
125
- let funcs = [];
126
- for (let i = 0; i <= 50; i++) {
127
- funcs.push(sinon.spy(callback));
128
- }
129
- const mw = middleware('test');
130
- for (let func of funcs) {
131
- mw.use(func);
132
- }
133
- mw.use((err, next, data) => {
134
- expect(err.toString()).to.equal('Error: some error');
135
- errorHandlerCalled = true;
136
- });
137
- mw.done()('some data', (data) => {
138
- expect(data).to.equal('some data');
139
- funcs.unshift(callback);
140
- for (let i = 1; i < funcs.length; i++) {
141
- expect(funcs[i].calledOnce).to.be.true;
142
- expect(funcs[i].calledWith('foo', funcs[i - 1]));
143
- }
144
- expect(errorHandlerCalled).to.be.false;
145
- done();
146
- });
147
- });
148
- });
package/src/middleware.ts DELETED
@@ -1,52 +0,0 @@
1
- import { debug } from 'debug';
2
-
3
- export default function middleware(name: string): MiddlewareChain {
4
- return new MiddlewareChain(name);
5
- }
6
-
7
- export class MiddlewareChain {
8
- public name: string;
9
- private chain: Array<Function> = [];
10
- private errHandler: Function = (err: Error) => { throw err; };
11
- private logger: Function;
12
-
13
- constructor(name: string) {
14
- this.name = name;
15
- this.logger = debug(`sockethub:middleware:${name}`);
16
- }
17
-
18
- use(func: Function): this {
19
- if (typeof func !== 'function') {
20
- throw new Error('middleware use() can only take a function as an argument');
21
- }
22
- if (func.length === 3) {
23
- this.errHandler = func;
24
- } else if (func.length === 2) {
25
- this.chain.push(func);
26
- } else {
27
- throw new Error(
28
- 'middleware function provided with incorrect number of params: ' + func.length);
29
- }
30
- return this;
31
- }
32
-
33
- done() {
34
- return (data: any, callback: Function) => {
35
- let position = 0;
36
- if (typeof callback !== 'function') {
37
- callback = () => {};
38
- }
39
- const next = (_data: any) => {
40
- if (_data instanceof Error) {
41
- this.logger(_data);
42
- this.errHandler(_data, data, callback);
43
- } else if (typeof this.chain[position] === 'function') {
44
- this.chain[position++](_data, next);
45
- } else {
46
- callback(_data);
47
- }
48
- };
49
- next(data);
50
- };
51
- }
52
- }
@@ -1,237 +0,0 @@
1
- import proxyquire from 'proxyquire';
2
- import { expect } from 'chai';
3
- import * as sinon from 'sinon';
4
-
5
- proxyquire.noPreserveCache();
6
- proxyquire.noCallThru();
7
-
8
- const FORK_PATH = __dirname + '/platform.js';
9
-
10
- describe("PlatformInstance", () => {
11
- let pi, sandbox, forkFake, socketMock, getSocketFake, PlatformInstance, platformInstances;
12
-
13
- beforeEach(() => {
14
- sandbox = sinon.createSandbox();
15
- forkFake = sandbox.fake();
16
- socketMock = {
17
- emit: sandbox.spy()
18
- };
19
- getSocketFake = sinon.fake.resolves(socketMock);
20
-
21
- const PlatformInstanceMod = proxyquire('./platform-instance', {
22
- 'bull': sandbox.stub().returns({
23
- on: sandbox.stub()
24
- }),
25
- './store': {
26
- redisConfig: {
27
- createClient: () => {}
28
- }
29
- },
30
- 'child_process': {
31
- fork: forkFake,
32
- ChildProcess: sandbox.stub()
33
- },
34
- './serve': {
35
- 'io': {
36
- 'in': sandbox.stub().returns({
37
- fetchSockets: () => {
38
- return [socketMock];
39
- }
40
- })
41
- },
42
- getSocket: getSocketFake
43
- }
44
- });
45
- PlatformInstance = PlatformInstanceMod.default;
46
- platformInstances = PlatformInstanceMod.platformInstances;
47
- });
48
-
49
- afterEach(() => {
50
- sinon.restore();
51
- });
52
-
53
- describe('private instance per-actor', () => {
54
- it("is set as non-global when an actor is provided", () => {
55
- const pi = new PlatformInstance({
56
- identifier: 'id',
57
- platform: 'name',
58
- parentId: 'parentId',
59
- actor: 'actor string'
60
- });
61
- expect(pi.global).to.be.equal(false);
62
- sandbox.assert.calledWith(forkFake, FORK_PATH, ['parentId', 'name', 'id']);
63
- pi.destroy();
64
- });
65
- });
66
-
67
- describe('PlatformInstance objects', () => {
68
- beforeEach(() => {
69
- pi = new PlatformInstance({
70
- identifier: 'platform identifier',
71
- platform: 'a platform name',
72
- parentId: 'the parentId'
73
- });
74
- platformInstances.set(pi.id, pi);
75
-
76
- pi.process = {
77
- on: sandbox.spy(),
78
- removeListener: sandbox.spy(),
79
- removeAllListeners: sandbox.spy(),
80
- unref: sandbox.spy(),
81
- kill: sandbox.spy(),
82
- };
83
- });
84
-
85
- afterEach(() => {
86
- pi.destroy();
87
- });
88
-
89
- it('has expected properties', () => {
90
- expect(typeof PlatformInstance).to.be.equal('function');
91
- });
92
-
93
- it('should have a platformInstances Map', () => {
94
- expect(platformInstances instanceof Map).to.be.equal(true);
95
- });
96
-
97
- it("has certain accessible properties", () => {
98
- expect(pi.id).to.be.equal('platform identifier');
99
- expect(pi.name).to.be.equal('a platform name');
100
- expect(pi.parentId).to.be.equal('the parentId');
101
- expect(pi.flaggedForTermination).to.be.equal(false);
102
- expect(pi.global).to.be.equal(true);
103
- expect(forkFake.calledWith(FORK_PATH, [
104
- 'the parentId', 'a platform name', 'platform identifier'
105
- ])).to.be.ok;
106
- });
107
-
108
- describe('registerSession', () => {
109
- beforeEach(() => {
110
- pi.callbackFunction = sandbox.fake();
111
- });
112
-
113
- it('adds a close and message handler when a session is registered', () => {
114
- pi.registerSession('my session id');
115
- expect(pi.callbackFunction.callCount).to.equal(2);
116
- sandbox.assert.calledWith(pi.callbackFunction, 'close', 'my session id');
117
- sandbox.assert.calledWith(pi.callbackFunction, 'message', 'my session id');
118
- expect(pi.sessions.has('my session id')).to.be.equal(true);
119
- });
120
-
121
- it('is able to generate failure reports', () => {
122
- pi.registerSession('my session id');
123
- expect(pi.sessions.has('my session id')).to.be.equal(true);
124
- pi.reportError('my session id', 'an error message');
125
- pi.sendToClient = sandbox.stub();
126
- pi.destroy = sandbox.stub();
127
- expect(pi.sessions.size).to.be.equal(0);
128
- });
129
- });
130
-
131
- it('initializes the job queue', () => {
132
- expect(pi.queue).to.be.undefined;
133
- pi.initQueue('a secret');
134
- expect(pi.queue).to.be.ok;
135
- });
136
-
137
- it("cleans up its references when destroyed", async () => {
138
- pi.initQueue('a secret');
139
- expect(pi.queue).to.be.ok;
140
- expect(platformInstances.has('platform identifier')).to.be.true;
141
- await pi.destroy();
142
- expect(pi.queue).not.to.be.ok;
143
- expect(platformInstances.has('platform identifier')).to.be.false;
144
- });
145
-
146
- it("updates its identifier when changed", () => {
147
- pi.updateIdentifier('foo bar');
148
- expect(pi.id).to.be.equal('foo bar');
149
- expect(platformInstances.has('platform identifier')).to.be.false;
150
- expect(platformInstances.has('foo bar')).to.be.true;
151
- });
152
-
153
- it('sends messages to client using socket session id', async () => {
154
- await pi.sendToClient('my session id',
155
- {foo: 'this is a message object', sessionSecret: 'private data'});
156
- expect(getSocketFake.callCount).to.equal(1);
157
- sandbox.assert.calledOnce(getSocketFake);
158
- sandbox.assert.calledWith(getSocketFake, 'my session id');
159
- sandbox.assert.calledOnce(socketMock.emit);
160
- sandbox.assert.calledWith(
161
- socketMock.emit, 'message', {foo:'this is a message object', context: 'a platform name'});
162
- });
163
-
164
- it('broadcasts to peers', async () => {
165
- pi.sessions.add('other peer');
166
- pi.sessions.add('another peer');
167
- await pi.broadcastToSharedPeers('myself', {foo: 'bar'});
168
- expect(getSocketFake.callCount).to.equal(2);
169
- sandbox.assert.calledWith(getSocketFake, 'other peer');
170
- });
171
-
172
- describe('handleJobResult', () => {
173
- beforeEach(() => {
174
- pi.sendToClient = sandbox.fake();
175
- pi.broadcastToSharedPeers = sandbox.fake();
176
- });
177
-
178
- it('broadcasts to peers when handling a completed job', async () => {
179
- pi.sessions.add('other peer');
180
- await pi.handleJobResult('completed', {msg: {foo: 'bar'}},
181
- undefined);
182
- expect(pi.sendToClient.callCount).to.equal(1);
183
- expect(pi.broadcastToSharedPeers.callCount).to.equal(1);
184
- });
185
-
186
- it('appends completed result message when present', async () => {
187
- await pi.handleJobResult('completed', {sessionId: 'a session id', msg: {foo: 'bar'}},
188
- 'a good result message');
189
- expect(pi.broadcastToSharedPeers.callCount).to.equal(1);
190
- sandbox.assert.calledWith(pi.sendToClient, 'a session id',
191
- {foo: 'bar'});
192
- });
193
-
194
- it('appends failed result message when present', async () => {
195
- await pi.handleJobResult('failed', {sessionId: 'a session id', msg: {foo: 'bar'}},
196
- 'a bad result message');
197
- expect(pi.broadcastToSharedPeers.callCount).to.equal(1);
198
- sandbox.assert.calledWith(pi.sendToClient, 'a session id',
199
- {foo: 'bar', error: 'a bad result message'});
200
- });
201
- });
202
-
203
- describe('callbackFunction', () => {
204
- beforeEach(() => {
205
- pi.reportError = sandbox.fake();
206
- pi.sendToClient = sandbox.fake();
207
- pi.updateIdentifier = sandbox.fake();
208
- });
209
-
210
- it('close events from platform thread are reported', () => {
211
- const close = pi.callbackFunction('close', 'my session id');
212
- close('error msg');
213
- sandbox.assert.calledWith(pi.reportError,
214
- 'my session id', 'Error: session thread closed unexpectedly: error msg');
215
- });
216
-
217
- it('message events from platform thread are route based on command: error', () => {
218
- const message = pi.callbackFunction('message', 'my session id');
219
- message(['error', 'error message']);
220
- sandbox.assert.calledWith(pi.reportError, 'my session id', 'error message');
221
- });
222
-
223
- it('message events from platform thread are route based on command: updateActor', () => {
224
- const message = pi.callbackFunction('message', 'my session id');
225
- message(['updateActor', undefined, {foo: 'bar'}]);
226
- sandbox.assert.calledWith(pi.updateIdentifier, {foo:'bar'});
227
- });
228
-
229
- it('message events from platform thread are route based on command: else', () => {
230
- const message = pi.callbackFunction('message', 'my session id');
231
- message(['blah', {foo: 'bar'}]);
232
- sandbox.assert.calledWith(pi.sendToClient,
233
- 'my session id', {foo:'bar'});
234
- });
235
- });
236
- });
237
- });
@@ -1,236 +0,0 @@
1
- import { ChildProcess, fork } from 'child_process';
2
- import { join } from 'path';
3
- import { debug, Debugger } from 'debug';
4
- import Queue from 'bull';
5
-
6
- import config from "./config";
7
- import { ActivityStream, JobDataDecrypted, JobEncrypted } from "./sockethub";
8
- import { getSocket } from "./serve";
9
- import { decryptJobData } from "./common";
10
-
11
- // collection of platform instances, stored by `id`
12
- export const platformInstances = new Map<string, PlatformInstance>();
13
-
14
- export interface PlatformInstanceParams {
15
- identifier: string;
16
- platform: string;
17
- parentId?: string;
18
- actor?: string;
19
- }
20
-
21
- interface MessageFromPlatform extends Array<string|ActivityStream>{
22
- 0: string, 1: ActivityStream, 2: string}
23
- export interface MessageFromParent extends Array<string|any>{0: string, 1: any}
24
-
25
- interface PlatformConfig {
26
- persist?: boolean;
27
- requireCredentials?: Array<string>;
28
- }
29
-
30
- export default class PlatformInstance {
31
- flaggedForTermination: boolean = false;
32
- id: string;
33
- queue: Queue;
34
- completedJobHandlers: Map<string, Function> = new Map();
35
- config: PlatformConfig = {};
36
- readonly name: string;
37
- readonly process: ChildProcess;
38
- readonly debug: Debugger;
39
- readonly parentId: string;
40
- readonly sessions: Set<string> = new Set();
41
- readonly sessionCallbacks: object = {
42
- 'close': (() => new Map())(),
43
- 'message': (() => new Map())()
44
- };
45
- public readonly global?: boolean = false;
46
- private readonly actor?: string;
47
-
48
- constructor(params: PlatformInstanceParams) {
49
- this.id = params.identifier;
50
- this.name = params.platform;
51
- this.parentId = params.parentId;
52
- if (params.actor) {
53
- this.actor = params.actor;
54
- } else {
55
- this.global = true;
56
- }
57
-
58
- this.debug = debug(`sockethub:platform-instance:${this.id}`);
59
- // spin off a process
60
- this.process = fork(join(__dirname, 'platform.js'), [this.parentId, this.name, this.id]);
61
- }
62
-
63
- /**
64
- * Destroys all references to this platform instance, internal listeners and controlled processes
65
- */
66
- public async destroy() {
67
- this.debug(`cleaning up`);
68
- this.flaggedForTermination = true;
69
- try {
70
- await this.queue.removeAllListeners();
71
- } catch (e) { }
72
- try {
73
- await this.queue.obliterate({ force: true });
74
- } catch (e) { }
75
- try {
76
- delete this.queue;
77
- await this.process.removeAllListeners('close');
78
- await this.process.unref();
79
- await this.process.kill();
80
- } catch (e) { }
81
- platformInstances.delete(this.id);
82
- }
83
-
84
- /**
85
- * When jobs are completed or failed, we prepare the results and send them to the client socket
86
- */
87
- public initQueue(secret: string) {
88
- this.queue = new Queue(this.parentId + this.id, { redis: config.get('redis') });
89
-
90
- this.queue.on('global:completed', (jobId, resultString) => {
91
- const result = resultString ? JSON.parse(resultString) : "";
92
- this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
93
- await this.handleJobResult('completed', decryptJobData(job, secret), result);
94
- await job.remove();
95
- });
96
- });
97
-
98
- this.queue.on('global:error', (jobId, result) => {
99
- this.debug("unknown queue error", jobId, result);
100
- });
101
-
102
- this.queue.on('global:failed', (jobId, result) => {
103
- this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
104
- await this.handleJobResult('failed', decryptJobData(job, secret), result);
105
- await job.remove();
106
- });
107
- });
108
- }
109
-
110
- /**
111
- * Register listener to be called when the process emits a message.
112
- * @param sessionId ID of socket connection that will receive messages from platform emits
113
- */
114
- public registerSession(sessionId: string) {
115
- if (! this.sessions.has(sessionId)) {
116
- this.sessions.add(sessionId);
117
- for (let type of Object.keys(this.sessionCallbacks)) {
118
- const cb = this.callbackFunction(type, sessionId);
119
- this.process.on(type, cb);
120
- this.sessionCallbacks[type].set(sessionId, cb);
121
- }
122
- }
123
- }
124
-
125
- /**
126
- * Sends a message to client (user), can be registered with an event emitted from the platform
127
- * process.
128
- * @param sessionId ID of the socket connection to send the message to
129
- * @param msg ActivityStream object to send to client
130
- */
131
- public sendToClient(sessionId: string, msg: ActivityStream) {
132
- getSocket(sessionId).then((socket) => {
133
- try {
134
- // this property should never be exposed externally
135
- delete msg.sessionSecret;
136
- } catch (e) {}
137
- msg.context = this.name;
138
- if ((msg.type === 'error') && (typeof msg.actor === 'undefined') && (this.actor)) {
139
- // ensure an actor is present if not otherwise defined
140
- msg.actor = { id: this.actor };
141
- }
142
- socket.emit('message', msg);
143
- }, (err) => this.debug(`sendToClient ${err}`));
144
- }
145
-
146
- // send message to every connected socket associated with this platform instance.
147
- private async broadcastToSharedPeers(sessionId: string, msg: ActivityStream) {
148
- for (let sid of this.sessions.values()) {
149
- if (sid !== sessionId) {
150
- this.debug(`broadcasting message to ${sid}`);
151
- await this.sendToClient(sid, msg);
152
- }
153
- }
154
- }
155
-
156
- // handle job results coming in on the queue from platform instances
157
- private async handleJobResult(type: string, jobData: JobDataDecrypted, result) {
158
- this.debug(`${type} job ${jobData.title}`);
159
- delete jobData.msg.sessionSecret;
160
- let msg = jobData.msg;
161
- if (type === 'failed') {
162
- msg.error = result ? result : "job failed for unknown reason";
163
- if ((this.config.persist) && (this.config.requireCredentials.includes(jobData.msg.type))) {
164
- this.debug(`critical job type ${jobData.msg.type} failed, terminating platform instance`);
165
- await this.destroy();
166
- }
167
- }
168
-
169
- // send result to client
170
- const callback = this.completedJobHandlers.get(jobData.title);
171
- if (callback) {
172
- callback(msg);
173
- this.completedJobHandlers.delete(jobData.title);
174
- } else {
175
- await this.sendToClient(jobData.sessionId, msg);
176
- }
177
-
178
- // let all related peers know of result as an independent message
179
- // (not as part of a job completion, or failure)
180
- await this.broadcastToSharedPeers(jobData.sessionId, msg);
181
- }
182
-
183
- /**
184
- * Sends error message to client and clears all references to this class.
185
- * @param sessionId
186
- * @param errorMessage
187
- */
188
- private async reportError(sessionId: string, errorMessage: any) {
189
- const errorObject: ActivityStream = {
190
- context: this.name,
191
- type: 'error',
192
- actor: { id: this.actor },
193
- error: errorMessage
194
- };
195
- this.sendToClient(sessionId, errorObject);
196
- this.sessions.clear();
197
- await this.destroy();
198
- }
199
-
200
- /**
201
- * Updates the instance with a new identifier, updating the platformInstances mapping as well.
202
- * @param identifier
203
- */
204
- private updateIdentifier(identifier: string) {
205
- platformInstances.delete(this.id);
206
- this.id = identifier;
207
- platformInstances.set(this.id, this);
208
- }
209
-
210
- /**
211
- * Generates a function tied to a given client session (socket connection), the generated
212
- * function will be called for each session ID registered, for every platform emit.
213
- * @param listener
214
- * @param sessionId
215
- */
216
- private callbackFunction(listener: string, sessionId: string) {
217
- const funcs = {
218
- 'close': (e: object) => {
219
- this.debug(`close even triggered ${this.id}: ${e}`);
220
- this.reportError(sessionId, `Error: session thread closed unexpectedly: ${e}`);
221
- },
222
- 'message': (data: MessageFromPlatform) => {
223
- if (data[0] === 'updateActor') {
224
- // We need to update the key to the store in order to find it in the future.
225
- this.updateIdentifier(data[2]);
226
- } else if (data[0] === 'error') {
227
- this.reportError(sessionId, data[1]);
228
- } else {
229
- // treat like a message to clients
230
- this.sendToClient(sessionId, data[1]);
231
- }
232
- }
233
- };
234
- return funcs[listener];
235
- }
236
- }