systemlynx 1.6.0 → 1.7.1
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 +67 -8
- package/README.md +8 -8
- package/index.test.js +6 -12
- package/package.json +3 -3
- package/systemlynx/App/App.js +17 -15
- package/systemlynx/App/components/loadModules.js +4 -2
- package/systemlynx/App/components/loadServices.js +2 -2
- package/systemlynx/App/tests/App.test.js +61 -25
- package/systemlynx/Client/Client.js +23 -8
- package/systemlynx/Client/components/ClientModule.js +13 -4
- package/systemlynx/Client/components/ServiceRequestHandler.js +8 -2
- package/systemlynx/Client/components/loadConnectionData.js +3 -1
- package/systemlynx/Client/tests/Client.test.js +15 -15
- package/systemlynx/Dispatcher/Dispatcher.js +9 -5
- package/systemlynx/HttpClient/HttpClient.test.js +40 -56
- package/systemlynx/LoadBalancer/tests/LoadBalancer.test.js +17 -10
- package/systemlynx/ServerManager/ServerManager.js +23 -9
- package/systemlynx/ServerManager/components/Router.js +5 -5
- package/systemlynx/ServerManager/components/SocketEmitter.js +3 -2
- package/systemlynx/ServerManager/tests/ServerManager.test.js +2 -4
- package/systemlynx/Service/Service.js +6 -6
- package/systemlynx/Service/Service.test.js +7 -9
- package/systemlynx/utils/System.js +2 -2
- package/systemlynx/utils/SystemContext.js +2 -2
package/API.md
CHANGED
|
@@ -51,25 +51,84 @@ Welcome to the docs! Following is a list of the objects used and created when de
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
53
|
<details>
|
|
54
|
-
<summary><b><a href="https://github.com/Odion100/SystemLynx/tasksjs2.0/API.md">
|
|
54
|
+
<summary><b><a href="https://github.com/Odion100/SystemLynx/tasksjs2.0/API.md">ServerModule</a></b></summary>
|
|
55
55
|
|
|
56
|
-
- [**
|
|
57
|
-
- [**on(name,
|
|
58
|
-
- [**emit()**]()
|
|
56
|
+
- [**...constructedMethods**]()
|
|
57
|
+
- [**on(name, callback)**]()
|
|
58
|
+
- [**emit(name, data)**]()
|
|
59
59
|
|
|
60
60
|
</details>
|
|
61
61
|
|
|
62
62
|
<details>
|
|
63
|
-
<summary><b><a href="https://github.com/Odion100/SystemLynx/tasksjs2.0/API.md">
|
|
63
|
+
<summary><b><a href="https://github.com/Odion100/SystemLynx/tasksjs2.0/API.md">ClientModule</a></b></summary>
|
|
64
64
|
|
|
65
|
-
- [**
|
|
66
|
-
- [**on(name,
|
|
67
|
-
- [**emit()**]()
|
|
65
|
+
- [**...loadedMethods**]()
|
|
66
|
+
- [**on(name, callback)**]()
|
|
67
|
+
- [**emit(name, data)**]()
|
|
68
68
|
|
|
69
69
|
</details>
|
|
70
70
|
|
|
71
71
|
---
|
|
72
72
|
|
|
73
|
+
## Service
|
|
74
|
+
|
|
75
|
+
In SystemLynx a **Service** is a class used to host objects that can be later loaded into a client application using a SystemLynx **Client.** Get a handle on a SystemLynx **Service** by de-structuring the SystemLynx export.
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const { Service } = require(“systemlynx”)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Service.module(name, constructor)
|
|
82
|
+
|
|
83
|
+
Use the `Service.module(name, constructor/object)` method to create a **ServerModule**, which is an object that is hosted by a **SystemLynx Service**. This will allows you to later load an instance of that object into a client application. The **Service.module(name, constructor)** method takes the (string) name assigned to the object as the first argument, and the object itself, or a constructor function, as the second argument, and will return the constructed **ServerModule.** See the examples below.
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const { Service } = require("systemlynx");
|
|
87
|
+
|
|
88
|
+
const UsersConstructor = {
|
|
89
|
+
add:function(data) {
|
|
90
|
+
return { message: "You have successfully called Users.add(...)" };
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
constr OrdersConstructor = function () {
|
|
94
|
+
const Orders = this;
|
|
95
|
+
|
|
96
|
+
Orders.find = function (arg1, arg2) {
|
|
97
|
+
return { message: "You have successfully called the Orders.find(...)" };
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const Users = Service.module("Users", UsersConstructor);
|
|
102
|
+
|
|
103
|
+
const Orders = Service.module("Orders", OrdersConstructor);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Service.startService(options)
|
|
107
|
+
|
|
108
|
+
Use the `Service.startService(options)` method to setup hosting and routing for the **Service**. Calling this method will start an **ExpressJS** Server and a **Socket.io** WebSocket Server, and allow the modules created by the **Service** to be loaded into a client application. This method returns a promise that will resolve once the Express server is running.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const { Service } = require("systemlynx");
|
|
112
|
+
const route = "my-route/whatever";
|
|
113
|
+
const port = 8100;
|
|
114
|
+
const host = "localhost";
|
|
115
|
+
|
|
116
|
+
const promise = Service.startService({ route, port, host });
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Following is a list of options that can be passed to the **Service.startService(options)** method.
|
|
120
|
+
|
|
121
|
+
| Name | Type | O/R/C | Description |
|
|
122
|
+
| :------------ | :-----: | :---: | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| route | string | R | The route from which the service can be loaded. |
|
|
124
|
+
| port | number | R | The port on which to start the Express server. |
|
|
125
|
+
| host | string | O | The host from which the **Service** can be reached. |
|
|
126
|
+
| socketPort | string | R | The port on which to start the Socket.io Websocket server. <br/><br/> Default value : **_random for digit number_** |
|
|
127
|
+
| useRest | boolean | O | When this is true a RESTful route will be created for any **ServerModule** method which is named after a REST method <br/><br/> Default value: `false` |
|
|
128
|
+
| useService | boolean | O | The route from which the service can be loaded. |
|
|
129
|
+
| staticRouting | boolean | O | The route from which the service can be loaded. |
|
|
130
|
+
| middleware | string | R | The route from which the service can be loaded. |
|
|
131
|
+
|
|
73
132
|
## App
|
|
74
133
|
|
|
75
134
|
**App** combinds the both functionalites of SystemLynx Service and Client into one object, while also providing a module interface and lifecycle events. Access the App instance by deconcatanating from the object return when loading SystemLynx `require("systemlynx")`.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SystemLynx JS   
|
|
2
2
|
|
|
3
|
-
SystemLynx is a framework for developing modular web APIs in NodeJS. It's a wrapper on top of ExpressJS and Socket.io. With SystemLynx, instead of
|
|
3
|
+
SystemLynx is a framework for developing modular web APIs in NodeJS. It's a wrapper on top of ExpressJS and Socket.io. With SystemLynx, instead of creating a server with many endpoints, you can simply create objects and load those objects from a server into a client application. Basically any objects hosted by a SystemLynx Service can be loaded and used by a SystemLynx Client.
|
|
4
4
|
|
|
5
5
|
SystemLynx comes with the following objects that are used for web app development:
|
|
6
6
|
|
|
@@ -8,13 +8,13 @@ SystemLynx comes with the following objects that are used for web app developmen
|
|
|
8
8
|
const { App, Service, Client, LoadBalancer } = require("systemlynx");
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Call `require("systemlynx")` and
|
|
11
|
+
Call `require("systemlynx")` and destructrue from the object it returns. The main abstractions used for client-to-server interactions are the following:
|
|
12
12
|
|
|
13
13
|
- **Service** - Used to create and host objects that can be loaded and used by a SystemLynx Client.
|
|
14
14
|
- **Client** - Used in a client application to load a **Service**, which contains all the objects added to the **Service**.
|
|
15
15
|
- **App** - Provides a modular interface and lifecycle methods for asynchronously creating and loading **Services**.
|
|
16
16
|
|
|
17
|
-
Find the full [API Documentation](https://github.com/Odion100/SystemLynx/blob/
|
|
17
|
+
Find the full [API Documentation](https://github.com/Odion100/SystemLynx/blob/master/API.md#tasksjs-api-documentation) here.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -57,7 +57,7 @@ Service.module("Orders", function () {
|
|
|
57
57
|
const Orders = this;
|
|
58
58
|
|
|
59
59
|
Orders.find = async function (arg1, arg2) {
|
|
60
|
-
console.log(
|
|
60
|
+
console.log(arg1, arg2);
|
|
61
61
|
return { message: "You have successfully called the Orders.find method" };
|
|
62
62
|
};
|
|
63
63
|
});
|
|
@@ -82,8 +82,8 @@ Service.module("Users", Users);
|
|
|
82
82
|
Service.module("Orders", function () {
|
|
83
83
|
const Orders = this;
|
|
84
84
|
|
|
85
|
-
Orders.find = function (arg1, arg2) {
|
|
86
|
-
console.log(
|
|
85
|
+
Orders.find = async function (arg1, arg2) {
|
|
86
|
+
console.log(arg1, arg2);
|
|
87
87
|
return { message: "You have successfully called the Orders.find method" };
|
|
88
88
|
};
|
|
89
89
|
});
|
|
@@ -165,8 +165,8 @@ Service.module("Users", Users);
|
|
|
165
165
|
Service.module("Orders", function () {
|
|
166
166
|
const Orders = this;
|
|
167
167
|
|
|
168
|
-
Orders.find = function (arg1, arg2) {
|
|
169
|
-
console.log(
|
|
168
|
+
Orders.find = async function (arg1, arg2) {
|
|
169
|
+
console.log(arg1, arg2);
|
|
170
170
|
return { message: "You have successfully called the Orders.find method" };
|
|
171
171
|
};
|
|
172
172
|
});
|
package/index.test.js
CHANGED
|
@@ -35,6 +35,7 @@ describe("SystemLynx Objects", () => {
|
|
|
35
35
|
"module",
|
|
36
36
|
"on",
|
|
37
37
|
"emit",
|
|
38
|
+
"use",
|
|
38
39
|
"startService",
|
|
39
40
|
"loadService",
|
|
40
41
|
"onLoad",
|
|
@@ -43,6 +44,7 @@ describe("SystemLynx Objects", () => {
|
|
|
43
44
|
.that.respondsTo("module")
|
|
44
45
|
.that.respondsTo("on")
|
|
45
46
|
.that.respondsTo("emit")
|
|
47
|
+
.that.respondsTo("use")
|
|
46
48
|
.that.respondsTo("startService")
|
|
47
49
|
.that.respondsTo("loadService")
|
|
48
50
|
.that.respondsTo("onLoad")
|
|
@@ -67,10 +69,8 @@ describe("SystemLynx Objects", () => {
|
|
|
67
69
|
it("should return a SystemLynx LoadBalancer", () => {
|
|
68
70
|
expect(LoadBalancer)
|
|
69
71
|
.to.be.an("object")
|
|
70
|
-
.that.has.all.keys("startService", "
|
|
72
|
+
.that.has.all.keys("startService", "server", "WebSocket", "clones", "module")
|
|
71
73
|
.that.respondsTo("startService")
|
|
72
|
-
.that.respondsTo("Server")
|
|
73
|
-
.that.respondsTo("WebSocket")
|
|
74
74
|
.that.respondsTo("module");
|
|
75
75
|
expect(LoadBalancer.clones)
|
|
76
76
|
.to.be.an("object")
|
|
@@ -87,18 +87,12 @@ describe("SystemLynx Objects", () => {
|
|
|
87
87
|
it("should return a SystemLynx ServerManager instance", () => {
|
|
88
88
|
expect(ServerManager)
|
|
89
89
|
.to.be.an("Object")
|
|
90
|
-
.that.has.all.keys(["startService", "addModule", "
|
|
90
|
+
.that.has.all.keys(["startService", "addModule", "server", "WebSocket"])
|
|
91
91
|
.that.respondsTo("startService")
|
|
92
|
-
.that.respondsTo("addModule")
|
|
93
|
-
.that.respondsTo("Server")
|
|
94
|
-
.that.respondsTo("WebSocket");
|
|
92
|
+
.that.respondsTo("addModule");
|
|
95
93
|
});
|
|
96
94
|
|
|
97
95
|
it("should return a new instance of a Service", () => {
|
|
98
|
-
expect(Service)
|
|
99
|
-
.to.be.an("object")
|
|
100
|
-
.that.respondsTo("startService")
|
|
101
|
-
.that.respondsTo("Server")
|
|
102
|
-
.that.respondsTo("WebSocket");
|
|
96
|
+
expect(Service).to.be.an("object").that.respondsTo("startService");
|
|
103
97
|
});
|
|
104
98
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "systemlynx",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"body-parser": "^1.18.3",
|
|
12
|
-
"chai-as-promised": "^7.1.1",
|
|
13
12
|
"express": "^4.16.4",
|
|
14
|
-
"jest": "^24.9.0",
|
|
15
13
|
"mime": "^2.4.0",
|
|
16
14
|
"multer": "^1.4.2",
|
|
17
15
|
"request": "^2.88.0",
|
|
@@ -30,7 +28,9 @@
|
|
|
30
28
|
"homepage": "https://github.com/Odion100/SystemLynx#readme",
|
|
31
29
|
"devDependencies": {
|
|
32
30
|
"chai": "^4.3.4",
|
|
31
|
+
"chai-as-promised": "^7.1.1",
|
|
33
32
|
"cz-conventional-changelog": "^3.3.0",
|
|
33
|
+
"jest": "^24.9.0",
|
|
34
34
|
"mocha": "^6.2.0"
|
|
35
35
|
},
|
|
36
36
|
"config": {
|
package/systemlynx/App/App.js
CHANGED
|
@@ -3,14 +3,20 @@ const { isNode } = require("../../utils/ProcessChecker");
|
|
|
3
3
|
const SystemLynxService = require("../Service/Service");
|
|
4
4
|
const SystemLynxDispatcher = require("../Dispatcher/Dispatcher");
|
|
5
5
|
const initializeApp = require("./components/initializeApp");
|
|
6
|
-
const
|
|
6
|
+
const SystemLynxContext = require("../utils/SystemContext");
|
|
7
7
|
const System = require("../utils/System");
|
|
8
8
|
|
|
9
9
|
module.exports = function SystemLynxApp() {
|
|
10
10
|
const system = new System();
|
|
11
|
-
const systemContext =
|
|
11
|
+
const systemContext = SystemLynxContext(system);
|
|
12
12
|
const App = SystemLynxDispatcher(undefined, systemContext);
|
|
13
|
-
|
|
13
|
+
const plugins = [];
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
plugins.forEach((plugin) => {
|
|
16
|
+
if (typeof plugin === "function") plugin.apply({}, [App, system]);
|
|
17
|
+
});
|
|
18
|
+
initializeApp(system, App, systemContext);
|
|
19
|
+
}, 0);
|
|
14
20
|
|
|
15
21
|
if (isNode) {
|
|
16
22
|
system.Service = SystemLynxService(systemContext);
|
|
@@ -21,33 +27,25 @@ module.exports = function SystemLynxApp() {
|
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
App.module = (name, __constructor) => {
|
|
24
|
-
system.
|
|
25
|
-
name,
|
|
26
|
-
__constructor,
|
|
27
|
-
});
|
|
30
|
+
system.modules.push({ name, __constructor });
|
|
28
31
|
return App;
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
App.loadService = (name, url) => {
|
|
33
|
-
system.
|
|
34
|
-
name,
|
|
35
|
-
url,
|
|
36
|
-
onLoad: null,
|
|
37
|
-
client: {},
|
|
38
|
-
});
|
|
36
|
+
system.services.push({ name, url, onLoad: null, client: {} });
|
|
39
37
|
return App;
|
|
40
38
|
};
|
|
41
39
|
|
|
42
40
|
App.onLoad = (handler) => {
|
|
43
|
-
const service = system.
|
|
41
|
+
const service = system.services[system.services.length - 1];
|
|
44
42
|
service.onLoad = handler;
|
|
45
43
|
return App;
|
|
46
44
|
};
|
|
47
45
|
|
|
48
46
|
App.config = (__constructor) => {
|
|
49
47
|
if (typeof __constructor === "function")
|
|
50
|
-
system.configurations = { __constructor, module:
|
|
48
|
+
system.configurations = { __constructor, module: SystemLynxContext(system) };
|
|
51
49
|
else
|
|
52
50
|
throw Error(
|
|
53
51
|
"[SystemLynx][App][Error]: App.config(...) methods requires a constructor function as its first parameter."
|
|
@@ -55,5 +53,9 @@ module.exports = function SystemLynxApp() {
|
|
|
55
53
|
return App;
|
|
56
54
|
};
|
|
57
55
|
|
|
56
|
+
App.use = (plugin) => {
|
|
57
|
+
plugins.push(plugin);
|
|
58
|
+
return App;
|
|
59
|
+
};
|
|
58
60
|
return App;
|
|
59
61
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
module.exports = async function loadModules(system, App) {
|
|
2
|
-
system.
|
|
2
|
+
system.modules.forEach(
|
|
3
3
|
(mod) => (mod.module = system.Service.module(mod.name, mod.__constructor))
|
|
4
4
|
);
|
|
5
5
|
|
|
6
|
-
if (system.routing)
|
|
6
|
+
if (system.routing) {
|
|
7
|
+
system.connectionData = await system.Service.startService(system.routing);
|
|
8
|
+
}
|
|
7
9
|
App.emit("ready", system);
|
|
8
10
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const SystemLynxClient = require("../../Client/Client");
|
|
2
2
|
|
|
3
|
-
module.exports = ({
|
|
3
|
+
module.exports = ({ services }, App, systemContext) => {
|
|
4
4
|
const Client = SystemLynxClient(systemContext);
|
|
5
5
|
|
|
6
6
|
return Promise.all(
|
|
7
|
-
|
|
7
|
+
services.map((serviceData) => {
|
|
8
8
|
const { url, limit, wait, name, onLoad } = serviceData;
|
|
9
9
|
return new Promise((resolve) => {
|
|
10
10
|
Client.loadService(url, { limit, wait })
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
|
-
const
|
|
2
|
+
const SystemLynxApp = require("../App");
|
|
3
3
|
const HttpClient = require("../../HttpClient/HttpClient")();
|
|
4
|
-
const
|
|
4
|
+
const SystemLynxService = require("../../Service/Service");
|
|
5
5
|
|
|
6
|
-
describe("
|
|
6
|
+
describe("SystemLynxApp()", () => {
|
|
7
7
|
it("should return a SystemLynx App", () => {
|
|
8
|
-
const App =
|
|
8
|
+
const App = SystemLynxApp();
|
|
9
9
|
|
|
10
10
|
expect(App)
|
|
11
11
|
.to.be.an("object")
|
|
@@ -13,6 +13,7 @@ describe("App Factory", () => {
|
|
|
13
13
|
"module",
|
|
14
14
|
"on",
|
|
15
15
|
"emit",
|
|
16
|
+
"use",
|
|
16
17
|
"startService",
|
|
17
18
|
"loadService",
|
|
18
19
|
"onLoad",
|
|
@@ -21,6 +22,7 @@ describe("App Factory", () => {
|
|
|
21
22
|
.that.respondsTo("module")
|
|
22
23
|
.that.respondsTo("on")
|
|
23
24
|
.that.respondsTo("emit")
|
|
25
|
+
.that.respondsTo("use")
|
|
24
26
|
.that.respondsTo("startService")
|
|
25
27
|
.that.respondsTo("loadService")
|
|
26
28
|
.that.respondsTo("onLoad")
|
|
@@ -29,7 +31,7 @@ describe("App Factory", () => {
|
|
|
29
31
|
});
|
|
30
32
|
describe("App: Loading Services", () => {
|
|
31
33
|
it("should be able to use App.loadService(str_url) to load as hosted Service", async () => {
|
|
32
|
-
const Service =
|
|
34
|
+
const Service = SystemLynxService();
|
|
33
35
|
const route = "test-service";
|
|
34
36
|
const port = "8503";
|
|
35
37
|
|
|
@@ -41,13 +43,13 @@ describe("App: Loading Services", () => {
|
|
|
41
43
|
await Service.startService({ route, port });
|
|
42
44
|
|
|
43
45
|
await new Promise((resolve) => {
|
|
44
|
-
const App =
|
|
46
|
+
const App = SystemLynxApp();
|
|
45
47
|
App.loadService("test", `http://localhost:${port}/${route}`).on(
|
|
46
48
|
"ready",
|
|
47
49
|
(system) => {
|
|
48
|
-
expect(system.
|
|
50
|
+
expect(system.services[0]).to.be.an("object");
|
|
49
51
|
|
|
50
|
-
expect(system.
|
|
52
|
+
expect(system.services[0].client)
|
|
51
53
|
.to.be.an("object")
|
|
52
54
|
.that.has.all.keys("emit", "on", "resetConnection", "disconnect", "mod")
|
|
53
55
|
.that.respondsTo("emit")
|
|
@@ -61,7 +63,7 @@ describe("App: Loading Services", () => {
|
|
|
61
63
|
});
|
|
62
64
|
|
|
63
65
|
it("should be able to use App.loadService(...).onLoad(handler) to fire a callback when the Service connects", async () => {
|
|
64
|
-
const Service =
|
|
66
|
+
const Service = SystemLynxService();
|
|
65
67
|
const route = "test-service";
|
|
66
68
|
const port = "8422";
|
|
67
69
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -74,7 +76,7 @@ describe("App: Loading Services", () => {
|
|
|
74
76
|
await Service.startService({ route, port });
|
|
75
77
|
|
|
76
78
|
await new Promise((resolve) => {
|
|
77
|
-
const App =
|
|
79
|
+
const App = SystemLynxApp();
|
|
78
80
|
App.loadService("test", url).onLoad((test) => {
|
|
79
81
|
expect(test)
|
|
80
82
|
.to.be.an("object")
|
|
@@ -89,7 +91,7 @@ describe("App: Loading Services", () => {
|
|
|
89
91
|
});
|
|
90
92
|
|
|
91
93
|
it('should use App.on("service_loaded[:name]", callback) to fire when a Service has loaded', async () => {
|
|
92
|
-
const Service =
|
|
94
|
+
const Service = SystemLynxService();
|
|
93
95
|
const route = "test-service";
|
|
94
96
|
const port = "8423";
|
|
95
97
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -101,7 +103,7 @@ describe("App: Loading Services", () => {
|
|
|
101
103
|
await Service.startService({ route, port });
|
|
102
104
|
|
|
103
105
|
await new Promise((resolve) => {
|
|
104
|
-
const App =
|
|
106
|
+
const App = SystemLynxApp();
|
|
105
107
|
App.loadService("test", url)
|
|
106
108
|
.on("service_loaded", (test) => {
|
|
107
109
|
expect(test)
|
|
@@ -124,7 +126,7 @@ describe("App: Loading Services", () => {
|
|
|
124
126
|
});
|
|
125
127
|
|
|
126
128
|
it("should be accessible to SystemObjects via the module.useService method", async () => {
|
|
127
|
-
const Service =
|
|
129
|
+
const Service = SystemLynxService();
|
|
128
130
|
const route = "test-service";
|
|
129
131
|
const port = "8442";
|
|
130
132
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -137,7 +139,7 @@ describe("App: Loading Services", () => {
|
|
|
137
139
|
await Service.startService({ route, port });
|
|
138
140
|
|
|
139
141
|
await new Promise((resolve) => {
|
|
140
|
-
const App =
|
|
142
|
+
const App = SystemLynxApp();
|
|
141
143
|
App.loadService("test", url)
|
|
142
144
|
.module("module_name", function () {
|
|
143
145
|
const test = this.useService("test");
|
|
@@ -156,7 +158,7 @@ describe("App: Loading Services", () => {
|
|
|
156
158
|
|
|
157
159
|
describe("App SystemObjects: Initializing Modules, Modules and configurations", () => {
|
|
158
160
|
it("should be able to use App.module to initialize a module", async () => {
|
|
159
|
-
const App =
|
|
161
|
+
const App = SystemLynxApp();
|
|
160
162
|
return new Promise((resolve) =>
|
|
161
163
|
App.module("test", function () {
|
|
162
164
|
expect(this)
|
|
@@ -181,7 +183,7 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
181
183
|
);
|
|
182
184
|
});
|
|
183
185
|
it("should be able to use App.startService to start as Service", async () => {
|
|
184
|
-
const App =
|
|
186
|
+
const App = SystemLynxApp();
|
|
185
187
|
const route = "test-service";
|
|
186
188
|
const port = "8493";
|
|
187
189
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -207,7 +209,7 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
207
209
|
expect(connData.serviceUrl).to.equal(url);
|
|
208
210
|
});
|
|
209
211
|
it("should be able to use App.module to add a hosted Module to the Service", async () => {
|
|
210
|
-
const App =
|
|
212
|
+
const App = SystemLynxApp();
|
|
211
213
|
const route = "test-service";
|
|
212
214
|
const port = "8494";
|
|
213
215
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -252,8 +254,10 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
252
254
|
});
|
|
253
255
|
|
|
254
256
|
it('should be able to use App.on("ready", callback) fire a callback when App initialization is complete', async () => {
|
|
255
|
-
const App =
|
|
256
|
-
|
|
257
|
+
const App = SystemLynxApp();
|
|
258
|
+
const route = "system-test";
|
|
259
|
+
const port = "4242";
|
|
260
|
+
App.startService({ route, port });
|
|
257
261
|
App.module("mod", function () {
|
|
258
262
|
this.test = () => {};
|
|
259
263
|
this.test2 = () => {};
|
|
@@ -267,9 +271,10 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
267
271
|
expect(system)
|
|
268
272
|
.to.be.an("object")
|
|
269
273
|
.that.has.all.keys(
|
|
270
|
-
"
|
|
274
|
+
"services",
|
|
271
275
|
"Service",
|
|
272
|
-
"
|
|
276
|
+
"modules",
|
|
277
|
+
"connectionData",
|
|
273
278
|
"configurations",
|
|
274
279
|
"routing"
|
|
275
280
|
);
|
|
@@ -279,7 +284,7 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
279
284
|
});
|
|
280
285
|
|
|
281
286
|
it("should be able to use App.config(constructor) to construct a configuration module", async () => {
|
|
282
|
-
const App =
|
|
287
|
+
const App = SystemLynxApp();
|
|
283
288
|
|
|
284
289
|
App.module("mod", function () {
|
|
285
290
|
this.test = () => {};
|
|
@@ -309,10 +314,41 @@ describe("App SystemObjects: Initializing Modules, Modules and configurations",
|
|
|
309
314
|
);
|
|
310
315
|
});
|
|
311
316
|
});
|
|
317
|
+
describe("Use App.use(SystemLynxPlugin), to initializing Modules, and load Services", () => {
|
|
318
|
+
it("should allow for adding new modules and services before app initialization", async () => {
|
|
319
|
+
const Service = SystemLynxService();
|
|
320
|
+
const route = "test-service";
|
|
321
|
+
const port = "8520";
|
|
322
|
+
const pluginUrl = `http://localhost:${port}/${route}`;
|
|
323
|
+
Service.module("mod", function () {
|
|
324
|
+
this.test = () => {};
|
|
325
|
+
this.test2 = () => {};
|
|
326
|
+
});
|
|
327
|
+
await Service.startService({ route, port });
|
|
312
328
|
|
|
329
|
+
const plugin = (App, system) => {
|
|
330
|
+
App.loadService("PluginService", pluginUrl);
|
|
331
|
+
App.module("plugin", { testMethod: (data) => data });
|
|
332
|
+
};
|
|
333
|
+
await new Promise((resolve) => {
|
|
334
|
+
const App = SystemLynxApp();
|
|
335
|
+
App.module("testModule", { testFunction: () => data })
|
|
336
|
+
.use(plugin)
|
|
337
|
+
.on("ready", (system) => {
|
|
338
|
+
expect(system.services).to.have.lengthOf(1);
|
|
339
|
+
expect(system.services[0]).to.be.an("object");
|
|
340
|
+
expect(system.services[0]).to.have.property("name", "PluginService");
|
|
341
|
+
expect(system.services[0]).to.have.property("url", pluginUrl);
|
|
342
|
+
expect(system.modules).to.have.lengthOf(2);
|
|
343
|
+
expect(system.modules[1]).to.have.property("name", "plugin");
|
|
344
|
+
resolve();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
});
|
|
313
349
|
describe("SystemContext", () => {
|
|
314
350
|
it("should be able to use this.useModule and this.useService within modules and Module", () => {
|
|
315
|
-
const App =
|
|
351
|
+
const App = SystemLynxApp();
|
|
316
352
|
App.module("mod1", function () {
|
|
317
353
|
expect(this)
|
|
318
354
|
.to.be.an("object")
|
|
@@ -368,7 +404,7 @@ describe("SystemContext", () => {
|
|
|
368
404
|
return new Promise((resolve) => App.on("ready", () => resolve()));
|
|
369
405
|
});
|
|
370
406
|
it("[SystemLynx][App][Client][on] should have access to systemContext during event callbacks.", async () => {
|
|
371
|
-
const AppBackend =
|
|
407
|
+
const AppBackend = SystemLynxApp();
|
|
372
408
|
const eventName = "testing-this";
|
|
373
409
|
const _route = "test-service";
|
|
374
410
|
const _port = "8900";
|
|
@@ -388,7 +424,7 @@ describe("SystemContext", () => {
|
|
|
388
424
|
});
|
|
389
425
|
await AppBackend.startService({ route: _route, port: _port });
|
|
390
426
|
|
|
391
|
-
const AppClient =
|
|
427
|
+
const AppClient = SystemLynxApp();
|
|
392
428
|
const route = "test-service";
|
|
393
429
|
const port = "8901";
|
|
394
430
|
|
|
@@ -12,19 +12,35 @@ module.exports = function SystemLynxClient(systemContext) {
|
|
|
12
12
|
return Client.loadedServices[url];
|
|
13
13
|
|
|
14
14
|
const connData = await loadConnectionData(url, options);
|
|
15
|
-
const Service =
|
|
15
|
+
const Service = Client.createService(connData);
|
|
16
16
|
Client.loadedServices[url] = Service;
|
|
17
|
-
|
|
17
|
+
await new Promise((resolve) => Service.on("connect", resolve));
|
|
18
|
+
return Service;
|
|
19
|
+
};
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
Client.createService = (connData) => {
|
|
22
|
+
const events = {};
|
|
23
|
+
if (Client.loadedServices[connData.serviceUrl])
|
|
24
|
+
return Client.loadedServices[connData.serviceUrl];
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
const Service = SocketDispatcher(connData.namespace, events, systemContext);
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
Client.loadedServices[connData.serviceUrl] = Service;
|
|
29
|
+
|
|
30
|
+
Service.resetConnection = async (cb) => {
|
|
31
|
+
const { modules, host, port, namespace } = await loadConnectionData(
|
|
32
|
+
connData.serviceUrl
|
|
26
33
|
);
|
|
34
|
+
SocketDispatcher.apply(Service, [namespace, events, systemContext]);
|
|
27
35
|
|
|
36
|
+
modules.forEach(({ namespace, route, name }) => {
|
|
37
|
+
if (Service[name]) {
|
|
38
|
+
Service[name].__setConnection(host, port, route, namespace);
|
|
39
|
+
Service[name].emit("reconnect");
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Service.emit("reconnect");
|
|
28
44
|
if (typeof cb === "function") cb();
|
|
29
45
|
};
|
|
30
46
|
|
|
@@ -40,7 +56,6 @@ module.exports = function SystemLynxClient(systemContext) {
|
|
|
40
56
|
|
|
41
57
|
Service.on("disconnect", Service.resetConnection);
|
|
42
58
|
|
|
43
|
-
await new Promise((resolve) => Service.on("connect", resolve));
|
|
44
59
|
return Service;
|
|
45
60
|
};
|
|
46
61
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
const ServiceRequestHandler = require("./ServiceRequestHandler");
|
|
3
3
|
const SocketDispatcher = require("./SocketDispatcher");
|
|
4
4
|
module.exports = function SystemLynxClientModule(
|
|
5
|
-
{ methods, namespace, route },
|
|
5
|
+
{ methods, namespace, route, connectionData, name },
|
|
6
6
|
{ port, host },
|
|
7
|
-
|
|
7
|
+
reconnectService,
|
|
8
8
|
systemContext
|
|
9
9
|
) {
|
|
10
10
|
const events = {};
|
|
@@ -14,14 +14,23 @@ module.exports = function SystemLynxClientModule(
|
|
|
14
14
|
ClientModule.__connectionData = () => ({ route, host, port });
|
|
15
15
|
SocketDispatcher.apply(ClientModule, [namespace, events, systemContext]);
|
|
16
16
|
};
|
|
17
|
-
|
|
18
17
|
ClientModule.__setConnection(host, port, route, namespace);
|
|
19
18
|
|
|
19
|
+
const reconnectModule = async (cb) => {
|
|
20
|
+
const url = connectionData.serviceUrl + `?modules=${name}`;
|
|
21
|
+
const { modules, port, host } = await loadConnectionData(url);
|
|
22
|
+
const { namespace, route } = modules[0];
|
|
23
|
+
ClientModule.__setConnection(host, port, route, namespace);
|
|
24
|
+
|
|
25
|
+
if (typeof cb === "function") cb();
|
|
26
|
+
};
|
|
27
|
+
|
|
20
28
|
methods.forEach(({ method, fn }) => {
|
|
21
29
|
ClientModule[fn] = ServiceRequestHandler.apply(ClientModule, [
|
|
22
30
|
method,
|
|
23
31
|
fn,
|
|
24
|
-
|
|
32
|
+
reconnectService,
|
|
33
|
+
connectionData && reconnectModule,
|
|
25
34
|
]);
|
|
26
35
|
});
|
|
27
36
|
|
|
@@ -8,7 +8,12 @@ const makeQuery = (data) =>
|
|
|
8
8
|
(query, name) => (query += `${name}=${data[name]}&`),
|
|
9
9
|
"?"
|
|
10
10
|
);
|
|
11
|
-
module.exports = function ServiceRequestHandler(
|
|
11
|
+
module.exports = function ServiceRequestHandler(
|
|
12
|
+
method,
|
|
13
|
+
fn,
|
|
14
|
+
reconnectService,
|
|
15
|
+
reconnectModule
|
|
16
|
+
) {
|
|
12
17
|
const ClientModule = this;
|
|
13
18
|
|
|
14
19
|
return function sendRequest() {
|
|
@@ -48,7 +53,8 @@ module.exports = function ServiceRequestHandler(method, fn, resetConnection) {
|
|
|
48
53
|
} else if (errCount <= 3) {
|
|
49
54
|
console.log(err);
|
|
50
55
|
errCount++;
|
|
51
|
-
|
|
56
|
+
if (reconnectModule) reconnectModule(() => tryRequest(cb, errCount));
|
|
57
|
+
else reconnectService(() => tryRequest(cb, errCount));
|
|
52
58
|
} else throw Error(`[SystemLynx][Service][Error]: Invalid route:${err}`);
|
|
53
59
|
};
|
|
54
60
|
|
|
@@ -11,7 +11,9 @@ module.exports = function loadConnectionData(url, { limit = 10, wait = 150 } = {
|
|
|
11
11
|
if (errors.length < limit)
|
|
12
12
|
setTimeout(() => getData(resolve), errors.length * wait);
|
|
13
13
|
else
|
|
14
|
-
|
|
14
|
+
console.error(
|
|
15
|
+
`[SystemLynx][Client][Error]: Failed to load Service @${url} after ${errors.length} attempts.`
|
|
16
|
+
);
|
|
15
17
|
} else resolve(results);
|
|
16
18
|
});
|
|
17
19
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const Service =
|
|
2
|
+
const SystemLynxClient = require("../Client");
|
|
3
|
+
const SystemLynxService = require("../../Service/Service");
|
|
4
|
+
const Service = SystemLynxService();
|
|
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("SystemLynxClient()", () => {
|
|
10
10
|
it("should return a SystemLynx Client", () => {
|
|
11
|
-
const Client =
|
|
11
|
+
const Client = SystemLynxClient();
|
|
12
12
|
expect(Client)
|
|
13
13
|
.to.be.an("object")
|
|
14
14
|
.that.has.property("loadService")
|
|
@@ -36,7 +36,7 @@ describe("Client", () => {
|
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
await Service.startService({ route, port });
|
|
39
|
-
const Client =
|
|
39
|
+
const Client = SystemLynxClient();
|
|
40
40
|
const buAPI = await Client.loadService(url);
|
|
41
41
|
|
|
42
42
|
expect(buAPI)
|
|
@@ -74,7 +74,7 @@ describe("Client", () => {
|
|
|
74
74
|
|
|
75
75
|
describe("Service", () => {
|
|
76
76
|
it("should be able to call methods from the frontend client to the backend Module", async () => {
|
|
77
|
-
const Client =
|
|
77
|
+
const Client = SystemLynxClient();
|
|
78
78
|
const buAPI = await Client.loadService(url);
|
|
79
79
|
|
|
80
80
|
const results = await buAPI.orders.action1({ code: 3 });
|
|
@@ -89,7 +89,7 @@ describe("Service", () => {
|
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
91
|
it("should be able to send multiple arguments to the backend Module", async () => {
|
|
92
|
-
const Client =
|
|
92
|
+
const Client = SystemLynxClient();
|
|
93
93
|
const buAPI = await Client.loadService(url);
|
|
94
94
|
const arg1 = 4,
|
|
95
95
|
arg2 = 5,
|
|
@@ -107,7 +107,7 @@ describe("Service", () => {
|
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
it("should be able to send no arguments and use a promise", async () => {
|
|
110
|
-
const Client =
|
|
110
|
+
const Client = SystemLynxClient();
|
|
111
111
|
const buAPI = await Client.loadService(url);
|
|
112
112
|
const results = await buAPI.orders.noArgTest();
|
|
113
113
|
|
|
@@ -122,13 +122,13 @@ describe("Service", () => {
|
|
|
122
122
|
const route = "test-service";
|
|
123
123
|
const port = "8980";
|
|
124
124
|
const url = `http://localhost:${port}/${route}`;
|
|
125
|
-
const Service =
|
|
125
|
+
const Service = SystemLynxService();
|
|
126
126
|
const eventTester = Service.module("eventTester", function () {
|
|
127
127
|
this.sendEvent = () => this.emit(eventName, { testPassed: true });
|
|
128
128
|
});
|
|
129
129
|
await Service.startService({ route, port });
|
|
130
130
|
|
|
131
|
-
const Client =
|
|
131
|
+
const Client = SystemLynxClient();
|
|
132
132
|
|
|
133
133
|
const buAPI = await Client.loadService(url);
|
|
134
134
|
setTimeout(() => eventTester.emit(eventName, { testPassed: true }), 500);
|
|
@@ -148,8 +148,8 @@ describe("Service", () => {
|
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
it("should be able to send REST http requests", async () => {
|
|
151
|
-
const Client =
|
|
152
|
-
const Service =
|
|
151
|
+
const Client = SystemLynxClient();
|
|
152
|
+
const Service = SystemLynxService();
|
|
153
153
|
const route = "rest-tester";
|
|
154
154
|
const port = "8492";
|
|
155
155
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -183,7 +183,7 @@ describe("Service", () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it("should be able to use 'useReturnValue' configuration option to enable synchronous return values from Module methods", async () => {
|
|
186
|
-
const service =
|
|
186
|
+
const service = SystemLynxService();
|
|
187
187
|
const route = "sync/test";
|
|
188
188
|
const port = 4920;
|
|
189
189
|
const host = "localhost";
|
|
@@ -199,7 +199,7 @@ describe("Service", () => {
|
|
|
199
199
|
port,
|
|
200
200
|
host,
|
|
201
201
|
});
|
|
202
|
-
const Client =
|
|
202
|
+
const Client = SystemLynxClient();
|
|
203
203
|
const { AsyncMath } = await Client.loadService(url);
|
|
204
204
|
const results = await AsyncMath.max(10, 2);
|
|
205
205
|
expect(results).to.equal(10);
|
|
@@ -11,12 +11,16 @@ module.exports = function SystemLynxDispatcher(events = {}, systemContext) {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
Dispatcher.on = (eventName, callback) => {
|
|
14
|
-
if (typeof callback !== "function")
|
|
15
|
-
|
|
16
|
-
"[SystemLynx][EventHandler][Error]: EventHandler.on(eventName, callback) received invalid parameters"
|
|
17
|
-
);
|
|
14
|
+
if (typeof callback !== "function") return Dispatcher;
|
|
15
|
+
|
|
18
16
|
if (!events[eventName]) events[eventName] = [];
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
if (callback.name) {
|
|
19
|
+
//if the function has a name and it already present don't add it
|
|
20
|
+
const i = events[eventName].findIndex((fn) => fn.name === callback.name);
|
|
21
|
+
if (i === -1) events[eventName].push(callback);
|
|
22
|
+
else events[eventName][i] = callback;
|
|
23
|
+
} else events[eventName].push(callback);
|
|
20
24
|
return Dispatcher;
|
|
21
25
|
};
|
|
22
26
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const fs = require("fs");
|
|
3
|
-
const
|
|
3
|
+
const HttpSystemLynxClient = require("./HttpClient");
|
|
4
4
|
const port = 4789;
|
|
5
5
|
const testServerSetup = require("./test.server");
|
|
6
6
|
//test server setup
|
|
7
7
|
|
|
8
|
-
beforeAll(() => new Promise(resolve => testServerSetup(port, resolve)));
|
|
9
|
-
describe("
|
|
10
|
-
const HttpClient =
|
|
8
|
+
beforeAll(() => new Promise((resolve) => testServerSetup(port, resolve)));
|
|
9
|
+
describe("HttpSystemLynxClient Test", () => {
|
|
10
|
+
const HttpClient = HttpSystemLynxClient();
|
|
11
11
|
const url = `http://localhost:${port}/test`;
|
|
12
12
|
const singleFileUrl = `http://localhost:${port}/sf/test`;
|
|
13
13
|
const multiFileUrl = `http://localhost:${port}/mf/test`;
|
|
@@ -26,7 +26,7 @@ describe("HttpClientFactory Test", () => {
|
|
|
26
26
|
{
|
|
27
27
|
method: "GET",
|
|
28
28
|
url: "http://localhost:4789/test",
|
|
29
|
-
body: { getWithCallback: true }
|
|
29
|
+
body: { getWithCallback: true },
|
|
30
30
|
},
|
|
31
31
|
(err, results) => {
|
|
32
32
|
if (err) reject(err);
|
|
@@ -35,88 +35,76 @@ describe("HttpClientFactory Test", () => {
|
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
expect(results)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
method: "GET"
|
|
44
|
-
});
|
|
38
|
+
expect(results).to.be.an("Object").that.deep.equal({
|
|
39
|
+
getWithCallback: true,
|
|
40
|
+
testPassed: true,
|
|
41
|
+
method: "GET",
|
|
42
|
+
});
|
|
45
43
|
});
|
|
46
44
|
|
|
47
45
|
it("should be able to make http requests using a promise", async () => {
|
|
48
46
|
const results = await HttpClient.request({
|
|
49
47
|
method: "GET",
|
|
50
48
|
url,
|
|
51
|
-
body: { getWithPromise: true }
|
|
49
|
+
body: { getWithPromise: true },
|
|
52
50
|
});
|
|
53
51
|
|
|
54
|
-
expect(results)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
method: "GET"
|
|
60
|
-
});
|
|
52
|
+
expect(results).to.be.an("Object").that.deep.equal({
|
|
53
|
+
getWithPromise: true,
|
|
54
|
+
testPassed: true,
|
|
55
|
+
method: "GET",
|
|
56
|
+
});
|
|
61
57
|
});
|
|
62
58
|
|
|
63
59
|
it("should be able to make PUT requests", async () => {
|
|
64
60
|
const results = await HttpClient.request({
|
|
65
61
|
method: "GET",
|
|
66
62
|
url,
|
|
67
|
-
body: { getWithPromise: true }
|
|
63
|
+
body: { getWithPromise: true },
|
|
68
64
|
});
|
|
69
65
|
|
|
70
|
-
expect(results)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
method: "GET"
|
|
76
|
-
});
|
|
66
|
+
expect(results).to.be.an("Object").that.deep.equal({
|
|
67
|
+
getWithPromise: true,
|
|
68
|
+
testPassed: true,
|
|
69
|
+
method: "GET",
|
|
70
|
+
});
|
|
77
71
|
});
|
|
78
72
|
|
|
79
73
|
it("should be able to make POST requests", async () => {
|
|
80
74
|
const results = await HttpClient.request({
|
|
81
75
|
method: "POST",
|
|
82
76
|
url,
|
|
83
|
-
body: { test: true }
|
|
77
|
+
body: { test: true },
|
|
84
78
|
});
|
|
85
79
|
|
|
86
|
-
expect(results)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
method: "POST"
|
|
92
|
-
});
|
|
80
|
+
expect(results).to.be.an("Object").that.deep.equal({
|
|
81
|
+
test: true,
|
|
82
|
+
testPassed: true,
|
|
83
|
+
method: "POST",
|
|
84
|
+
});
|
|
93
85
|
});
|
|
94
86
|
it("should be able to make DELETE requests", async () => {
|
|
95
87
|
const results = await HttpClient.request({
|
|
96
88
|
method: "DELETE",
|
|
97
89
|
url,
|
|
98
|
-
body: { test: true }
|
|
90
|
+
body: { test: true },
|
|
99
91
|
});
|
|
100
92
|
|
|
101
|
-
expect(results)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
method: "DELETE"
|
|
107
|
-
});
|
|
93
|
+
expect(results).to.be.an("Object").that.deep.equal({
|
|
94
|
+
test: true,
|
|
95
|
+
testPassed: true,
|
|
96
|
+
method: "DELETE",
|
|
97
|
+
});
|
|
108
98
|
});
|
|
109
99
|
|
|
110
100
|
it("should be able to upload a file", async () => {
|
|
111
101
|
const file = fs.createReadStream(__dirname + "/test.file.json");
|
|
112
102
|
const results = await HttpClient.upload({
|
|
113
103
|
url: singleFileUrl,
|
|
114
|
-
formData: { file }
|
|
104
|
+
formData: { file },
|
|
115
105
|
});
|
|
116
106
|
|
|
117
|
-
expect(results)
|
|
118
|
-
.to.be.an("Object")
|
|
119
|
-
.that.has.property("testPassed", true);
|
|
107
|
+
expect(results).to.be.an("Object").that.has.property("testPassed", true);
|
|
120
108
|
expect(results)
|
|
121
109
|
.to.have.property("file")
|
|
122
110
|
.that.is.an("Object")
|
|
@@ -126,18 +114,14 @@ describe("HttpClientFactory Test", () => {
|
|
|
126
114
|
it("should be able to upload multiple files", async () => {
|
|
127
115
|
const files = [
|
|
128
116
|
fs.createReadStream(__dirname + "/test.file.json"),
|
|
129
|
-
fs.createReadStream(__dirname + "/test.file.json")
|
|
117
|
+
fs.createReadStream(__dirname + "/test.file.json"),
|
|
130
118
|
];
|
|
131
119
|
const multiUploadResponse = await HttpClient.upload({
|
|
132
120
|
url: multiFileUrl,
|
|
133
|
-
formData: { files }
|
|
121
|
+
formData: { files },
|
|
134
122
|
});
|
|
135
|
-
expect(multiUploadResponse)
|
|
136
|
-
|
|
137
|
-
.that.has.property("testPassed", true);
|
|
138
|
-
expect(multiUploadResponse)
|
|
139
|
-
.to.have.property("files")
|
|
140
|
-
.that.is.an("Array");
|
|
123
|
+
expect(multiUploadResponse).to.be.an("Object").that.has.property("testPassed", true);
|
|
124
|
+
expect(multiUploadResponse).to.have.property("files").that.is.an("Array");
|
|
141
125
|
expect(multiUploadResponse).to.have.property("fileUploadTest", true);
|
|
142
126
|
});
|
|
143
127
|
});
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const LoadBalancer = require("../LoadBalancer")();
|
|
3
|
-
const
|
|
3
|
+
const SystemLynxService = require("../../Service/Service");
|
|
4
4
|
const HttpClient = require("../../HttpClient/HttpClient")();
|
|
5
5
|
const lbPort = 5030;
|
|
6
6
|
const route = "loadbalancer";
|
|
7
7
|
|
|
8
|
-
describe("
|
|
8
|
+
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("startService", "
|
|
12
|
+
.that.has.all.keys("startService", "server", "WebSocket", "module", "clones")
|
|
13
13
|
.that.respondsTo("startService")
|
|
14
|
-
.that.respondsTo("Server")
|
|
15
|
-
.that.respondsTo("WebSocket")
|
|
16
14
|
.that.respondsTo("module");
|
|
17
15
|
expect(LoadBalancer.clones)
|
|
18
16
|
.to.be.an("object")
|
|
@@ -69,9 +67,18 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
69
67
|
it("should be a Service object with additional methods for LoadBalancing", () => {
|
|
70
68
|
expect(LoadBalancer.clones)
|
|
71
69
|
.to.be.an("Object")
|
|
72
|
-
.that.has.all.keys(
|
|
70
|
+
.that.has.all.keys(
|
|
71
|
+
"on",
|
|
72
|
+
"emit",
|
|
73
|
+
"$emit",
|
|
74
|
+
"register",
|
|
75
|
+
"dispatch",
|
|
76
|
+
"assignDispatch",
|
|
77
|
+
"clones"
|
|
78
|
+
)
|
|
73
79
|
.that.respondsTo("on")
|
|
74
80
|
.that.respondsTo("emit")
|
|
81
|
+
.that.respondsTo("$emit")
|
|
75
82
|
.that.respondsTo("register")
|
|
76
83
|
.that.respondsTo("dispatch")
|
|
77
84
|
.that.respondsTo("assignDispatch")
|
|
@@ -80,7 +87,7 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
80
87
|
});
|
|
81
88
|
|
|
82
89
|
it("should be able to use clones.register(connData, callback) method to host connection", async () => {
|
|
83
|
-
const Service =
|
|
90
|
+
const Service = SystemLynxService();
|
|
84
91
|
const { route, port, host } = test_service1;
|
|
85
92
|
await Service.startService({ route, port, host });
|
|
86
93
|
LoadBalancer.clones.register({ route, port, host }, () => {});
|
|
@@ -106,8 +113,8 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
106
113
|
|
|
107
114
|
it("should be able to manager the routing to multiple clones of the same Service", async () => {
|
|
108
115
|
const { route, port1, port2, host } = test_service2;
|
|
109
|
-
const Clone1 =
|
|
110
|
-
const Clone2 =
|
|
116
|
+
const Clone1 = SystemLynxService();
|
|
117
|
+
const Clone2 = SystemLynxService();
|
|
111
118
|
await Clone1.startService({ route, port: port1, host });
|
|
112
119
|
await Clone2.startService({ route, port: port2, host });
|
|
113
120
|
LoadBalancer.clones.register({ route, port: port1, host }, () => {});
|
|
@@ -121,7 +128,7 @@ describe("LoadBalancer.clones (Module)", () => {
|
|
|
121
128
|
expect(connData2.serviceUrl).to.equal(`http://localhost:${port2}/${route}`);
|
|
122
129
|
});
|
|
123
130
|
|
|
124
|
-
it("should be able to manage the route of multiple clones of multiple
|
|
131
|
+
it("should be able to manage the route of multiple clones of multiple services. aka Service Discovery", async () => {
|
|
125
132
|
const route1 = test_service1.route;
|
|
126
133
|
const route2 = test_service2.route;
|
|
127
134
|
const url1 = `http://localhost:${lbPort}/${route1}`;
|
|
@@ -24,7 +24,7 @@ module.exports = function SystemLynxServerManager() {
|
|
|
24
24
|
const moduleQueue = [];
|
|
25
25
|
const modules = [];
|
|
26
26
|
|
|
27
|
-
const ServerManager = {
|
|
27
|
+
const ServerManager = { server, WebSocket };
|
|
28
28
|
|
|
29
29
|
ServerManager.startService = (options) => {
|
|
30
30
|
let { route, host = "localhost", port, socketPort, staticRouting } = options;
|
|
@@ -39,6 +39,7 @@ module.exports = function SystemLynxServerManager() {
|
|
|
39
39
|
route =
|
|
40
40
|
route.charAt(route.length - 1) === "/" ? route.substr(route.length - 1) : route;
|
|
41
41
|
const serviceUrl = `http://${host}:${port}/${route}`;
|
|
42
|
+
|
|
42
43
|
serverConfigurations = {
|
|
43
44
|
...serverConfigurations,
|
|
44
45
|
...options,
|
|
@@ -46,18 +47,31 @@ module.exports = function SystemLynxServerManager() {
|
|
|
46
47
|
route,
|
|
47
48
|
socketPort,
|
|
48
49
|
};
|
|
50
|
+
const connectionData = {
|
|
51
|
+
modules,
|
|
52
|
+
host,
|
|
53
|
+
route: `/${route}`,
|
|
54
|
+
port,
|
|
55
|
+
serviceUrl,
|
|
56
|
+
namespace: `http://${host}:${socketPort}/${namespace}`,
|
|
57
|
+
SystemLynxService: true,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const selectModules = (moduleList) =>
|
|
61
|
+
moduleList.reduce(
|
|
62
|
+
(sum, moduleName) =>
|
|
63
|
+
sum.concat(modules.find(({ name }) => name === moduleName) || []),
|
|
64
|
+
[]
|
|
65
|
+
);
|
|
49
66
|
|
|
50
67
|
server.get(`/${route}`, (req, res) => {
|
|
51
68
|
//The route will return connection data for the service including an array of
|
|
52
69
|
//modules (objects) which contain instructions on how to make request to each object
|
|
70
|
+
const { query } = req;
|
|
71
|
+
|
|
53
72
|
res.json({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
host,
|
|
57
|
-
route: `/${route}`,
|
|
58
|
-
serviceUrl,
|
|
59
|
-
namespace: `http://${host}:${socketPort}/${namespace}`,
|
|
60
|
-
SystemLynxService: true,
|
|
73
|
+
...connectionData,
|
|
74
|
+
modules: query.modules ? selectModules(query.modules.split(",")) : modules,
|
|
61
75
|
});
|
|
62
76
|
});
|
|
63
77
|
|
|
@@ -68,7 +82,7 @@ module.exports = function SystemLynxServerManager() {
|
|
|
68
82
|
ServerManager.addModule(name, Module, reserved_methods)
|
|
69
83
|
);
|
|
70
84
|
moduleQueue.length = 0;
|
|
71
|
-
resolve(
|
|
85
|
+
resolve(connectionData);
|
|
72
86
|
})
|
|
73
87
|
);
|
|
74
88
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const isObject = (value) =>
|
|
2
2
|
typeof value === "object" ? (!value ? false : !Array.isArray(value)) : false;
|
|
3
3
|
const isEmpty = (obj) => Object.getOwnPropertyNames(obj).length === 0;
|
|
4
|
-
const isPromise = (p) => typeof p === "object" && typeof p.then === "function";
|
|
4
|
+
const isPromise = (p) => typeof p === "object" && typeof (p || {}).then === "function";
|
|
5
5
|
|
|
6
6
|
module.exports = function SystemLynxRouter(server, config) {
|
|
7
7
|
const addService = (Module, route, { fn, method }, module_name) => {
|
|
@@ -34,16 +34,16 @@ module.exports = function SystemLynxRouter(server, config) {
|
|
|
34
34
|
const { query, file, files, body, fn, Module, module_name, method } = req;
|
|
35
35
|
const { serviceUrl } = config();
|
|
36
36
|
const presets = { serviceUrl, module_name, fn };
|
|
37
|
+
const unhandledMessage = `[SystemLynx]: handled error While calling ${module_name}.${fn}(...)`;
|
|
37
38
|
|
|
38
39
|
const sendError = (error) => {
|
|
39
40
|
const status = (error || {}).status || 500;
|
|
40
|
-
const message = (error || {}).message ||
|
|
41
|
-
const unhandledMessage = status === 500 ? "Unhandled error" : "Error";
|
|
41
|
+
const message = (error || {}).message || unhandledMessage;
|
|
42
42
|
res.status(status).json({
|
|
43
43
|
...presets,
|
|
44
|
-
error,
|
|
44
|
+
...error,
|
|
45
45
|
status,
|
|
46
|
-
message
|
|
46
|
+
message,
|
|
47
47
|
SystemLynxServiceError: true,
|
|
48
48
|
});
|
|
49
49
|
};
|
|
@@ -6,14 +6,15 @@ module.exports = function SocketEmitter(namespace, WebSocket) {
|
|
|
6
6
|
(this || {}).on && (this || {}).emit ? this : SystemLynxDispatcher.apply(this);
|
|
7
7
|
|
|
8
8
|
const socket = WebSocket.of(`/${namespace}`);
|
|
9
|
-
|
|
9
|
+
//use $emit to emit events locally only
|
|
10
|
+
Emitter.$emit = Emitter.emit;
|
|
10
11
|
|
|
11
12
|
Emitter.emit = (name, data) => {
|
|
12
13
|
const id = shortid();
|
|
13
14
|
const type = "WebSocket";
|
|
14
15
|
socket.emit("dispatch", { id, name, data, type });
|
|
15
16
|
//emit the same event locally
|
|
16
|
-
emit(name, data);
|
|
17
|
+
Emitter.$emit(name, data);
|
|
17
18
|
};
|
|
18
19
|
return Emitter;
|
|
19
20
|
};
|
|
@@ -8,11 +8,9 @@ describe("SystemLynxServerManager function", () => {
|
|
|
8
8
|
|
|
9
9
|
expect(ServerManager)
|
|
10
10
|
.to.be.an("Object")
|
|
11
|
-
.that.has.all.keys(["startService", "addModule", "
|
|
11
|
+
.that.has.all.keys(["startService", "addModule", "server", "WebSocket"])
|
|
12
12
|
.that.respondsTo("startService")
|
|
13
|
-
.that.respondsTo("addModule")
|
|
14
|
-
.that.respondsTo("Server")
|
|
15
|
-
.that.respondsTo("WebSocket");
|
|
13
|
+
.that.respondsTo("addModule");
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
describe("ServerManager", () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
2
|
+
const SystemLynxServerManager = require("../ServerManager/ServerManager");
|
|
3
3
|
const SystemLynxDispatcher = require("../Dispatcher/Dispatcher");
|
|
4
4
|
|
|
5
|
-
module.exports = function
|
|
6
|
-
const ServerManager =
|
|
7
|
-
const { startService,
|
|
8
|
-
const Service = { startService,
|
|
5
|
+
module.exports = function SystemLynxService(systemContext = {}) {
|
|
6
|
+
const ServerManager = SystemLynxServerManager();
|
|
7
|
+
const { startService, server, WebSocket } = ServerManager;
|
|
8
|
+
const Service = { startService, server, WebSocket };
|
|
9
9
|
|
|
10
10
|
Service.module = function (name, constructor, reserved_methods = []) {
|
|
11
11
|
const exclude_methods = reserved_methods.concat(
|
|
@@ -29,7 +29,7 @@ module.exports = function ServiceFactory(systemContext = {}) {
|
|
|
29
29
|
undefined,
|
|
30
30
|
systemContext,
|
|
31
31
|
]);
|
|
32
|
-
constructor.apply(Module, [
|
|
32
|
+
constructor.apply(Module, [server, WebSocket]);
|
|
33
33
|
ServerManager.addModule(name, Module, exclude_methods);
|
|
34
34
|
return Module;
|
|
35
35
|
}
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
const { expect } = require("chai");
|
|
2
2
|
const request = require("request");
|
|
3
|
-
const
|
|
3
|
+
const SystemLynxService = require("./Service");
|
|
4
4
|
|
|
5
5
|
describe("SystemLynxService", () => {
|
|
6
6
|
it("should return a new instance of a Service", () => {
|
|
7
|
-
const Service =
|
|
7
|
+
const Service = SystemLynxService();
|
|
8
8
|
expect(Service)
|
|
9
9
|
.to.be.an("object")
|
|
10
|
-
.that.has.all.keys("startService", "module", "
|
|
10
|
+
.that.has.all.keys("startService", "module", "server", "WebSocket")
|
|
11
11
|
.that.respondsTo("startService")
|
|
12
|
-
.that.respondsTo("module")
|
|
13
|
-
.that.respondsTo("Server")
|
|
14
|
-
.that.respondsTo("WebSocket");
|
|
12
|
+
.that.respondsTo("module");
|
|
15
13
|
});
|
|
16
14
|
});
|
|
17
15
|
|
|
18
16
|
describe("Service factory", () => {
|
|
19
17
|
it("should be able to use Service.startService to initiate a ServerManager instance that hosts the Service Connection Data", async () => {
|
|
20
|
-
const Service =
|
|
18
|
+
const Service = SystemLynxService();
|
|
21
19
|
const route = "/testService";
|
|
22
20
|
const port = 5500;
|
|
23
21
|
const url = `http://localhost:${port}${route}`;
|
|
@@ -49,7 +47,7 @@ describe("Service factory", () => {
|
|
|
49
47
|
});
|
|
50
48
|
|
|
51
49
|
describe("Service.module(constructor)", () => {
|
|
52
|
-
const Service =
|
|
50
|
+
const Service = SystemLynxService();
|
|
53
51
|
const port = 6542;
|
|
54
52
|
const route = "test/service";
|
|
55
53
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -111,7 +109,7 @@ describe("Service.module(constructor)", () => {
|
|
|
111
109
|
});
|
|
112
110
|
|
|
113
111
|
describe("Service.module(object)", () => {
|
|
114
|
-
const Service =
|
|
112
|
+
const Service = SystemLynxService();
|
|
115
113
|
const port = 6543;
|
|
116
114
|
const route = "test/service2";
|
|
117
115
|
const url = `http://localhost:${port}/${route}`;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
module.exports = function SystemObject(system) {
|
|
3
3
|
const context = this || {};
|
|
4
4
|
context.useModule = (modName) =>
|
|
5
|
-
(system.
|
|
5
|
+
(system.modules.find((mod) => mod.name === modName) || {}).module || {};
|
|
6
6
|
context.useService = (serviceName) =>
|
|
7
|
-
(system.
|
|
7
|
+
(system.services.find((mod) => mod.name === serviceName) || {}).client || {};
|
|
8
8
|
context.useConfig = () => system.configurations.module || {};
|
|
9
9
|
return context;
|
|
10
10
|
};
|