systemlynx 1.19.12 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +741 -118
- package/README.md +106 -3
- package/RFCs/001-websocket-named-events-room-scoping.md +133 -0
- package/RFCs/002-module-handle-and-internal-error-events.md +135 -0
- package/index.test.js +10 -2
- package/package.json +1 -1
- package/systemlynx/App/App.js +14 -0
- package/systemlynx/App/tests/App.test.js +138 -57
- package/systemlynx/Client/components/ServiceRequestHandler.js +2 -2
- package/systemlynx/Client/components/SocketDispatcher.js +80 -1
- package/systemlynx/Client/tests/Client.test.js +4 -0
- package/systemlynx/Client/tests/SocketDispatcher.test.js +12 -6
- package/systemlynx/Dispatcher/Dispatcher.js +71 -27
- package/systemlynx/Dispatcher/Dispatcher.test.js +87 -4
- package/systemlynx/LoadBalancer/tests/LoadBalancer.test.js +4 -0
- package/systemlynx/ServerManager/components/Router.js +13 -0
- package/systemlynx/ServerManager/components/SocketEmitter.js +7 -1
- package/systemlynx/ServerManager/tests/SocketEmitter.test.js +12 -9
- package/systemlynx/Service/Service.test.js +3 -1
|
@@ -3,15 +3,18 @@ const Dispatcher = require("./Dispatcher");
|
|
|
3
3
|
|
|
4
4
|
describe("createDispatcher", () => {
|
|
5
5
|
const dispatcher = new Dispatcher();
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
it("should return an EventDispatcher object with on, emit, $clearEvent, once, and destroy", () => {
|
|
7
8
|
expect(dispatcher)
|
|
8
9
|
.to.be.an("object")
|
|
9
|
-
.that.has.all.keys("on", "emit", "$clearEvent")
|
|
10
10
|
.that.respondsTo("on")
|
|
11
11
|
.that.respondsTo("emit")
|
|
12
|
-
.that.respondsTo("$clearEvent")
|
|
12
|
+
.that.respondsTo("$clearEvent")
|
|
13
|
+
.that.respondsTo("once")
|
|
14
|
+
.that.respondsTo("destroy");
|
|
13
15
|
});
|
|
14
|
-
|
|
16
|
+
|
|
17
|
+
it("should emit and handle events", (done) => {
|
|
15
18
|
dispatcher.on("test", (data) => {
|
|
16
19
|
expect(data).to.deep.equal({ testPassed: true });
|
|
17
20
|
done();
|
|
@@ -19,4 +22,84 @@ describe("createDispatcher", () => {
|
|
|
19
22
|
|
|
20
23
|
dispatcher.emit("test", { testPassed: true });
|
|
21
24
|
});
|
|
25
|
+
|
|
26
|
+
it("on() should return an unsubscribe function that removes the listener", (done) => {
|
|
27
|
+
const d = new Dispatcher();
|
|
28
|
+
let callCount = 0;
|
|
29
|
+
|
|
30
|
+
const unsubscribe = d.on("ping", () => callCount++);
|
|
31
|
+
expect(unsubscribe).to.be.a("function");
|
|
32
|
+
|
|
33
|
+
d.emit("ping");
|
|
34
|
+
unsubscribe();
|
|
35
|
+
d.emit("ping");
|
|
36
|
+
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
expect(callCount).to.equal(1);
|
|
39
|
+
done();
|
|
40
|
+
}, 0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("eventId should replace the existing listener on re-register", (done) => {
|
|
44
|
+
const d = new Dispatcher();
|
|
45
|
+
let callCount = 0;
|
|
46
|
+
|
|
47
|
+
d.on("ping", () => callCount++, { eventId: "my-listener" });
|
|
48
|
+
d.on("ping", () => callCount++, { eventId: "my-listener" });
|
|
49
|
+
|
|
50
|
+
d.emit("ping");
|
|
51
|
+
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
expect(callCount).to.equal(1);
|
|
54
|
+
done();
|
|
55
|
+
}, 0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("once() should fire the callback only once", (done) => {
|
|
59
|
+
const d = new Dispatcher();
|
|
60
|
+
let callCount = 0;
|
|
61
|
+
|
|
62
|
+
d.once("ping", () => callCount++);
|
|
63
|
+
d.emit("ping");
|
|
64
|
+
d.emit("ping");
|
|
65
|
+
d.emit("ping");
|
|
66
|
+
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
expect(callCount).to.equal(1);
|
|
69
|
+
done();
|
|
70
|
+
}, 0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("destroy() should remove all listeners", (done) => {
|
|
74
|
+
const d = new Dispatcher();
|
|
75
|
+
let callCount = 0;
|
|
76
|
+
|
|
77
|
+
d.on("a", () => callCount++);
|
|
78
|
+
d.on("b", () => callCount++);
|
|
79
|
+
d.destroy();
|
|
80
|
+
d.emit("a");
|
|
81
|
+
d.emit("b");
|
|
82
|
+
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
expect(callCount).to.equal(0);
|
|
85
|
+
done();
|
|
86
|
+
}, 0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("$clearEvent should still work with a named function (backward compat)", (done) => {
|
|
90
|
+
const d = new Dispatcher();
|
|
91
|
+
let callCount = 0;
|
|
92
|
+
|
|
93
|
+
function myHandler() { callCount++; }
|
|
94
|
+
|
|
95
|
+
d.on("ping", myHandler);
|
|
96
|
+
d.emit("ping");
|
|
97
|
+
d.$clearEvent("ping", myHandler);
|
|
98
|
+
d.emit("ping");
|
|
99
|
+
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
expect(callCount).to.equal(1);
|
|
102
|
+
done();
|
|
103
|
+
}, 0);
|
|
104
|
+
});
|
|
22
105
|
});
|
|
@@ -26,8 +26,10 @@ describe("LoadBalancer()", () => {
|
|
|
26
26
|
.to.be.an("object")
|
|
27
27
|
.that.has.all.keys(
|
|
28
28
|
"on",
|
|
29
|
+
"once",
|
|
29
30
|
"emit",
|
|
30
31
|
"$clearEvent",
|
|
32
|
+
"destroy",
|
|
31
33
|
"before",
|
|
32
34
|
"after",
|
|
33
35
|
"clones",
|
|
@@ -93,9 +95,11 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
93
95
|
.to.be.an("Object")
|
|
94
96
|
.that.has.all.keys(
|
|
95
97
|
"on",
|
|
98
|
+
"once",
|
|
96
99
|
"emit",
|
|
97
100
|
"$emit",
|
|
98
101
|
"$clearEvent",
|
|
102
|
+
"destroy",
|
|
99
103
|
"before",
|
|
100
104
|
"after",
|
|
101
105
|
"register",
|
|
@@ -34,6 +34,7 @@ module.exports = function createRouter(server, config) {
|
|
|
34
34
|
[`/${route}`],
|
|
35
35
|
(req, res, next) => {
|
|
36
36
|
req.module_name = module_name;
|
|
37
|
+
req.moduleName = module_name;
|
|
37
38
|
req.fn = method;
|
|
38
39
|
req.Module = Module;
|
|
39
40
|
req.module = Module;
|
|
@@ -57,6 +58,18 @@ module.exports = function createRouter(server, config) {
|
|
|
57
58
|
const sendError = (error) => {
|
|
58
59
|
const status = (error || {}).status || 500;
|
|
59
60
|
const message = (error || {}).message || unhandledMessage;
|
|
61
|
+
// Emit a local-only "error" event on the module so server-side observers
|
|
62
|
+
// (e.g. a SystemView plugin) can monitor failures. $emit does not broadcast
|
|
63
|
+
// over websockets — the failing client already receives the error over HTTP.
|
|
64
|
+
if (Module && typeof Module.$emit === "function")
|
|
65
|
+
Module.$emit("error", {
|
|
66
|
+
module_name,
|
|
67
|
+
fn,
|
|
68
|
+
arguments: req.arguments,
|
|
69
|
+
status,
|
|
70
|
+
message,
|
|
71
|
+
error,
|
|
72
|
+
});
|
|
60
73
|
res.status(status).json({
|
|
61
74
|
...presets,
|
|
62
75
|
...error,
|
|
@@ -6,13 +6,19 @@ module.exports = function SocketEmitter(namespace, WebSocket) {
|
|
|
6
6
|
(this || {}).on && (this || {}).emit ? this : createDispatcher.apply(this);
|
|
7
7
|
|
|
8
8
|
const socket = WebSocket.of(`/${namespace}`);
|
|
9
|
+
|
|
10
|
+
socket.on("connection", (clientSocket) => {
|
|
11
|
+
clientSocket.on("subscribe", (name) => clientSocket.join(name));
|
|
12
|
+
clientSocket.on("unsubscribe", (name) => clientSocket.leave(name));
|
|
13
|
+
});
|
|
14
|
+
|
|
9
15
|
//use $emit to emit events locally only
|
|
10
16
|
Emitter.$emit = Emitter.emit;
|
|
11
17
|
|
|
12
18
|
Emitter.emit = (name, data) => {
|
|
13
19
|
const id = shortid();
|
|
14
20
|
const type = "WebSocket";
|
|
15
|
-
socket.emit(
|
|
21
|
+
socket.to(name).emit(name, { id, data, type });
|
|
16
22
|
//emit the same event locally
|
|
17
23
|
Emitter.$emit(name, data);
|
|
18
24
|
};
|
|
@@ -11,19 +11,22 @@ describe("SocketEmiiter", () => {
|
|
|
11
11
|
SocketServer.listen(port);
|
|
12
12
|
const emmiter = SocketEmiiter(namespace, WebSocket);
|
|
13
13
|
|
|
14
|
-
setTimeout(() => {
|
|
15
|
-
emmiter.emit(eventName, { testPassed: true });
|
|
16
|
-
}, 500);
|
|
17
14
|
const socket = io.connect(`http://localhost:${port}/${namespace}`);
|
|
18
|
-
socket.on("
|
|
19
|
-
|
|
15
|
+
socket.on("connect", () => {
|
|
16
|
+
console.log(`socket connected to namespace: ${namespace}`);
|
|
17
|
+
socket.emit("subscribe", eventName);
|
|
18
|
+
});
|
|
19
|
+
socket.on(eventName, (payload) => {
|
|
20
|
+
expect(payload)
|
|
20
21
|
.to.be.an("object")
|
|
21
|
-
.that.has.all.keys("id", "
|
|
22
|
-
expect(
|
|
23
|
-
expect(dispatch.data).to.deep.equal({ testPassed: true });
|
|
22
|
+
.that.has.all.keys("id", "data", "type");
|
|
23
|
+
expect(payload.data).to.deep.equal({ testPassed: true });
|
|
24
24
|
done();
|
|
25
25
|
});
|
|
26
26
|
socket.on("disconnect", () => console.log("---------> disconnect"));
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
emmiter.emit(eventName, { testPassed: true });
|
|
30
|
+
}, 500);
|
|
28
31
|
});
|
|
29
32
|
});
|
|
@@ -70,7 +70,7 @@ describe("Service.module(constructor)", () => {
|
|
|
70
70
|
|
|
71
71
|
expect(mod)
|
|
72
72
|
.to.be.an("Object")
|
|
73
|
-
.that.has.all.keys("on", "emit", "$clearEvent", "before", "after", "test", "test2")
|
|
73
|
+
.that.has.all.keys("on", "once", "emit", "$clearEvent", "destroy", "before", "after", "test", "test2")
|
|
74
74
|
.that.respondsTo("on")
|
|
75
75
|
.that.respondsTo("emit")
|
|
76
76
|
.that.respondsTo("$clearEvent")
|
|
@@ -205,8 +205,10 @@ describe("Service.module(object)", () => {
|
|
|
205
205
|
"action1",
|
|
206
206
|
"action2",
|
|
207
207
|
"on",
|
|
208
|
+
"once",
|
|
208
209
|
"emit",
|
|
209
210
|
"$clearEvent",
|
|
211
|
+
"destroy",
|
|
210
212
|
"before",
|
|
211
213
|
"after"
|
|
212
214
|
)
|