systemlynx 1.8.2 → 1.8.3
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 +7 -0
- package/README.md +11 -5
- package/index.js +22 -23
- package/index.test.js +47 -17
- package/package.json +1 -1
- package/systemlynx/App/App.js +11 -6
- package/systemlynx/App/components/initializeApp.js +2 -2
- package/systemlynx/App/components/loadServices.js +3 -3
- package/systemlynx/App/tests/App.test.js +95 -31
- package/systemlynx/Client/Client.js +6 -3
- package/systemlynx/Client/components/ClientModule.js +9 -3
- package/systemlynx/Client/components/ServiceRequestHandler.js +23 -19
- package/systemlynx/Client/components/SocketDispatcher.js +2 -2
- package/systemlynx/Client/components/loadConnectionData.js +6 -4
- package/systemlynx/Client/tests/Client.test.js +27 -16
- package/systemlynx/Client/tests/SocketDispatcher.test.js +17 -6
- package/systemlynx/Dispatcher/Dispatcher.js +16 -1
- package/systemlynx/Dispatcher/Dispatcher.test.js +4 -3
- package/systemlynx/HttpClient/HttpClient.js +1 -1
- package/systemlynx/LoadBalancer/tests/LoadBalancer.test.js +30 -7
- package/systemlynx/ServerManager/ServerManager.js +75 -36
- package/systemlynx/ServerManager/components/Router.js +30 -11
- package/systemlynx/ServerManager/components/Server.js +22 -18
- package/systemlynx/ServerManager/components/SocketEmitter.js +2 -2
- package/systemlynx/ServerManager/components/WebSocketServer.js +2 -2
- package/systemlynx/ServerManager/components/clearFolder.js +10 -0
- package/systemlynx/ServerManager/components/parseMethods.js +1 -1
- package/systemlynx/ServerManager/tests/ServerManager.test.js +124 -11
- package/systemlynx/Service/Service.js +31 -12
- package/systemlynx/Service/Service.test.js +81 -16
- package/temp/.gitignore +0 -4
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const ServiceRequestHandler = require("./ServiceRequestHandler");
|
|
3
3
|
const SocketDispatcher = require("./SocketDispatcher");
|
|
4
|
+
const getProtocol = (url) => url.match(/^(\w+):\/\//)[0];
|
|
5
|
+
|
|
4
6
|
module.exports = function SystemLynxClientModule(
|
|
7
|
+
httpClient,
|
|
5
8
|
{ methods, namespace, route, connectionData, name },
|
|
6
|
-
{ port, host },
|
|
9
|
+
{ port, host, serviceUrl },
|
|
7
10
|
reconnectService,
|
|
8
11
|
systemContext
|
|
9
12
|
) {
|
|
10
13
|
const events = {};
|
|
11
|
-
const ClientModule =
|
|
14
|
+
const ClientModule = {};
|
|
12
15
|
|
|
13
16
|
ClientModule.__setConnection = (host, port, route, namespace) => {
|
|
14
17
|
ClientModule.__connectionData = () => ({ route, host, port });
|
|
18
|
+
|
|
15
19
|
SocketDispatcher.apply(ClientModule, [namespace, events, systemContext]);
|
|
16
20
|
};
|
|
17
21
|
ClientModule.__setConnection(host, port, route, namespace);
|
|
@@ -24,9 +28,11 @@ module.exports = function SystemLynxClientModule(
|
|
|
24
28
|
|
|
25
29
|
if (typeof cb === "function") cb();
|
|
26
30
|
};
|
|
27
|
-
|
|
31
|
+
const protocol = getProtocol(serviceUrl);
|
|
28
32
|
methods.forEach(({ method, fn }) => {
|
|
29
33
|
ClientModule[fn] = ServiceRequestHandler.apply(ClientModule, [
|
|
34
|
+
httpClient,
|
|
35
|
+
protocol,
|
|
30
36
|
method,
|
|
31
37
|
fn,
|
|
32
38
|
reconnectService,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const HttpClient = require("../../HttpClient/HttpClient")();
|
|
3
2
|
const isObject = (value) =>
|
|
4
3
|
typeof value === "object" ? (!value ? false : !Array.isArray(value)) : false;
|
|
5
4
|
|
|
@@ -9,53 +8,58 @@ const makeQuery = (data) =>
|
|
|
9
8
|
"?"
|
|
10
9
|
);
|
|
11
10
|
module.exports = function ServiceRequestHandler(
|
|
11
|
+
httpClient,
|
|
12
|
+
protocol,
|
|
12
13
|
method,
|
|
13
14
|
fn,
|
|
14
15
|
reconnectService,
|
|
15
16
|
reconnectModule
|
|
16
17
|
) {
|
|
17
18
|
const ClientModule = this;
|
|
18
|
-
|
|
19
19
|
return function sendRequest() {
|
|
20
20
|
const __arguments = Array.from(arguments);
|
|
21
21
|
|
|
22
22
|
const tryRequest = (cb, errCount = 0) => {
|
|
23
23
|
const { route, port, host } = ClientModule.__connectionData();
|
|
24
|
-
const singleFileURL =
|
|
25
|
-
const multiFileURL =
|
|
26
|
-
const defaultURL =
|
|
24
|
+
const singleFileURL = `${protocol}${host}:${port}/sf${route}/${fn}`;
|
|
25
|
+
const multiFileURL = `${protocol}${host}:${port}/mf${route}/${fn}`;
|
|
26
|
+
const defaultURL = `${protocol}${host}:${port}${route}/${fn}`;
|
|
27
27
|
const { file, files } = __arguments[0] || {};
|
|
28
28
|
const url = file ? singleFileURL : files ? multiFileURL : defaultURL;
|
|
29
29
|
|
|
30
30
|
if (url === defaultURL)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
httpClient
|
|
32
|
+
.request({
|
|
33
|
+
url: `${url}${
|
|
34
|
+
method === "get" && isObject(__arguments[0])
|
|
35
|
+
? makeQuery(__arguments[0])
|
|
36
|
+
: ""
|
|
37
|
+
}`,
|
|
38
|
+
method,
|
|
39
|
+
body: { __arguments },
|
|
40
|
+
})
|
|
38
41
|
.then((results) => cb(null, results))
|
|
39
42
|
.catch((err) => ErrorHandler(err, errCount, cb));
|
|
40
43
|
else
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
httpClient
|
|
45
|
+
.upload({
|
|
46
|
+
url,
|
|
47
|
+
method,
|
|
48
|
+
formData: { ...__arguments[0], __arguments },
|
|
49
|
+
})
|
|
46
50
|
.then((results) => cb(null, results))
|
|
47
51
|
.catch((err) => ErrorHandler(err, errCount, cb));
|
|
48
52
|
};
|
|
49
53
|
|
|
50
54
|
const ErrorHandler = (err, errCount, cb) => {
|
|
51
|
-
if (err.
|
|
55
|
+
if (err.SystemLynxService) {
|
|
52
56
|
cb(err);
|
|
53
57
|
} else if (errCount <= 3) {
|
|
54
58
|
console.log(err);
|
|
55
59
|
errCount++;
|
|
56
60
|
if (reconnectModule) reconnectModule(() => tryRequest(cb, errCount));
|
|
57
61
|
else reconnectService(() => tryRequest(cb, errCount));
|
|
58
|
-
} else
|
|
62
|
+
} else console.error(Error(`[SystemLynx][Service][Error]: Invalid route:${err}`));
|
|
59
63
|
};
|
|
60
64
|
|
|
61
65
|
return new Promise((resolve, reject) =>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const io = require("socket.io-client");
|
|
3
|
-
const
|
|
3
|
+
const createDispatcher = require("../../Dispatcher/Dispatcher");
|
|
4
4
|
|
|
5
5
|
module.exports = function SocketDispatcher(namespace, events = {}, systemContext) {
|
|
6
6
|
const dispatcher =
|
|
7
7
|
(this || {}).on && (this || {}).emit
|
|
8
8
|
? this
|
|
9
|
-
:
|
|
9
|
+
: createDispatcher.apply(this, [events, systemContext]);
|
|
10
10
|
const socket = io.connect(namespace);
|
|
11
11
|
socket.on("dispatch", (event) => dispatcher.emit(event.name, event.data, event));
|
|
12
12
|
socket.on("disconnect", () => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
module.exports = function loadConnectionData(
|
|
2
|
+
httpClient,
|
|
3
|
+
url,
|
|
4
|
+
{ limit = 3, wait = 1000 } = {}
|
|
5
|
+
) {
|
|
4
6
|
const errors = [];
|
|
5
7
|
|
|
6
8
|
return new Promise(function getData(resolve) {
|
|
7
|
-
|
|
9
|
+
httpClient.request({ method: "GET", url }, (err, results) => {
|
|
8
10
|
if (err) {
|
|
9
11
|
errors.push(err);
|
|
10
12
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const Service =
|
|
2
|
+
const createClient = require("../Client");
|
|
3
|
+
const createService = require("../../Service/Service");
|
|
4
|
+
const Service = createService();
|
|
5
5
|
const port = 6757;
|
|
6
6
|
const route = "service-test";
|
|
7
7
|
const url = `http://localhost:${port}/${route}`;
|
|
8
8
|
|
|
9
|
-
describe("
|
|
9
|
+
describe("createClient()", () => {
|
|
10
10
|
it("should return a SystemLynx Client", () => {
|
|
11
|
-
const Client =
|
|
11
|
+
const Client = createClient();
|
|
12
12
|
expect(Client)
|
|
13
13
|
.to.be.an("object")
|
|
14
14
|
.that.has.property("loadService")
|
|
@@ -36,13 +36,21 @@ describe("Client", () => {
|
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
await Service.startService({ route, port });
|
|
39
|
-
const Client =
|
|
39
|
+
const Client = createClient();
|
|
40
40
|
const buAPI = await Client.loadService(url);
|
|
41
41
|
|
|
42
42
|
expect(buAPI)
|
|
43
43
|
.to.be.an("object")
|
|
44
|
-
.that.has.all.keys(
|
|
44
|
+
.that.has.all.keys(
|
|
45
|
+
"emit",
|
|
46
|
+
"on",
|
|
47
|
+
"$clearEvent",
|
|
48
|
+
"resetConnection",
|
|
49
|
+
"disconnect",
|
|
50
|
+
"orders"
|
|
51
|
+
)
|
|
45
52
|
.that.respondsTo("emit")
|
|
53
|
+
.that.respondsTo("$clearEvent")
|
|
46
54
|
.that.respondsTo("on")
|
|
47
55
|
.that.respondsTo("resetConnection")
|
|
48
56
|
.that.respondsTo("disconnect");
|
|
@@ -52,6 +60,7 @@ describe("Client", () => {
|
|
|
52
60
|
.that.has.all.keys(
|
|
53
61
|
"emit",
|
|
54
62
|
"on",
|
|
63
|
+
"$clearEvent",
|
|
55
64
|
"disconnect",
|
|
56
65
|
"__setConnection",
|
|
57
66
|
"__connectionData",
|
|
@@ -61,8 +70,10 @@ describe("Client", () => {
|
|
|
61
70
|
"noArgTest"
|
|
62
71
|
)
|
|
63
72
|
.that.respondsTo("emit")
|
|
73
|
+
.that.respondsTo("$clearEvent")
|
|
64
74
|
.that.respondsTo("on")
|
|
65
75
|
.that.respondsTo("emit")
|
|
76
|
+
.that.respondsTo("$clearEvent")
|
|
66
77
|
.that.respondsTo("__setConnection")
|
|
67
78
|
.that.respondsTo("__connectionData")
|
|
68
79
|
.that.respondsTo("action1")
|
|
@@ -74,7 +85,7 @@ describe("Client", () => {
|
|
|
74
85
|
|
|
75
86
|
describe("Service", () => {
|
|
76
87
|
it("should be able to call methods from the frontend client to the backend Module", async () => {
|
|
77
|
-
const Client =
|
|
88
|
+
const Client = createClient();
|
|
78
89
|
const buAPI = await Client.loadService(url);
|
|
79
90
|
|
|
80
91
|
const results = await buAPI.orders.action1({ code: 3 });
|
|
@@ -89,7 +100,7 @@ describe("Service", () => {
|
|
|
89
100
|
});
|
|
90
101
|
});
|
|
91
102
|
it("should be able to send multiple arguments to the backend Module", async () => {
|
|
92
|
-
const Client =
|
|
103
|
+
const Client = createClient();
|
|
93
104
|
const buAPI = await Client.loadService(url);
|
|
94
105
|
const arg1 = 4,
|
|
95
106
|
arg2 = 5,
|
|
@@ -107,7 +118,7 @@ describe("Service", () => {
|
|
|
107
118
|
});
|
|
108
119
|
|
|
109
120
|
it("should be able to send no arguments and use a promise", async () => {
|
|
110
|
-
const Client =
|
|
121
|
+
const Client = createClient();
|
|
111
122
|
const buAPI = await Client.loadService(url);
|
|
112
123
|
const results = await buAPI.orders.noArgTest();
|
|
113
124
|
|
|
@@ -122,13 +133,13 @@ describe("Service", () => {
|
|
|
122
133
|
const route = "test-service";
|
|
123
134
|
const port = "8980";
|
|
124
135
|
const url = `http://localhost:${port}/${route}`;
|
|
125
|
-
const Service =
|
|
136
|
+
const Service = createService();
|
|
126
137
|
const eventTester = Service.module("eventTester", function () {
|
|
127
138
|
this.sendEvent = () => this.emit(eventName, { testPassed: true });
|
|
128
139
|
});
|
|
129
140
|
await Service.startService({ route, port });
|
|
130
141
|
|
|
131
|
-
const Client =
|
|
142
|
+
const Client = createClient();
|
|
132
143
|
|
|
133
144
|
const buAPI = await Client.loadService(url);
|
|
134
145
|
setTimeout(() => eventTester.emit(eventName, { testPassed: true }), 500);
|
|
@@ -148,8 +159,8 @@ describe("Service", () => {
|
|
|
148
159
|
});
|
|
149
160
|
|
|
150
161
|
it("should be able to send REST http requests", async () => {
|
|
151
|
-
const Client =
|
|
152
|
-
const Service =
|
|
162
|
+
const Client = createClient();
|
|
163
|
+
const Service = createService();
|
|
153
164
|
const route = "rest-tester";
|
|
154
165
|
const port = "8492";
|
|
155
166
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -183,7 +194,7 @@ describe("Service", () => {
|
|
|
183
194
|
});
|
|
184
195
|
|
|
185
196
|
it("should be able to use 'useReturnValue' configuration option to enable synchronous return values from Module methods", async () => {
|
|
186
|
-
const service =
|
|
197
|
+
const service = createService();
|
|
187
198
|
const route = "sync/test";
|
|
188
199
|
const port = 4920;
|
|
189
200
|
const host = "localhost";
|
|
@@ -199,7 +210,7 @@ describe("Service", () => {
|
|
|
199
210
|
port,
|
|
200
211
|
host,
|
|
201
212
|
});
|
|
202
|
-
const Client =
|
|
213
|
+
const Client = createClient();
|
|
203
214
|
const { AsyncMath } = await Client.loadService(url);
|
|
204
215
|
const results = await AsyncMath.max(10, 2);
|
|
205
216
|
expect(results).to.equal(10);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const SocketDispatcher = require("../components/SocketDispatcher");
|
|
3
|
-
const { WebSocket, SocketServer } =
|
|
3
|
+
const { WebSocket, SocketServer } =
|
|
4
|
+
require("../../ServerManager/components/WebSocketServer")();
|
|
4
5
|
|
|
5
6
|
const namespace = "test-namespace";
|
|
6
7
|
const port = 4592;
|
|
@@ -14,9 +15,10 @@ describe("SocketDispatcher", () => {
|
|
|
14
15
|
it("should return an EventDispatcher object with methods on and emit", async () => {
|
|
15
16
|
expect(dispatcher)
|
|
16
17
|
.to.be.an("object")
|
|
17
|
-
.that.has.all.keys("on", "emit", "disconnect")
|
|
18
|
+
.that.has.all.keys("on", "emit", "$clearEvent", "disconnect")
|
|
18
19
|
.that.respondsTo("on")
|
|
19
20
|
.that.respondsTo("emit")
|
|
21
|
+
.that.respondsTo("$clearEvent")
|
|
20
22
|
.that.respondsTo("disconnect");
|
|
21
23
|
});
|
|
22
24
|
it("Should be able to emit and handle events", (done) => {
|
|
@@ -25,19 +27,25 @@ describe("SocketDispatcher", () => {
|
|
|
25
27
|
done();
|
|
26
28
|
});
|
|
27
29
|
dispatcher.on("connect", () => console.log(`I'm all the way connected!`));
|
|
28
|
-
setTimeout(
|
|
30
|
+
setTimeout(
|
|
31
|
+
() => socket.emit("dispatch", { name: eventName, data: { testPassed: true } }),
|
|
32
|
+
500
|
|
33
|
+
);
|
|
29
34
|
});
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
describe("SocketDispatcher.apply()", () => {
|
|
33
38
|
const eventName = "testing-event";
|
|
34
|
-
const dispatcher = SocketDispatcher.apply({}, [
|
|
39
|
+
const dispatcher = SocketDispatcher.apply({}, [
|
|
40
|
+
`http://localhost:${port}/${namespace}`,
|
|
41
|
+
]);
|
|
35
42
|
it("should return an EventDispatcher object with methods on and emit", async () => {
|
|
36
43
|
expect(dispatcher)
|
|
37
44
|
.to.be.an("object")
|
|
38
|
-
.that.has.all.keys("on", "emit", "disconnect")
|
|
45
|
+
.that.has.all.keys("on", "emit", "$clearEvent", "disconnect")
|
|
39
46
|
.that.respondsTo("on")
|
|
40
47
|
.that.respondsTo("emit")
|
|
48
|
+
.that.respondsTo("$clearEvent")
|
|
41
49
|
.that.respondsTo("disconnect");
|
|
42
50
|
});
|
|
43
51
|
it("Should be able to emit and handle events", (done) => {
|
|
@@ -49,6 +57,9 @@ describe("SocketDispatcher.apply()", () => {
|
|
|
49
57
|
done();
|
|
50
58
|
});
|
|
51
59
|
|
|
52
|
-
setTimeout(
|
|
60
|
+
setTimeout(
|
|
61
|
+
() => socket.emit("dispatch", { name: eventName, data: { testPassed: true } }),
|
|
62
|
+
500
|
|
63
|
+
);
|
|
53
64
|
});
|
|
54
65
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
module.exports = function
|
|
2
|
+
module.exports = function createDispatcher(events = {}, systemContext) {
|
|
3
3
|
const Dispatcher = this || {};
|
|
4
4
|
|
|
5
5
|
Dispatcher.emit = (eventName, data, event) => {
|
|
@@ -24,5 +24,20 @@ module.exports = function SystemLynxDispatcher(events = {}, systemContext) {
|
|
|
24
24
|
return Dispatcher;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
Dispatcher.$clearEvent = (eventName, fn) => {
|
|
28
|
+
if (!events[eventName]) return Dispatcher;
|
|
29
|
+
|
|
30
|
+
if (!fn) {
|
|
31
|
+
// Clear all listeners for the given event
|
|
32
|
+
delete events[eventName];
|
|
33
|
+
} else {
|
|
34
|
+
// Remove the listener function with the specified name from the event's listener array
|
|
35
|
+
events[eventName] = events[eventName].filter((callback) => {
|
|
36
|
+
return callback.name !== fn;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return Dispatcher;
|
|
41
|
+
};
|
|
27
42
|
return Dispatcher;
|
|
28
43
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const Dispatcher = require("./Dispatcher");
|
|
3
3
|
|
|
4
|
-
describe("
|
|
4
|
+
describe("createDispatcher", () => {
|
|
5
5
|
const dispatcher = Dispatcher();
|
|
6
6
|
it("should return an EventDispatcher object with methods on and emit", async () => {
|
|
7
7
|
expect(dispatcher)
|
|
8
8
|
.to.be.an("object")
|
|
9
|
-
.that.has.all.keys("on", "emit")
|
|
9
|
+
.that.has.all.keys("on", "emit", "$clearEvent")
|
|
10
10
|
.that.respondsTo("on")
|
|
11
|
-
.that.respondsTo("emit")
|
|
11
|
+
.that.respondsTo("emit")
|
|
12
|
+
.that.respondsTo("$clearEvent");
|
|
12
13
|
});
|
|
13
14
|
it("Should be able to emit and handle events", (done) => {
|
|
14
15
|
dispatcher.on("test", (data) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const httpClient = require("request");
|
|
3
3
|
const json = true;
|
|
4
4
|
|
|
5
|
-
module.exports = function
|
|
5
|
+
module.exports = function createClient() {
|
|
6
6
|
const Client = this || {};
|
|
7
7
|
Client.request = ({ method, url, body }, cb) => {
|
|
8
8
|
const tryRequest = (callback) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const LoadBalancer = require("../LoadBalancer")();
|
|
3
|
-
const
|
|
3
|
+
const createService = require("../../Service/Service");
|
|
4
4
|
const HttpClient = require("../../HttpClient/HttpClient")();
|
|
5
5
|
const lbPort = 5030;
|
|
6
6
|
const route = "loadbalancer";
|
|
@@ -9,14 +9,33 @@ describe("LoadBalancer()", () => {
|
|
|
9
9
|
it("should return a SystemLynx LoadBalancer", () => {
|
|
10
10
|
expect(LoadBalancer)
|
|
11
11
|
.to.be.an("object")
|
|
12
|
-
.that.has.all.keys(
|
|
12
|
+
.that.has.all.keys(
|
|
13
|
+
"startService",
|
|
14
|
+
"server",
|
|
15
|
+
"WebSocket",
|
|
16
|
+
"module",
|
|
17
|
+
"clones",
|
|
18
|
+
"before"
|
|
19
|
+
)
|
|
13
20
|
.that.respondsTo("startService")
|
|
14
|
-
.that.respondsTo("module")
|
|
21
|
+
.that.respondsTo("module")
|
|
22
|
+
.that.respondsTo("before");
|
|
15
23
|
expect(LoadBalancer.clones)
|
|
16
24
|
.to.be.an("object")
|
|
17
|
-
.that.has.all.keys(
|
|
25
|
+
.that.has.all.keys(
|
|
26
|
+
"on",
|
|
27
|
+
"emit",
|
|
28
|
+
"$clearEvent",
|
|
29
|
+
"before",
|
|
30
|
+
"clones",
|
|
31
|
+
"register",
|
|
32
|
+
"dispatch",
|
|
33
|
+
"assignDispatch"
|
|
34
|
+
)
|
|
18
35
|
.that.respondsTo("emit")
|
|
36
|
+
.that.respondsTo("$clearEvent")
|
|
19
37
|
.that.respondsTo("on")
|
|
38
|
+
.that.respondsTo("before")
|
|
20
39
|
.that.respondsTo("register")
|
|
21
40
|
.that.respondsTo("dispatch")
|
|
22
41
|
.that.respondsTo("assignDispatch")
|
|
@@ -71,6 +90,8 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
71
90
|
"on",
|
|
72
91
|
"emit",
|
|
73
92
|
"$emit",
|
|
93
|
+
"$clearEvent",
|
|
94
|
+
"before",
|
|
74
95
|
"register",
|
|
75
96
|
"dispatch",
|
|
76
97
|
"assignDispatch",
|
|
@@ -78,6 +99,8 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
78
99
|
)
|
|
79
100
|
.that.respondsTo("on")
|
|
80
101
|
.that.respondsTo("emit")
|
|
102
|
+
.that.respondsTo("$clearEvent")
|
|
103
|
+
.that.respondsTo("before")
|
|
81
104
|
.that.respondsTo("$emit")
|
|
82
105
|
.that.respondsTo("register")
|
|
83
106
|
.that.respondsTo("dispatch")
|
|
@@ -87,7 +110,7 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
87
110
|
});
|
|
88
111
|
|
|
89
112
|
it("should be able to use clones.register(connData, callback) method to host connection", async () => {
|
|
90
|
-
const Service =
|
|
113
|
+
const Service = createService();
|
|
91
114
|
const { route, port, host } = test_service1;
|
|
92
115
|
await Service.startService({ route, port, host });
|
|
93
116
|
LoadBalancer.clones.register({ route, port, host }, () => {});
|
|
@@ -113,8 +136,8 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
113
136
|
|
|
114
137
|
it("should be able to manager the routing to multiple clones of the same Service", async () => {
|
|
115
138
|
const { route, port1, port2, host } = test_service2;
|
|
116
|
-
const Clone1 =
|
|
117
|
-
const Clone2 =
|
|
139
|
+
const Clone1 = createService();
|
|
140
|
+
const Clone2 = createService();
|
|
118
141
|
await Clone1.startService({ route, port: port1, host });
|
|
119
142
|
await Clone2.startService({ route, port: port2, host });
|
|
120
143
|
LoadBalancer.clones.register({ route, port: port1, host }, () => {});
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const createServer = require("./components/Server");
|
|
3
|
+
const createRouter = require("./components/Router");
|
|
4
4
|
const SocketEmitter = require("./components/SocketEmitter");
|
|
5
|
-
const
|
|
5
|
+
const createWebSocket = require("./components/WebSocketServer");
|
|
6
6
|
const parseMethods = require("./components/parseMethods");
|
|
7
7
|
const shortId = require("shortid");
|
|
8
|
+
const randomPort = () => parseInt(Math.random() * parseInt(Math.random() * 10000)) + 1023;
|
|
9
|
+
const createSSLServer = (app, options) => {
|
|
10
|
+
const https = require("https");
|
|
11
|
+
return https.createServer(options, app);
|
|
12
|
+
};
|
|
8
13
|
|
|
9
|
-
module.exports = function
|
|
14
|
+
module.exports = function createServerManager(customServer, customWebSocketServer) {
|
|
10
15
|
let serverConfigurations = {
|
|
11
16
|
route: null,
|
|
12
17
|
port: null,
|
|
@@ -16,21 +21,27 @@ module.exports = function SystemLynxServerManager() {
|
|
|
16
21
|
useREST: false,
|
|
17
22
|
useService: true,
|
|
18
23
|
staticRouting: false,
|
|
19
|
-
|
|
24
|
+
ssl: { key: "", cert: "" },
|
|
25
|
+
validators: { $all: [] },
|
|
20
26
|
};
|
|
21
|
-
const server =
|
|
22
|
-
const router =
|
|
23
|
-
const { SocketServer, WebSocket } =
|
|
27
|
+
const server = createServer(customServer);
|
|
28
|
+
const router = createRouter(server, () => serverConfigurations);
|
|
29
|
+
const { SocketServer, WebSocket } = createWebSocket(customWebSocketServer);
|
|
24
30
|
const moduleQueue = [];
|
|
25
31
|
const modules = [];
|
|
26
32
|
|
|
27
33
|
const ServerManager = { server, WebSocket };
|
|
28
34
|
|
|
29
35
|
ServerManager.startService = (options) => {
|
|
30
|
-
let {
|
|
36
|
+
let {
|
|
37
|
+
route,
|
|
38
|
+
host = "localhost",
|
|
39
|
+
port,
|
|
40
|
+
socketPort = randomPort(),
|
|
41
|
+
staticRouting,
|
|
42
|
+
ssl,
|
|
43
|
+
} = options;
|
|
31
44
|
|
|
32
|
-
socketPort =
|
|
33
|
-
socketPort || parseInt(Math.random() * parseInt(Math.random() * 10000)) + 1023;
|
|
34
45
|
const namespace = staticRouting ? route : shortId();
|
|
35
46
|
SocketServer.listen(socketPort);
|
|
36
47
|
SocketEmitter.apply(ServerManager, [namespace, WebSocket]);
|
|
@@ -38,7 +49,8 @@ module.exports = function SystemLynxServerManager() {
|
|
|
38
49
|
route = route.charAt(0) === "/" ? route.substr(1) : route;
|
|
39
50
|
route =
|
|
40
51
|
route.charAt(route.length - 1) === "/" ? route.substr(route.length - 1) : route;
|
|
41
|
-
const
|
|
52
|
+
const protocol = ssl ? "https" : "http";
|
|
53
|
+
const serviceUrl = `${protocol}://${host}:${port}/${route}`;
|
|
42
54
|
|
|
43
55
|
serverConfigurations = {
|
|
44
56
|
...serverConfigurations,
|
|
@@ -57,46 +69,44 @@ module.exports = function SystemLynxServerManager() {
|
|
|
57
69
|
SystemLynxService: true,
|
|
58
70
|
};
|
|
59
71
|
|
|
60
|
-
const selectModules = (moduleList) =>
|
|
61
|
-
moduleList.reduce(
|
|
62
|
-
(sum, moduleName) =>
|
|
63
|
-
sum.concat(modules.find(({ name }) => name === moduleName) || []),
|
|
64
|
-
[]
|
|
65
|
-
);
|
|
66
|
-
|
|
67
72
|
server.get(`/${route}`, (req, res) => {
|
|
68
73
|
//The route will return connection data for the service including an array of
|
|
69
74
|
//modules (objects) which contain instructions on how to make request to each object
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
res.json({
|
|
73
|
-
...connectionData,
|
|
74
|
-
modules: query.modules ? selectModules(query.modules.split(",")) : modules,
|
|
75
|
-
});
|
|
75
|
+
res.json({ ...connectionData, modules });
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
return new Promise((resolve) =>
|
|
79
|
-
server
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
const _server = ssl ? createSSLServer(server, ssl) : server;
|
|
80
|
+
_server.listen(port, () => {
|
|
80
81
|
console.log(`[SystemLynx][Service]: Listening on ${serviceUrl}`);
|
|
81
82
|
moduleQueue.forEach(({ name, Module, reserved_methods }) =>
|
|
82
83
|
ServerManager.addModule(name, Module, reserved_methods)
|
|
83
84
|
);
|
|
84
85
|
moduleQueue.length = 0;
|
|
85
86
|
resolve(connectionData);
|
|
86
|
-
})
|
|
87
|
-
);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
ServerManager.addModule = (name, Module, reserved_methods = []) => {
|
|
91
|
-
const {
|
|
92
|
-
|
|
92
|
+
const {
|
|
93
|
+
host,
|
|
94
|
+
route,
|
|
95
|
+
serviceUrl,
|
|
96
|
+
staticRouting,
|
|
97
|
+
useService,
|
|
98
|
+
useREST,
|
|
99
|
+
socketPort,
|
|
100
|
+
validators,
|
|
101
|
+
} = serverConfigurations;
|
|
93
102
|
|
|
94
103
|
if (!serviceUrl) return moduleQueue.push({ name, Module, reserved_methods });
|
|
95
|
-
const
|
|
104
|
+
const exclude_methods = ["on", "emit", "before", "$clearEvent", ...reserved_methods];
|
|
105
|
+
const methods = parseMethods(Module, exclude_methods, useREST);
|
|
96
106
|
const namespace = staticRouting ? name : shortId();
|
|
97
107
|
|
|
98
108
|
SocketEmitter.apply(Module, [namespace, WebSocket]);
|
|
99
|
-
|
|
109
|
+
const _validators = [...validators.$all, ...(validators[name] || [])];
|
|
100
110
|
if (useService) {
|
|
101
111
|
const path = staticRouting ? `${route}/${name}` : `${shortId()}/${shortId()}`;
|
|
102
112
|
|
|
@@ -106,19 +116,48 @@ module.exports = function SystemLynxServerManager() {
|
|
|
106
116
|
name,
|
|
107
117
|
methods,
|
|
108
118
|
});
|
|
109
|
-
methods.forEach((method) =>
|
|
119
|
+
methods.forEach((method) => {
|
|
120
|
+
const nsp = `${name}.${method.fn}`;
|
|
121
|
+
const customValidators = [..._validators, ...(validators[nsp] || [])];
|
|
122
|
+
router.addService(Module, path, method, name, customValidators);
|
|
123
|
+
});
|
|
110
124
|
}
|
|
111
125
|
if (useREST)
|
|
112
126
|
methods.forEach((method) => {
|
|
127
|
+
const nsp = `${name}.${method.fn}`;
|
|
128
|
+
const customValidators = [..._validators, ...(validators[nsp] || [])];
|
|
113
129
|
switch (method.fn) {
|
|
114
130
|
case "get":
|
|
115
131
|
case "put":
|
|
116
132
|
case "post":
|
|
117
133
|
case "delete":
|
|
118
|
-
router.addREST(Module, `${route}/${name}`, method, name);
|
|
134
|
+
router.addREST(Module, `${route}/${name}`, method, name, customValidators);
|
|
119
135
|
}
|
|
120
136
|
});
|
|
121
137
|
};
|
|
122
|
-
|
|
138
|
+
ServerManager.addRouteHandler = (...args) => {
|
|
139
|
+
const name = typeof args[0] === "string" ? args.shift() : "$all";
|
|
140
|
+
args.forEach(async (middleware) => {
|
|
141
|
+
if (!serverConfigurations.validators[name])
|
|
142
|
+
serverConfigurations.validators[name] = [];
|
|
143
|
+
serverConfigurations.validators[name].push(async function (req, res, next) {
|
|
144
|
+
try {
|
|
145
|
+
await middleware(req, res, next);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
res.sendError(error);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
};
|
|
123
152
|
return ServerManager;
|
|
124
153
|
};
|
|
154
|
+
|
|
155
|
+
//creating an ssl setup with openssl cli
|
|
156
|
+
//1. `openssl genrsa -out key.pem` to generate a private key
|
|
157
|
+
//2. create a certificate signing request using the key we just generated
|
|
158
|
+
// `openssl req -new -key key.pem -out csr.pem`
|
|
159
|
+
//3. Answer the prompts in the terminal
|
|
160
|
+
//4. use the newly generate csr to generate a ssl certificate
|
|
161
|
+
// openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem
|
|
162
|
+
//(x509 is the standard to use for the certificate, days are the number of day the cert is valid)
|
|
163
|
+
//5. csr.pem is no longer needed
|