orator 2.0.4 → 3.0.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.
@@ -0,0 +1,4 @@
1
+ bind-addr: 127.0.0.1:8080
2
+ auth: password
3
+ password: luxury
4
+ cert: false
@@ -0,0 +1,4 @@
1
+ {
2
+ "optOut": false,
3
+ "lastUpdateCheck": 1648097783781
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "optOut": false,
3
+ "lastUpdateCheck": 1677357438471
4
+ }
@@ -5,22 +5,42 @@
5
5
  "version": "0.2.0",
6
6
  "configurations": [
7
7
  {
8
+ "name": "Launch Debug Harness",
8
9
  "type": "node",
9
10
  "request": "launch",
11
+ "outputCapture": "std",
12
+ "skipFiles": [
13
+ "<node_internals>/**"
14
+ ],
15
+ "program": "${workspaceFolder}/debug/Harness.js",
16
+ "presentation": {
17
+ "hidden": false,
18
+ "group": "",
19
+ "order": 1
20
+ }
21
+ },
22
+ {
10
23
  "name": "Mocha Tests",
11
- "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
12
24
  "args": [
13
25
  "-u",
14
26
  "tdd",
15
- "--bail",
16
27
  "--timeout",
17
28
  "999999",
18
29
  "--colors",
19
- "${workspaceFolder}/test/Orator_basic_tests.js",
20
- "${workspaceFolder}/test/Orator_logging_tests.js",
21
- "${workspaceFolder}/test/Orator-proxy_tests.js"
30
+ "${workspaceFolder}/test"
31
+ ],
32
+ "internalConsoleOptions": "openOnSessionStart",
33
+ "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
34
+ "request": "launch",
35
+ "skipFiles": [
36
+ "<node_internals>/**"
22
37
  ],
23
- "internalConsoleOptions": "openOnSessionStart"
38
+ "type": "pwa-node",
39
+ "presentation": {
40
+ "hidden": false,
41
+ "group": "",
42
+ "order": 2
43
+ }
24
44
  }
25
45
  ]
26
46
  }
@@ -0,0 +1,69 @@
1
+ # Use the codercom/code-server image
2
+ FROM codercom/code-server:latest
3
+ MAINTAINER steven velozo
4
+
5
+ VOLUME /home/coder/.config
6
+ VOLUME /home/coder/.vscode
7
+
8
+ RUN echo "...installing debian dependencies..."
9
+ RUN sudo apt update
10
+ RUN sudo apt install vim curl tmux -y
11
+
12
+ RUN echo "Building development image..."
13
+
14
+ RUN echo "...installing vscode extensions..."
15
+
16
+ # Mocha unit testing in the sidebar
17
+ RUN code-server --install-extension hbenl.vscode-mocha-test-adapter
18
+ RUN code-server --install-extension hbenl.test-adapter-converter
19
+ RUN code-server --install-extension hbenl.vscode-test-explorer
20
+
21
+ # Magic indentation rainbow
22
+ RUN code-server --install-extension oderwat.indent-rainbow
23
+ RUN code-server --install-extension dbaeumer.vscode-eslint
24
+
25
+ # Contextual git
26
+ RUN code-server --install-extension eamodio.gitlens
27
+
28
+ # Other extensions (uncomment them to have them automagic, or run this from a terminal to install in the container):
29
+
30
+ # Microsoft's AI code completion
31
+ # RUN code-server --install-extension VisualStudioExptTeam.vscodeintellicode
32
+
33
+ # Live server -- make sure to open up the port on the docker image
34
+ # RUN code-server --install-extension ritwickdey.LiveServer
35
+
36
+ # Quick link to required modules' documentation
37
+ # RUN code-server --install-extension bengreenier.vscode-node-readme
38
+
39
+ # Switch up fonts
40
+ # RUN code-server --install-extension evan-buss.font-switcher
41
+
42
+ # Icons
43
+ # RUN code-server --install-extension vscode-icons-team.vscode-icons
44
+ # RUN code-server --install-extension PKief.material-icon-theme
45
+
46
+ # Hover over CSS colors to see them previewed
47
+ # RUN code-server --install-extension bierner.color-info
48
+
49
+ # An easy on the eyes color theme
50
+ # RUN code-server --install-extension daylerees.rainglow
51
+
52
+ RUN echo "...mapping library specific volumes..."
53
+
54
+ # Volume mapping for code
55
+ VOLUME /home/coder/orator
56
+
57
+ SHELL ["/bin/bash", "-c"]
58
+ USER coder
59
+
60
+ RUN echo "...installing node version manager..."
61
+ # Because there is a .bashrc chicken/egg problem, we will create one here to simulate logging in. This is not great.
62
+ RUN touch ~/.bashrc && chmod +x ~/.bashrc
63
+ RUN curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
64
+
65
+ RUN echo "...installing node version 14 as the default..."
66
+ RUN . ~/.nvm/nvm.sh && source ~/.bashrc && nvm install 14
67
+ RUN . ~/.nvm/nvm.sh && source ~/.bashrc && nvm alias default 14
68
+
69
+ WORKDIR /home/coder/orator
@@ -0,0 +1,42 @@
1
+ // Load the orator module with a few simple routes
2
+ const libOrator = require(__dirname+'/../source/Orator.js');
3
+ // Uncomment the following line to test the restify server plug-in
4
+ // > make sure to run "npm i orator-serviceserver-restify" from the parent directory first so the package is available
5
+ // > please don't --save it!
6
+ const libOratorServiceServerRestify = require('orator-serviceserver-restify');
7
+
8
+ const tmpServiceServer = new libOrator(
9
+ {
10
+ "Product": "HarnessService",
11
+ "ProductVersion": "1.2.3",
12
+
13
+ "APIServerPort": 8080
14
+ }
15
+ // Uncomment the next line to enable restify!
16
+ ,libOratorServiceServerRestify
17
+ );
18
+ // Initialize the service server
19
+ tmpServiceServer.initializeServiceServer();
20
+ // Start the service
21
+ tmpServiceServer.startService();
22
+
23
+ // Add a GET endpoint
24
+ tmpServiceServer.webServer.get
25
+ (
26
+ '/test/:hash',
27
+ (pRequest, pResponse, fNext) =>
28
+ {
29
+ // Send back whatever was sent as "name" in the URI
30
+ pResponse.send(pRequest.params);
31
+ tmpServiceServer.log.info(`Service has served the test echo route!`);
32
+ return fNext();
33
+ }
34
+ );
35
+
36
+ // If this is a web server, invoke is likely not implemented and will error.
37
+ let tmpURI = `/test/SomeHash`;
38
+ tmpServiceServer.invoke('GET', tmpURI, null,
39
+ (pError, pResponseData) =>
40
+ {
41
+ tmpServiceServer.log.info(`Response to [${tmpURI}] came back from IPC resulting in [${pResponseData}]!`)
42
+ });
package/package.json CHANGED
@@ -1,17 +1,15 @@
1
1
  {
2
2
  "name": "orator",
3
- "version": "2.0.4",
4
- "description": "Restful web API server. Using restify 6.",
3
+ "version": "3.0.0",
4
+ "description": "Unopinionated restful web API server container",
5
5
  "main": "source/Orator.js",
6
6
  "scripts": {
7
7
  "start": "node source/Orator.js",
8
- "coverage": "npm run coverage-normal && npm run coverage-cluster && npm run coverage-report",
9
- "coverage-normal": "./node_modules/istanbul/lib/cli.js cover --dir ./coverage/normal ./node_modules/mocha/bin/_mocha -- --exit -u tdd -R spec",
10
- "coverage-cluster": "./node_modules/istanbul/lib/cli.js cover --dir ./coverage/cluster ./node_modules/mocha/bin/_mocha -- --exit -u tdd -R spec ./test/Orator_cluster_test.js.deferred",
11
- "coverage-report": "./node_modules/istanbul/lib/cli.js report",
12
- "test": "npm run test-normal && npm run test-cluster",
13
- "test-normal": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec",
14
- "test-cluster": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec ./test/Orator_cluster_test.js.deferred"
8
+ "coverage": "./node_modules/.bin/nyc --reporter=lcov --reporter=text-lcov ./node_modules/mocha/bin/_mocha -- -u tdd -R spec",
9
+ "test": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec",
10
+ "build": "./node_modules/.bin/gulp build",
11
+ "docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/orator:local",
12
+ "docker-dev-run": "docker run -it -d --name retold-orator-dev -p 40000:8080 -p 48086:8086 -p 48088:8088 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/orator\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold/orator:local"
15
13
  },
16
14
  "repository": {
17
15
  "type": "git",
@@ -27,28 +25,43 @@
27
25
  "bugs": {
28
26
  "url": "https://github.com/stevenvelozo/orator/issues"
29
27
  },
28
+ "mocha": {
29
+ "diff": true,
30
+ "extension": [
31
+ "js"
32
+ ],
33
+ "package": "./package.json",
34
+ "reporter": "spec",
35
+ "slow": "75",
36
+ "timeout": "5000",
37
+ "ui": "tdd",
38
+ "watch-files": [
39
+ "source/**/*.js",
40
+ "test/**/*.js"
41
+ ],
42
+ "watch-ignore": [
43
+ "lib/vendor"
44
+ ]
45
+ },
30
46
  "homepage": "https://github.com/stevenvelozo/orator",
31
47
  "devDependencies": {
32
- "async": "2.6.1",
33
- "chai": "4.1.2",
34
- "codeclimate-test-reporter": "0.5.0",
35
- "coveralls": "3.0.2",
36
- "istanbul": "0.4.5",
37
- "mocha": "5.2.0",
38
- "supertest": "3.1.0"
39
- },
40
- "optionalDependencies": {
41
- "v8-profiler": "^5.7.0"
48
+ "browserify": "^17.0.0",
49
+ "chai": "4.3.7",
50
+ "gulp": "^4.0.2",
51
+ "gulp-babel": "^8.0.0",
52
+ "gulp-sourcemaps": "^3.0.0",
53
+ "gulp-terser": "^2.1.0",
54
+ "gulp-util": "^3.0.8",
55
+ "mocha": "10.2.0",
56
+ "nyc": "^15.1.0",
57
+ "vinyl-buffer": "^1.0.1",
58
+ "vinyl-source-stream": "^2.0.0"
42
59
  },
43
60
  "dependencies": {
61
+ "async": "^3.2.4",
44
62
  "cachetrax": "^1.0.0",
45
- "cluster": "^0.7.7",
46
- "fable": "~1.0.2",
47
- "fable-uuid": "~1.0.2",
48
- "http-forward": "^0.1.3",
49
- "request": "^2.69.0",
50
- "restify": "^6.4.0",
51
- "restify-await-promise": "^1.0.0",
52
- "restify-cors-middleware": "^1.1.1"
63
+ "fable": "~3.0.2",
64
+ "find-my-way": "^7.5.0",
65
+ "orator-serviceserver": "^1.0.1"
53
66
  }
54
67
  }
@@ -0,0 +1,10 @@
1
+ // Simple default configuration for application, when none is provided
2
+
3
+ module.exports = (
4
+ {
5
+ "Product": "Unnamed_Service",
6
+ "ProductVersion": "0.0.1",
7
+
8
+ "ServicePort": 8080
9
+ });
10
+
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Default Service Server Function
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ // Return the servers that are available without extensions loaded
10
+ getDefaultServiceServers = () =>
11
+ {
12
+ let tmpDefaultServiceServers = {};
13
+
14
+ tmpDefaultServiceServers.ipc = require('./Orator-ServiceServer-IPC.js');
15
+
16
+ tmpDefaultServiceServers.default = tmpDefaultServiceServers.ipc;
17
+
18
+ return tmpDefaultServiceServers;
19
+ }
20
+
21
+ module.exports = getDefaultServiceServers();
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ // This is taken directly from the find-my-way documentation for custom constraints and only mildly edited
4
+ const ipcResponseTypeStrategy = (
5
+ {
6
+ // strategy name for referencing in the route handler `constraints` options
7
+ name: 'ipc',
8
+ isAsync: true,
9
+
10
+ // storage factory for storing routes in the find-my-way route tree
11
+ storage:
12
+ ()=>
13
+ {
14
+ let handlers = {};
15
+
16
+ return (
17
+ {
18
+ get: (type) => { return handlers[type] || null },
19
+ set: (type, store) => { handlers[type] = store }
20
+ });
21
+ },
22
+
23
+ // function to get the value of the constraint from each incoming request
24
+ deriveConstraint: (pRequest, pContext, fDone) =>
25
+ {
26
+ // If we wanted to deny the IPC request based on a constraint, we would do:
27
+ // fDone(new Error(`The request was denied because ____ in the Request object wasn't right...`));
28
+ return fDone(null, 'IPC');
29
+ },
30
+
31
+ // optional flag marking if handlers without constraints can match requests that have a value for this constraint
32
+ mustMatchWhenDerived: true
33
+ });
34
+
35
+ module.exports = ipcResponseTypeStrategy;
@@ -0,0 +1,56 @@
1
+ class OratorServiceServerIPCSynthesizedResponse
2
+ {
3
+ constructor(pLog, pRequestGUID)
4
+ {
5
+ this.log = pLog;
6
+
7
+ this.requestGUID = pRequestGUID;
8
+
9
+ this.responseData = null;
10
+ this.responseStatus = -1;
11
+ }
12
+
13
+ send(pData)
14
+ {
15
+ if (typeof(pData) == 'string')
16
+ {
17
+ // This is a string! Append it to the responsedata.
18
+ if (this.responseData === null)
19
+ {
20
+ this.responseData = pData;
21
+ return true;
22
+ }
23
+ else if (typeof(this.responseData) == 'string')
24
+ {
25
+ this.responseData = this.responseData+pData;
26
+ return true;
27
+ }
28
+ else
29
+ {
30
+ this.log(`Request ${this.requestGUID} has tried to send() a string value after send()ing data type ${typeof(this.responseData)}.`, pData)
31
+ return false;
32
+ }
33
+ }
34
+ else if (typeof(pData) == 'object')
35
+ {
36
+ if (this.responseData === null)
37
+ {
38
+ this.responseData = JSON.stringify(pData);
39
+ return true;
40
+ }
41
+ else if (typeof(this.responseData) == 'string')
42
+ {
43
+ // TODO: Discuss best way to handle this / if to handle this
44
+ this.responseData += this.responseData+JSON.stringify(pData);
45
+ return true;
46
+ }
47
+ else
48
+ {
49
+ this.log(`Request ${this.requestGUID} has tried to send() an object value to be auto stringified after send()ing data type ${typeof(this.responseData)}.`, pData)
50
+ return false;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ module.exports = OratorServiceServerIPCSynthesizedResponse;
@@ -0,0 +1,214 @@
1
+ const libOratorServiceServerBase = require('orator-serviceserver');
2
+
3
+ // A synthesized response object, for simple IPC.
4
+ const libOratorServiceServerIPCSynthesizedResponse = require('./Orator-ServiceServer-IPC-SynthesizedResponse.js');
5
+ // A simple constrainer for the find-my-way router since we aren't using any kind of headers to pass version or host
6
+ const libOratorServiceServerIPCCustomConstrainer = require('./Orator-ServiceServer-IPC-RouterConstrainer.js');
7
+
8
+ // This library is the default router for our services
9
+ const libFindMyWay = require('find-my-way');
10
+ const libAsync = require('async');
11
+
12
+ class OratorServiceServerIPC extends libOratorServiceServerBase
13
+ {
14
+ constructor(pOrator)
15
+ {
16
+ super(pOrator);
17
+
18
+ this.routerOptions = (this.orator.settings.hasOwnProperty('router_options') && (typeof(this.orator.settings.router_options) == 'object')) ? this.orator.settings.router_options : {};
19
+ this.router = libFindMyWay(this.routerOptions);
20
+ this.router.addConstraintStrategy(libOratorServiceServerIPCCustomConstrainer);
21
+
22
+ this.URL = 'IPC';
23
+
24
+ this.preBehaviorFunctions = [];
25
+ this.behaviorMap = {};
26
+ this.postBehaviorFunctions = [];
27
+ }
28
+
29
+ executePreBehaviorFunctions(pRequest, pResponse, fNext)
30
+ {
31
+ libAsync.eachOfSeries(this.preBehaviorFunctions,
32
+ (fBehaviorFunction, pFunctionIndex, fCallback) =>
33
+ {
34
+ return fBehaviorFunction(pRequest, pResponse, fCallback);
35
+ },
36
+ (pError) =>
37
+ {
38
+ if (pError)
39
+ {
40
+ this.log.error(`IPC Provider preBehaviorFunction ${pFunctionIndex} failed with error: ${pError}`, pError);
41
+ }
42
+ return fNext(pError);
43
+ });
44
+ }
45
+
46
+ executePostBehaviorFunctions(pRequest, pResponse, fNext)
47
+ {
48
+ libAsync.eachOfSeries(this.postBehaviorFunctions,
49
+ (fBehaviorFunction, pFunctionIndex, fCallback) =>
50
+ {
51
+ return fBehaviorFunction(pRequest, pResponse, fCallback);
52
+ },
53
+ (pError) =>
54
+ {
55
+ if (pError)
56
+ {
57
+ this.log.error(`IPC Provider postBehaviorFunction ${pFunctionIndex} failed with error: ${pError}`, pError);
58
+ }
59
+ return fNext(pError);
60
+ });
61
+ }
62
+
63
+ /*
64
+ * Service Route Creation Functions
65
+ *
66
+ * These base functions provide basic validation for the routes, but don't actually
67
+ * do anything with them. The design intent here is to allow derived classes to call
68
+ * these functions to validate that they conform to expected standards.
69
+ *
70
+ * Something like:
71
+
72
+ get (pRoute, ...fRouteProcessingFunctions)
73
+ {
74
+ //...now we can do our actual get mapping function!....
75
+ }
76
+
77
+ * This pattern and calling super is totally optional, obviously.
78
+ *************************************************************************/
79
+ addRouteProcessor(pMethod, pRoute, pRouteFunctionArray)
80
+ {
81
+ // We have a constrainer on IPC so we can control channels eventually, if we like.
82
+ // For now it just makes sure it was added with an IPC service server.
83
+ this.router.on(pMethod, pRoute, { constraints: { "ipc": "IPC" } },
84
+ (pRequest, pResponse, pParameters) =>
85
+ {
86
+ libAsync.waterfall(
87
+ [
88
+ (fStageComplete)=>
89
+ {
90
+ // Added to make this mimic what we saw with route parsing in the old restify
91
+ pRequest.params = pParameters;
92
+ return fStageComplete();
93
+ },
94
+ (fStageComplete)=>
95
+ {
96
+ return this.executePreBehaviorFunctions(pRequest, pResponse, fStageComplete);
97
+ },
98
+ (fStageComplete)=>
99
+ {
100
+ libAsync.eachOfSeries(pRouteFunctionArray,
101
+ (fBehaviorFunction, pFunctionIndex, fCallback) =>
102
+ {
103
+ return fBehaviorFunction(pRequest, pResponse, fCallback);
104
+ },
105
+ (pBehaviorFunctionError) =>
106
+ {
107
+ if (pBehaviorFunctionError)
108
+ {
109
+ this.log.error(`IPC Provider behavior function ${pFunctionIndex} failed with error: ${pBehaviorFunctionError}`, pBehaviorFunctionError);
110
+ return fNext(pError);
111
+ }
112
+ });
113
+ },
114
+ (fStageComplete)=>
115
+ {
116
+ return this.executePostBehaviorFunctions(pRequest, pResponse, fStageComplete);
117
+ }
118
+ ],
119
+ (pRequestError)=>
120
+ {
121
+ if (pRequestError)
122
+ {
123
+ this.log.error(`IPC Provider behavior function ${pFunctionIndex} failed with error: ${pBehaviorFunctionError}`, pBehaviorFunctionError);
124
+ }
125
+ });
126
+ });
127
+
128
+ return true;
129
+ }
130
+
131
+ get(pRoute, ...fRouteProcessingFunctions)
132
+ {
133
+ if (!super.get(pRoute, ...fRouteProcessingFunctions))
134
+ {
135
+ this.log.error(`IPC provider failed to map GET route [${pRoute}]!`);
136
+ return false;
137
+ }
138
+
139
+ return this.addRouteProcessor('GET', pRoute, Array.from(fRouteProcessingFunctions));
140
+ }
141
+
142
+ put(pRoute, ...fRouteProcessingFunctions)
143
+ {
144
+ if (!super.get(pRoute, ...fRouteProcessingFunctions))
145
+ {
146
+ this.log.error(`IPC provider failed to map PUT route [${pRoute}]!`);
147
+ return false;
148
+ }
149
+
150
+ return true;
151
+ }
152
+
153
+ post(pRoute, ...fRouteProcessingFunctions)
154
+ {
155
+ if (!super.get(pRoute, ...fRouteProcessingFunctions))
156
+ {
157
+ this.log.error(`IPC provider failed to map POST route [${pRoute}]!`);
158
+ return false;
159
+ }
160
+
161
+ return true;
162
+ }
163
+
164
+ del(pRoute, ...fRouteProcessingFunctions)
165
+ {
166
+ if (!super.get(pRoute, ...fRouteProcessingFunctions))
167
+ {
168
+ this.log.error(`IPC provider failed to map DEL route [${pRoute}]!`);
169
+ return false;
170
+ }
171
+
172
+ return true;
173
+ }
174
+ /*************************************************************************
175
+ * End of Service Route Creation Functions
176
+ */
177
+
178
+ // Programmatically invoke a route
179
+ invoke(pMethod, pRoute, pData, fCallback)
180
+ {
181
+ // If the data is skipped and a callback is parameter 3, do the right thing
182
+ let tmpCallback = (typeof(fCallback) == 'function') ? fCallback :
183
+ (typeof(pData) == 'function') ? pData :
184
+ // This is here in case the developer passed no callback and just wants to fire and forget the IPC call which might not be async safe
185
+ ()=>{};
186
+
187
+ // Create a bare minimum request object for IPC to pass to our router
188
+ let tmpRequest = (
189
+ {
190
+ method: pMethod,
191
+ url: pRoute,
192
+ guid: this.orator.fable.getUUID()
193
+ });
194
+
195
+ // Create a container for the IPC response data to be aggregated to from send() methodds
196
+ let tmpSynthesizedResponseData = new libOratorServiceServerIPCSynthesizedResponse(this.log, tmpRequest.guid);
197
+
198
+ return this.router.lookup(
199
+ tmpRequest,
200
+ tmpSynthesizedResponseData,
201
+ (pError, pResults)=>
202
+ {
203
+ if (pError)
204
+ {
205
+ this.log.error(`IPC Request Error Request GUID [${tmpRequest.guid}] handling route [${pRoute}]: ${pError}`, {Error: pError, Route: pRoute, Data: pData});
206
+ }
207
+
208
+ // by default, send data back through
209
+ return tmpCallback(pError, tmpSynthesizedResponseData.responseData, tmpSynthesizedResponseData, pResults);
210
+ });
211
+ }
212
+ }
213
+
214
+ module.exports = OratorServiceServerIPC;