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/src/Registry.js CHANGED
@@ -1,45 +1,51 @@
1
- import { connection, codec } from './Connection.js'
2
- import { sleep } from './Util.js'
3
- import semver from 'semver'
4
- import EventEmitter from 'events'
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('gx2.beacon')
30
+ const subscription = await connection.subscribe("gx2.beacon");
30
31
 
31
32
  for await (const event of subscription) {
32
- const data = codec.decode(event.data)
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('added', this.#registry[data.i])
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('removed', entry)
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: (target, method, receiver) => async (...args) => Request(service, method, args, context)
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 './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'
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 (let n = 0; n < stack.length; n++) {
45
- const typeName = stack[n].getTypeName()
44
+ for (const item of stack) {
45
+ const typeName = item.getTypeName();
46
46
 
47
47
  if (Service.serviceClasses.includes(typeName))
48
- return `${typeName}.${stack[n].getMethodName()}`
48
+ return `${typeName}.${item.getMethodName()}`;
49
49
  }
50
50
  }
51
51
 
52
52
  /**
53
+ * Send a request to a service
53
54
  *
54
- * @param {*} service
55
- * @param {*} method
56
- * @param {*} args
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 = [], context = [], options) {
60
- const match = service.match(/(?<name>[^@#]*)(@(?<version>[^@#]*))?(#(?<id>[^@#]*))?/)
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
- if (!identifier)
80
- throw Error(`Request: requested instance of ${service} not found`)
82
+ return directRequest(identifier, method, args, context, options, service);
83
+ }
81
84
 
82
- let response
83
- const originator = getOriginator()
84
- let requestBegin = Date.now()
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('GxError: Request', inspect({
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(`Request: invalid response`)
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 !== 'function')
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
  }
@@ -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
+ };