geonix 1.12.2 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.js +25 -0
- package/examples/ServeStatic/index.js +5 -5
- package/examples/ServeStatic/package.json +14 -14
- package/examples/SimpleService/index.js +8 -8
- package/examples/SimpleService/package.json +14 -14
- package/exports.js +14 -43
- package/index.d.ts +20 -20
- package/package.json +10 -6
- package/src/Connection.js +78 -55
- package/src/Gateway.js +214 -198
- package/src/Registry.js +38 -32
- package/src/Remote.js +3 -3
- package/src/Request.js +66 -52
- package/src/RequestOptions.js +4 -4
- package/src/Service.js +128 -121
- package/src/Stream.js +48 -139
- package/src/Util.js +85 -124
- package/src/WebServer.js +68 -65
- package/test/gateway.js +15 -0
- package/test/package.json +16 -0
- package/test/stream.js +38 -0
- package/tsconfig.json +10 -10
- package/src/status/deps/babel.development.js +0 -135978
- package/src/status/deps/babel.min.js +0 -17
- package/src/status/deps/react-dom.development.js +0 -29869
- package/src/status/deps/react-dom.production.min.js +0 -267
- package/src/status/deps/react.development.js +0 -3342
- package/src/status/deps/react.production.min.js +0 -31
- package/src/status/index.html +0 -13
- package/src/status/main.js +0 -30
package/src/Registry.js
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
|
-
import { connection, codec } from
|
|
2
|
-
import { sleep } from
|
|
3
|
-
import semver from
|
|
4
|
-
import EventEmitter from
|
|
1
|
+
import { connection, codec } from "./Connection.js";
|
|
2
|
+
import { sleep } from "./Util.js";
|
|
3
|
+
import semver from "semver";
|
|
4
|
+
import EventEmitter from "events";
|
|
5
|
+
import { directRequest } from "./Request.js";
|
|
5
6
|
|
|
6
|
-
const REGISTRY_ENTRY_TIMEOUT = 5000
|
|
7
|
+
const REGISTRY_ENTRY_TIMEOUT = 5000;
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Registry maintains a local list of available services and their versions.
|
|
10
11
|
*/
|
|
11
12
|
class Registry extends EventEmitter {
|
|
12
13
|
|
|
13
|
-
#registry = {}
|
|
14
|
+
#registry = {};
|
|
14
15
|
|
|
15
16
|
constructor() {
|
|
16
|
-
super()
|
|
17
|
+
super();
|
|
17
18
|
|
|
18
|
-
this.#start()
|
|
19
|
+
this.#start();
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
async #start() {
|
|
22
|
-
await connection.waitUntilReady()
|
|
23
|
+
await connection.waitUntilReady();
|
|
23
24
|
|
|
24
|
-
this.#beaconListener()
|
|
25
|
-
this.#garbageCollector()
|
|
25
|
+
this.#beaconListener();
|
|
26
|
+
this.#garbageCollector();
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
async #beaconListener() {
|
|
29
|
-
const subscription = await connection.subscribe(
|
|
30
|
+
const subscription = await connection.subscribe("gx2.beacon");
|
|
30
31
|
|
|
31
32
|
for await (const event of subscription) {
|
|
32
|
-
|
|
33
|
+
let data = codec.decode(event.data);
|
|
33
34
|
|
|
34
|
-
const exists = this.#registry[data.i] !== undefined
|
|
35
|
+
const exists = this.#registry[data.i] !== undefined;
|
|
36
|
+
|
|
37
|
+
// if this is a short beacon, request full service info
|
|
38
|
+
if (!data.n) {
|
|
39
|
+
data = await directRequest(data.i, "$getServiceInfo");
|
|
40
|
+
}
|
|
35
41
|
|
|
36
42
|
this.#registry[data.i] = {
|
|
37
43
|
...data,
|
|
38
44
|
timeout: Date.now() + REGISTRY_ENTRY_TIMEOUT
|
|
39
|
-
}
|
|
45
|
+
};
|
|
40
46
|
|
|
41
47
|
if (!exists)
|
|
42
|
-
this.emit(
|
|
48
|
+
this.emit("added", this.#registry[data.i]);
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
|
|
@@ -48,51 +54,51 @@ class Registry extends EventEmitter {
|
|
|
48
54
|
*/
|
|
49
55
|
async #garbageCollector() {
|
|
50
56
|
while (true) {
|
|
51
|
-
const now = Date.now()
|
|
57
|
+
const now = Date.now();
|
|
52
58
|
for (let identifier in this.#registry) {
|
|
53
|
-
const entry = this.#registry[identifier]
|
|
59
|
+
const entry = this.#registry[identifier];
|
|
54
60
|
|
|
55
61
|
if (now > entry.timeout) {
|
|
56
|
-
delete this.#registry[identifier]
|
|
62
|
+
delete this.#registry[identifier];
|
|
57
63
|
|
|
58
|
-
this.emit(
|
|
64
|
+
this.emit("removed", entry);
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
await sleep(500)
|
|
68
|
+
await sleep(500);
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
getEntries() {
|
|
67
|
-
return this.#registry
|
|
73
|
+
return this.#registry;
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
getIdentifier(service, version, id) {
|
|
71
|
-
let matches = []
|
|
77
|
+
let matches = [];
|
|
72
78
|
|
|
73
79
|
for (let identifier in this.#registry) {
|
|
74
|
-
const entry = this.#registry[identifier]
|
|
80
|
+
const entry = this.#registry[identifier];
|
|
75
81
|
|
|
76
|
-
let matchName = entry.n === service
|
|
77
|
-
let matchVersion = version ? semver.satisfies(entry.v, version) : true
|
|
78
|
-
let matchId = id ? entry.id === id : true
|
|
82
|
+
let matchName = entry.n === service;
|
|
83
|
+
let matchVersion = version ? semver.satisfies(entry.v, version) : true;
|
|
84
|
+
let matchId = id ? entry.id === id : true;
|
|
79
85
|
|
|
80
86
|
if (matchName && matchVersion && matchId)
|
|
81
|
-
matches.push(entry)
|
|
87
|
+
matches.push(entry);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
if (matches.length > 0) {
|
|
85
91
|
// return instance id in case of id matching
|
|
86
92
|
if (id)
|
|
87
|
-
return matches[0].i
|
|
93
|
+
return matches[0].i;
|
|
88
94
|
|
|
89
95
|
// sort matched services in the registry by version
|
|
90
|
-
matches.sort((a, b) => semver.rcompare(a.v, b.v))
|
|
96
|
+
matches.sort((a, b) => semver.rcompare(a.v, b.v));
|
|
91
97
|
|
|
92
|
-
return `${matches[0].n}@${matches[0].v}
|
|
98
|
+
return `${matches[0].n}@${matches[0].v}`;
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
export const registry = new Registry()
|
|
104
|
+
export const registry = new Registry();
|
package/src/Remote.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Request } from "./Request.js"
|
|
1
|
+
import { Request } from "./Request.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Create a remote function proxy
|
|
@@ -8,5 +8,5 @@ import { Request } from "./Request.js"
|
|
|
8
8
|
* @returns {String|Stream|Object}
|
|
9
9
|
*/
|
|
10
10
|
export const Remote = (service, ...context) => new Proxy({}, {
|
|
11
|
-
get: (
|
|
12
|
-
})
|
|
11
|
+
get: (_target, method, _receiver) => async (...args) => Request(service, method, args, context)
|
|
12
|
+
});
|
package/src/Request.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { connection } from
|
|
2
|
-
import { registry } from
|
|
3
|
-
import { Service } from
|
|
4
|
-
import { hash, sleep } from
|
|
5
|
-
import { RequestOptionsClass } from
|
|
6
|
-
import { isStream, streamToString } from
|
|
7
|
-
import { inspect } from
|
|
1
|
+
import { connection } from "./Connection.js";
|
|
2
|
+
import { registry } from "./Registry.js";
|
|
3
|
+
import { Service } from "./Service.js";
|
|
4
|
+
import { hash, sleep } from "./Util.js";
|
|
5
|
+
import { RequestOptionsClass } from "./RequestOptions.js";
|
|
6
|
+
import { isStream, streamToString } from "./Stream.js";
|
|
7
|
+
import { inspect } from "node:util";
|
|
8
8
|
|
|
9
|
-
const REGISTRY_TIMEOUT = 300000
|
|
9
|
+
const REGISTRY_TIMEOUT = 300000;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get full v8 stack trace
|
|
13
13
|
* @returns
|
|
14
14
|
*/
|
|
15
15
|
function getStack() {
|
|
16
|
-
const oldLimit = Error.stackTraceLimit
|
|
17
|
-
const oldHandler = Error.prepareStackTrace
|
|
16
|
+
const oldLimit = Error.stackTraceLimit;
|
|
17
|
+
const oldHandler = Error.prepareStackTrace;
|
|
18
18
|
const holder = {};
|
|
19
19
|
|
|
20
20
|
// set new values
|
|
21
21
|
Error.stackTraceLimit = Infinity;
|
|
22
|
-
Error.prepareStackTrace = (holder, stackTrace) => stackTrace
|
|
22
|
+
Error.prepareStackTrace = (holder, stackTrace) => stackTrace;
|
|
23
23
|
|
|
24
24
|
// capture stack trace
|
|
25
|
-
Error.captureStackTrace(holder, getStack)
|
|
25
|
+
Error.captureStackTrace(holder, getStack);
|
|
26
26
|
|
|
27
|
-
const stack = holder.stack
|
|
27
|
+
const stack = holder.stack;
|
|
28
28
|
|
|
29
29
|
// restore values
|
|
30
|
-
Error.prepareStackTrace = oldHandler
|
|
31
|
-
Error.stackTraceLimit = oldLimit
|
|
30
|
+
Error.prepareStackTrace = oldHandler;
|
|
31
|
+
Error.stackTraceLimit = oldLimit;
|
|
32
32
|
|
|
33
|
-
return stack
|
|
33
|
+
return stack;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -39,49 +39,63 @@ function getStack() {
|
|
|
39
39
|
* @returns
|
|
40
40
|
*/
|
|
41
41
|
function getOriginator() {
|
|
42
|
-
const stack = getStack()
|
|
42
|
+
const stack = getStack();
|
|
43
43
|
|
|
44
|
-
for (
|
|
45
|
-
const typeName =
|
|
44
|
+
for (const item of stack) {
|
|
45
|
+
const typeName = item.getTypeName();
|
|
46
46
|
|
|
47
47
|
if (Service.serviceClasses.includes(typeName))
|
|
48
|
-
return `${typeName}.${
|
|
48
|
+
return `${typeName}.${item.getMethodName()}`;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
+
* Send a request to a service
|
|
53
54
|
*
|
|
54
|
-
* @param {
|
|
55
|
-
* @param {
|
|
56
|
-
* @param {
|
|
55
|
+
* @param {string} service
|
|
56
|
+
* @param {string} method
|
|
57
|
+
* @param {any[]} args
|
|
58
|
+
* @param {any[]} context
|
|
59
|
+
* @param {object} options
|
|
57
60
|
* @returns
|
|
58
61
|
*/
|
|
59
|
-
export async function Request(service, method, args
|
|
60
|
-
const match =
|
|
61
|
-
const { name, version, id } = match.groups
|
|
62
|
+
export async function Request(service, method, args, context, options) {
|
|
63
|
+
const match = /(?<name>[^@#]*)(@(?<version>[^@#]*))?(#(?<id>[^@#]*))?/.exec(service);
|
|
64
|
+
const { name, version, id } = match.groups;
|
|
62
65
|
|
|
63
66
|
// allow passing RequestOptions as first arg
|
|
64
67
|
if (args?.length > 0 && args[0] instanceof RequestOptionsClass)
|
|
65
|
-
options = (args.shift())?.options
|
|
68
|
+
options = (args.shift())?.options;
|
|
66
69
|
|
|
67
|
-
let identifier = null
|
|
70
|
+
let identifier = null;
|
|
68
71
|
|
|
69
72
|
// get service instance identifier and wait for it if it's not available
|
|
70
|
-
const registryTimeout = options?.timeout ?? REGISTRY_TIMEOUT
|
|
71
|
-
const delay = 5
|
|
72
|
-
let retries = Math.floor(registryTimeout / delay)
|
|
73
|
+
const registryTimeout = options?.timeout ?? REGISTRY_TIMEOUT;
|
|
74
|
+
const delay = 5;
|
|
75
|
+
let retries = Math.floor(registryTimeout / delay);
|
|
73
76
|
while (identifier == null && retries-- > 0) {
|
|
74
|
-
identifier = registry.getIdentifier(name, version, id)
|
|
77
|
+
identifier = registry.getIdentifier(name, version, id);
|
|
75
78
|
if (!identifier)
|
|
76
|
-
await sleep(delay)
|
|
79
|
+
await sleep(delay);
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
return directRequest(identifier, method, args, context, options, service);
|
|
83
|
+
}
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Send a request to a service
|
|
87
|
+
*
|
|
88
|
+
* @param {string} identifier
|
|
89
|
+
* @param {string} method
|
|
90
|
+
* @param {any[]} args
|
|
91
|
+
* @param {any[]} context
|
|
92
|
+
* @param {object} options
|
|
93
|
+
* @returns
|
|
94
|
+
*/
|
|
95
|
+
export async function directRequest(identifier, method, args, context, options, service) {
|
|
96
|
+
let response;
|
|
97
|
+
const originator = getOriginator();
|
|
98
|
+
let requestBegin = Date.now();
|
|
85
99
|
try {
|
|
86
100
|
response = await connection.request(
|
|
87
101
|
`gx2.service.${hash(identifier)}`,
|
|
@@ -91,28 +105,28 @@ export async function Request(service, method, args = [], context = [], options)
|
|
|
91
105
|
c: context,
|
|
92
106
|
o: originator
|
|
93
107
|
},
|
|
94
|
-
options)
|
|
108
|
+
options);
|
|
95
109
|
|
|
96
110
|
// automatically process streamed response
|
|
97
111
|
if (isStream(response))
|
|
98
|
-
response = JSON.parse(await streamToString(response))
|
|
112
|
+
response = JSON.parse(await streamToString(response));
|
|
99
113
|
} catch (e) {
|
|
100
|
-
console.debug(
|
|
101
|
-
originator, service, method, args, context, options,
|
|
114
|
+
console.debug("GxError: directRequest", inspect({
|
|
115
|
+
originator, service: service ?? identifier, method, args, context, options,
|
|
102
116
|
error: e, duration: Date.now() - requestBegin
|
|
103
|
-
}))
|
|
117
|
+
}));
|
|
104
118
|
|
|
105
|
-
throw e
|
|
119
|
+
throw e;
|
|
106
120
|
}
|
|
107
121
|
|
|
108
122
|
if (!response)
|
|
109
|
-
throw Error(
|
|
123
|
+
throw Error("Request: invalid response");
|
|
110
124
|
|
|
111
125
|
// got error?
|
|
112
126
|
if (response.e)
|
|
113
|
-
throw Error(`Request: remote error: ${response.e}`)
|
|
127
|
+
throw Error(`Request: remote error: ${response.e}`);
|
|
114
128
|
|
|
115
|
-
return response.r
|
|
129
|
+
return response.r;
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
/**
|
|
@@ -122,7 +136,7 @@ export async function Request(service, method, args = [], context = [], options)
|
|
|
122
136
|
* @param {string|number} payload
|
|
123
137
|
*/
|
|
124
138
|
export async function Publish(subject, payload) {
|
|
125
|
-
connection.publishRaw(`gx.sub.${subject}`, Buffer.from(payload))
|
|
139
|
+
connection.publishRaw(`gx.sub.${subject}`, Buffer.from(payload));
|
|
126
140
|
}
|
|
127
141
|
|
|
128
142
|
/**
|
|
@@ -133,10 +147,10 @@ export async function Publish(subject, payload) {
|
|
|
133
147
|
* @returns
|
|
134
148
|
*/
|
|
135
149
|
export async function Subscribe(subject, callback) {
|
|
136
|
-
if (typeof callback !==
|
|
137
|
-
return
|
|
150
|
+
if (typeof callback !== "function")
|
|
151
|
+
return;
|
|
138
152
|
|
|
139
|
-
const subscription = await connection.subscribe(`gx.sub.${subject}`)
|
|
153
|
+
const subscription = await connection.subscribe(`gx.sub.${subject}`);
|
|
140
154
|
for await (const event of subscription)
|
|
141
|
-
callback(event.data)
|
|
155
|
+
callback(event.data);
|
|
142
156
|
}
|
package/src/RequestOptions.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export class RequestOptionsClass {
|
|
2
|
-
options
|
|
2
|
+
options;
|
|
3
3
|
constructor(options) {
|
|
4
|
-
this.options = options
|
|
4
|
+
this.options = options;
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export const RequestOptions = (options) => {
|
|
9
|
-
return new RequestOptionsClass(options)
|
|
10
|
-
}
|
|
9
|
+
return new RequestOptionsClass(options);
|
|
10
|
+
};
|