geonix 1.12.3 → 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.
@@ -0,0 +1,25 @@
1
+ import globals from "globals";
2
+ import eslint from "@eslint/js";
3
+
4
+ export default [
5
+ eslint.configs.recommended,
6
+ {
7
+ files: ["**/*.js"],
8
+ languageOptions: {
9
+ ecmaVersion: 2022,
10
+ sourceType: "module",
11
+ globals: {
12
+ ...globals.node,
13
+ ...globals.browser,
14
+ }
15
+ },
16
+ rules: {
17
+ // "no-console": "error",
18
+ semi: "error",
19
+ "no-unused-vars": ["error", { argsIgnorePattern: "^_.*" }],
20
+ "no-constant-condition": ["error", { checkLoops: false }],
21
+ quotes: ["error", "double", { avoidEscape: true }],
22
+ "no-multiple-empty-lines": ["error", { max: 1 }]
23
+ },
24
+ }
25
+ ];
@@ -1,14 +1,14 @@
1
- import { Service } from 'geonix'
2
- import { ServeStatic } from 'geonix'
1
+ import { Service } from "geonix";
2
+ import { ServeStatic } from "geonix";
3
3
 
4
4
  class StaticServer extends Service {
5
5
 
6
6
  // simple version
7
- 'GET *' = ServeStatic('public')
7
+ "GET *" = ServeStatic("public");
8
8
 
9
9
  // in a folder
10
- 'GET /folder/*' = ServeStatic('public', { root: '/folder/' })
10
+ "GET /folder/*" = ServeStatic("public", { root: "/folder/" });
11
11
 
12
12
  }
13
13
 
14
- StaticServer.start()
14
+ StaticServer.start();
@@ -1,15 +1,15 @@
1
1
  {
2
- "name": "servicestatic",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "author": "",
11
- "license": "ISC",
12
- "dependencies": {
13
- "geonix": "^1.0.13"
14
- }
15
- }
2
+ "name": "servicestatic",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "geonix": "^1.0.13"
14
+ }
15
+ }
@@ -1,13 +1,13 @@
1
- import { Service } from 'geonix'
1
+ import { Service } from "geonix";
2
2
 
3
3
  class SimpleService extends Service {
4
4
 
5
5
  reverseString(input) {
6
- return input.split('').reverse().join('')
6
+ return input.split("").reverse().join("");
7
7
  }
8
8
 
9
- 'GET /simpleservice/reversestring'(req, res) {
10
- res.send(this.reverseString(req.query.q))
9
+ "GET /simpleservice/reversestring"(req, res) {
10
+ res.send(this.reverseString(req.query.q));
11
11
  }
12
12
 
13
13
  }
@@ -16,12 +16,12 @@ class SimpleService extends Service {
16
16
 
17
17
  class TestService extends Service {
18
18
 
19
- 'GET /test'(req, res) {
20
- console.log('rawr')
19
+ "GET /test"(req, res) {
20
+ console.log("rawr");
21
21
 
22
- res.send('ok')
22
+ res.send("ok");
23
23
  }
24
24
 
25
25
  }
26
26
 
27
- TestService.start()
27
+ TestService.start();
@@ -1,15 +1,15 @@
1
1
  {
2
- "name": "simpleservice",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "author": "",
11
- "license": "ISC",
12
- "dependencies": {
13
- "geonix": "^1.0.16"
14
- }
15
- }
2
+ "name": "simpleservice",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "geonix": "^1.0.16"
14
+ }
15
+ }
package/exports.js CHANGED
@@ -1,43 +1,14 @@
1
- import { readFile } from 'fs/promises'
2
- import semver from 'semver'
3
- import { URL, fileURLToPath } from 'url'
4
- import { join } from 'path'
5
-
6
- try {
7
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
- const local = JSON.parse(await readFile(join(__dirname, 'package.json')))
9
- let remote = await (await fetch('https://registry.npmjs.com/-/v1/search?text=geonix')).json()
10
-
11
- if (remote?.objects?.length > 0) {
12
- remote = remote.objects[0].package
13
-
14
- _geonix_version = local.version
15
-
16
- if (semver.lt(local.version, remote.version)) {
17
- let line = `${local.version} → ${remote.version}`
18
- line = ' '.repeat(Math.floor((39 - line.length) / 2)) + line + ' '.repeat(Math.ceil((39 - line.length) / 2))
19
-
20
- console.log(`╭───────────────────────────────────────╮`)
21
- console.log(`│ Geonix update available │`)
22
- console.log(`│${line}│`)
23
- console.log(`╰───────────────────────────────────────╯`)
24
- }
25
- }
26
- } catch (e) {
27
- // silently ignore version check
28
- }
29
-
30
- export * from './src/Service.js'
31
- export * from './src/Stream.js'
32
- export * from './src/Remote.js'
33
-
34
- export { ServeStatic } from './src/WebServer.js'
35
- export { Gateway } from './src/Gateway.js'
36
- export { GeonixVersion } from './src/Util.js'
37
- export { connection, stopConnection } from './src/Connection.js'
38
- export { registry } from './src/Registry.js'
39
- export { Request, Subscribe, Publish } from './src/Request.js'
40
- export { RequestOptions } from './src/RequestOptions.js'
41
- export { picoid as randomID } from './src/Util.js'
42
-
43
- export { stats as StreamStats } from './src/Stream.js'
1
+ export * from "./src/Service.js";
2
+ export * from "./src/Stream.js";
3
+ export * from "./src/Remote.js";
4
+
5
+ export { ServeStatic } from "./src/WebServer.js";
6
+ export { Gateway } from "./src/Gateway.js";
7
+ export { GeonixVersion } from "./src/Util.js";
8
+ export { connection, stopConnection } from "./src/Connection.js";
9
+ export { registry } from "./src/Registry.js";
10
+ export { Request, Subscribe, Publish } from "./src/Request.js";
11
+ export { RequestOptions } from "./src/RequestOptions.js";
12
+ export { picoid as randomID } from "./src/Util.js";
13
+
14
+ export { stats as StreamStats } from "./src/Stream.js";
package/index.d.ts CHANGED
@@ -47,7 +47,7 @@ declare class Connection {
47
47
  * @param {object} options
48
48
  * @returns any
49
49
  */
50
- request(subject: string, json: object, options?: object): Promise<unknown>;
50
+ request(subject: string, json: object, opts?: {}): Promise<unknown>;
51
51
  subscribe(subject: any, options: any): Promise<any>;
52
52
  unsubscribe(subscription: any): Promise<void>;
53
53
  /**
@@ -84,6 +84,14 @@ export function Remote(service: string, ...context: (string | Stream | Object)[]
84
84
  * @returns
85
85
  */
86
86
  export function Request(service: any, method: any, args: any, context: any[] | undefined, options: any): Promise<any>;
87
+ /**
88
+ *
89
+ * @param {*} service
90
+ * @param {*} method
91
+ * @param {*} args
92
+ * @returns
93
+ */
94
+ export function directRequest(identifier: any, method: any, args: any, context: any[] | undefined, options: any, service: any): Promise<any>;
87
95
  /**
88
96
  * Publish payload to a subject
89
97
  *
@@ -109,8 +117,8 @@ export class Service {
109
117
  static start(options?: {}): void;
110
118
  static static(): void;
111
119
  connections: Map<any, any>;
112
- SYS_createConnection(streamId: any): Promise<boolean>;
113
- SYS_getEnv(): Promise<{
120
+ $createConnection(streamId: any): Promise<boolean>;
121
+ $getEnv(): {
114
122
  geonix: string;
115
123
  node: {
116
124
  version: any;
@@ -121,11 +129,12 @@ export class Service {
121
129
  mem: any;
122
130
  rss: any;
123
131
  cpu: any;
124
- }>;
132
+ };
133
+ $getServiceInfo(): {};
125
134
  #private;
126
135
  }
127
136
  /**
128
- * Converts input data to stream
137
+ * Converts data to stream
129
138
  *
130
139
  * @param {*} data
131
140
  * @param {*} automated
@@ -133,10 +142,8 @@ export class Service {
133
142
  */
134
143
  export function Stream(data: any, tag?: string): any;
135
144
  export function isStream(object: any): any;
136
- export function getReadable(object: any, forceNats?: boolean): Promise<any>;
137
- export function getReadableOverHTTP(object: any): Promise<any>;
138
- export function getReadableOverNATS(object: any): Promise<any>;
139
- export function streamToBuffer(object: any, forceNats?: boolean): Promise<any>;
145
+ export function getReadable(object: any): Promise<any>;
146
+ export function streamToBuffer(object: any): Promise<any>;
140
147
  export function streamToString(object: any): Promise<any>;
141
148
  export const stats: {};
142
149
  /**
@@ -144,16 +151,7 @@ export const stats: {};
144
151
  * @param {string} url
145
152
  * @returns
146
153
  */
147
- export function parseURL(url: string): {
148
- servers: string;
149
- user: any;
150
- pass: any;
151
- token: any;
152
- };
153
- export function timeoutAsyncGenerator(target: any, ms: any): {};
154
- export function waitForAbort(abortSignal: any, result: any): Promise<any>;
155
- export function abortableAsyncGenerator(target: any, abortSignal: any): {};
156
- export function getNetworkAddresses(): any[];
154
+ export function parseURL(url: string): any;
157
155
  export function sleep(delay: number): Promise<any>;
158
156
  export function picoid(size?: number): any;
159
157
  export function hash(data: string | Buffer): any;
@@ -172,6 +170,7 @@ export function ServeStatic(root: any, options?: {}): any;
172
170
  export const webserver: WebServer;
173
171
  declare class WebServer {
174
172
  start(): Promise<void>;
173
+ getAddresses(): any[];
175
174
  getPort(): any;
176
175
  router(): any;
177
176
  waitUntilReady(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geonix",
3
- "version": "1.12.3",
3
+ "version": "1.20.0",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "bin": {
@@ -9,22 +9,26 @@
9
9
  "main": "exports.js",
10
10
  "scripts": {
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
- "build": "tsc && cat build/* > index.d.ts && rm -rf build",
12
+ "build": "npx tsc && cat build/* > index.d.ts && rm -rf build",
13
13
  "deploy": "npm run build && npm publish"
14
14
  },
15
15
  "author": "Davor Tarandek <dtarandek@tria.hr>",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "cookie-parser": "^1.4.6",
19
- "express": "^4.18.2",
19
+ "express": "^4.19.2",
20
20
  "express-async-errors": "^3.1.1",
21
21
  "express-ws": "^5.0.2",
22
22
  "multer": "^1.4.5-lts.1",
23
- "nats": "^2.19.0",
24
- "semver": "^7.5.4",
25
- "ws": "^8.16.0"
23
+ "nats": "^2.28.2",
24
+ "semver": "^7.6.3",
25
+ "ws": "^8.18.0"
26
26
  },
27
27
  "publishConfig": {
28
28
  "registry": "https://registry.npmjs.org/"
29
+ },
30
+ "devDependencies": {
31
+ "eslint": "^9.9.1",
32
+ "typescript": "^5.5.4"
29
33
  }
30
34
  }
package/src/Connection.js CHANGED
@@ -1,11 +1,14 @@
1
- import { connect, JSONCodec } from 'nats'
2
- import { parseURL, picoid, sleep } from './Util.js'
3
- import { Stream } from './Stream.js'
4
- import { webserver } from './WebServer.js'
1
+ import { connect, JSONCodec } from "nats";
2
+ import { parseURL, picoid, sleep } from "./Util.js";
3
+ import { Stream } from "./Stream.js";
4
+ import { webserver } from "./WebServer.js";
5
5
 
6
6
  // -------------------------------------------------------------------------------------------------
7
- const REQUEST_TIMEOUT = 30000
8
- const CONNECTION_TIMEOUT = 10000
7
+ const CONNECTION_TIMEOUT = 10000;
8
+
9
+ const defaultRequestOptions = {
10
+ timeout: 300000
11
+ };
9
12
  // -------------------------------------------------------------------------------------------------
10
13
 
11
14
  /**
@@ -17,58 +20,68 @@ const CONNECTION_TIMEOUT = 10000
17
20
  */
18
21
  class Connection {
19
22
 
20
- #draining = false
21
- #closed = false
22
- #ready = false
23
- #nc
23
+ #draining = false;
24
+ #closed = false;
25
+ #ready = false;
26
+ #connections = [];
27
+ #connectionRoundRobin = 0;
28
+
29
+ #getConnection() {
30
+ this.#connectionRoundRobin = ++this.#connectionRoundRobin % this.#connections.length;
31
+ return this.#connections[this.#connectionRoundRobin];
32
+ }
24
33
 
25
34
  /**
26
35
  * Initiates connection to transport
27
36
  * @param {string} transport
28
37
  */
29
- async start(transport = process.env.TRANSPORT || 'nats://localhost') {
38
+ async start(transport = process.env.TRANSPORT || "nats://localhost") {
30
39
  const defaults = {
31
40
  timeout: CONNECTION_TIMEOUT,
32
41
  reconnect: true,
33
- debug: process.env.TRANSPORT_DEBUG === 'true',
42
+ debug: process.env.TRANSPORT_DEBUG === "true",
34
43
  maxReconnectAttempts: 30,
35
44
  pingInterval: 30000,
36
- waitOnFirstConnect: true
37
- }
45
+ waitOnFirstConnect: true,
46
+ connections: 1
47
+ };
38
48
  const options = {
39
49
  ...defaults,
40
50
  ...parseURL(transport)
41
- }
51
+ };
42
52
 
43
- this.#nc = await connect(options)
53
+ for (let i = 0; i < options.connections; i++) {
54
+ this.#connections.push(await connect(options));
55
+ }
44
56
 
45
- console.log('gx.connection.connected')
57
+ console.log("gx.connection.connected");
46
58
 
47
- this.#ready = true
59
+ this.#ready = true;
48
60
 
49
- this.monitorStatus()
50
- this.waitUntilClosed()
61
+ this.monitorStatus();
62
+ this.waitUntilClosed();
51
63
  }
52
64
 
53
65
  async monitorStatus() {
54
- for await (const event of this.#nc.status())
55
- console.log('gx.connection.status', JSON.stringify(event))
66
+ for await (const event of this.#getConnection().status()) {
67
+ console.log("gx.connection.status", JSON.stringify(event));
68
+ }
56
69
  }
57
70
 
58
71
  /**
59
72
  * Wait for the connection to be safely closed
60
73
  */
61
74
  async waitUntilClosed() {
62
- await this.#nc.closed()
63
- this.#closed = true
64
- console.log('gx.connection.closed')
75
+ await this.#getConnection().closed();
76
+ this.#closed = true;
77
+ console.log("gx.connection.closed");
65
78
 
66
- webserver.stop()
79
+ webserver.stop();
67
80
 
68
- await sleep(5000)
81
+ await sleep(5000);
69
82
 
70
- console.log('gx.terminate')
71
- process.exit(1)
83
+ console.log("gx.terminate");
84
+ process.exit(1);
72
85
  }
73
86
 
74
87
  /**
@@ -76,7 +89,7 @@ class Connection {
76
89
  */
77
90
  async waitUntilReady() {
78
91
  while (!this.#ready)
79
- await sleep(100)
92
+ await sleep(100);
80
93
  }
81
94
 
82
95
  /**
@@ -88,15 +101,15 @@ class Connection {
88
101
  */
89
102
  async publish(subject, json) {
90
103
  if (this.#draining || this.#closed)
91
- return
104
+ return;
92
105
 
93
- let payload = codec.encode(json)
106
+ let payload = codec.encode(json);
94
107
 
95
108
  // if payload is too big, convert it to Stream
96
109
  if (payload.length > this.getMaxPayloadSize())
97
- payload = codec.encode(Stream(JSON.stringify(json)))
110
+ payload = codec.encode(Stream(JSON.stringify(json)));
98
111
 
99
- await this.#nc.publish(subject, payload)
112
+ await this.#getConnection().publish(subject, payload);
100
113
  }
101
114
 
102
115
  /**
@@ -108,9 +121,9 @@ class Connection {
108
121
  */
109
122
  async publishRaw(subject, data) {
110
123
  if (this.#draining || this.#closed)
111
- return
124
+ return;
112
125
 
113
- await this.#nc.publish(subject, data)
126
+ await this.#getConnection().publish(subject, data);
114
127
  }
115
128
 
116
129
  /**
@@ -121,29 +134,35 @@ class Connection {
121
134
  * @param {object} options
122
135
  * @returns any
123
136
  */
124
- async request(subject, json, options = { timeout: 300000 }) {
125
- const respondTo = `gx2.r.${picoid(16)}`
137
+ async request(subject, json, opts = {}) {
138
+ const options = {
139
+ ...defaultRequestOptions,
140
+ ...opts
141
+ };
142
+
143
+ const respondTo = `gx2.r.${picoid(16)}`;
126
144
 
127
- let payload = codec.encode({ $r: respondTo, p: json })
145
+ let payload = codec.encode({ $r: respondTo, p: json });
128
146
 
129
147
  // if payload is too big, convert it to Stream
130
148
  if (payload.length > this.getMaxPayloadSize())
131
- payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })))
149
+ payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })));
132
150
 
133
- let response = await this.#nc.subscribe(respondTo, { max: 1, ...options })
151
+ const nc = this.#getConnection();
152
+ let response = await nc.subscribe(respondTo, { max: 1, ...options });
134
153
 
135
- await this.#nc.publish(subject, payload)
154
+ await nc.publish(subject, payload);
136
155
 
137
156
  for await (let event of response)
138
- return codec.decode(event.data)
157
+ return codec.decode(event.data);
139
158
  }
140
159
 
141
160
  async subscribe(subject, options) {
142
- return this.#nc.subscribe(subject, options)
161
+ return this.#getConnection().subscribe(subject, options);
143
162
  }
144
163
 
145
164
  async unsubscribe(subscription) {
146
- subscription.unsubscribe()
165
+ subscription.unsubscribe();
147
166
  }
148
167
 
149
168
  /**
@@ -151,28 +170,32 @@ class Connection {
151
170
  * @returns {number}
152
171
  */
153
172
  getMaxPayloadSize() {
154
- return this.#nc?.info?.max_payload || 1024 * 512
173
+ const nc = this.#getConnection();
174
+ return nc?.info?.max_payload || 1024 * 512;
155
175
  }
156
176
 
157
177
  isClosed() {
158
- return this.#closed
178
+ return this.#closed;
159
179
  }
160
180
 
161
181
  async drain() {
162
- this.#draining = true
163
- await this.#nc.drain()
182
+ this.#draining = true;
183
+
184
+ for (let connection of this.#connections) {
185
+ await connection.drain();
186
+ }
164
187
  }
165
188
 
166
189
  }
167
190
 
168
- export const codec = JSONCodec()
191
+ export const codec = JSONCodec();
169
192
 
170
- export const connection = new Connection()
171
- connection.start()
193
+ export const connection = new Connection();
194
+ connection.start();
172
195
 
173
196
  export const stopConnection = () => {
174
197
  if (!connection)
175
- return
198
+ return;
176
199
 
177
- connection.drain()
178
- }
200
+ connection.drain();
201
+ };