geonix 1.8.10 → 1.8.20
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/package.json +5 -5
- package/src/Connection.js +31 -3
- package/src/Request.js +2 -1
- package/test/.env +1 -0
- package/test/inheritance.js +60 -0
- package/test/package.json +3 -1
- package/test/private.js +31 -0
- package/test/registration.js +29 -0
- package/test/stream.js +1 -1
- package/test/stream2.js +42 -0
- package/src/Serialization.js +0 -33
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "geonix",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"bin": {
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"cookie-parser": "^1.4.6",
|
|
19
|
-
"express": "^4.18.
|
|
19
|
+
"express": "^4.18.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.
|
|
24
|
-
"semver": "^7.
|
|
25
|
-
"ws": "^8.
|
|
23
|
+
"nats": "^2.16.0",
|
|
24
|
+
"semver": "^7.5.4",
|
|
25
|
+
"ws": "^8.13.0"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"registry": "https://registry.npmjs.org/"
|
package/src/Connection.js
CHANGED
|
@@ -55,6 +55,9 @@ class Connection {
|
|
|
55
55
|
console.log('gx.connection.status', JSON.stringify(event))
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Wait for the connection to be safely closed
|
|
60
|
+
*/
|
|
58
61
|
async waitUntilClosed() {
|
|
59
62
|
await this.#nc.closed()
|
|
60
63
|
this.#closed = true
|
|
@@ -68,11 +71,21 @@ class Connection {
|
|
|
68
71
|
process.exit(1)
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Wait for the connection to be fully established
|
|
76
|
+
*/
|
|
71
77
|
async waitUntilReady() {
|
|
72
78
|
while (!this.#ready)
|
|
73
79
|
await sleep(100)
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Publish JSON
|
|
84
|
+
*
|
|
85
|
+
* @param {string} subject
|
|
86
|
+
* @param {object} json
|
|
87
|
+
* @returns void
|
|
88
|
+
*/
|
|
76
89
|
async publish(subject, json) {
|
|
77
90
|
if (this.#draining || this.#closed)
|
|
78
91
|
return
|
|
@@ -86,6 +99,13 @@ class Connection {
|
|
|
86
99
|
await this.#nc.publish(subject, payload)
|
|
87
100
|
}
|
|
88
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Publish RAW
|
|
104
|
+
*
|
|
105
|
+
* @param {string} subject
|
|
106
|
+
* @param {string | Buffer} data
|
|
107
|
+
* @returns void
|
|
108
|
+
*/
|
|
89
109
|
async publishRaw(subject, data) {
|
|
90
110
|
if (this.#draining || this.#closed)
|
|
91
111
|
return
|
|
@@ -93,8 +113,16 @@ class Connection {
|
|
|
93
113
|
await this.#nc.publish(subject, data)
|
|
94
114
|
}
|
|
95
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Request/Reply pattern on top of pub/sub
|
|
118
|
+
*
|
|
119
|
+
* @param {string} subject
|
|
120
|
+
* @param {object} json
|
|
121
|
+
* @param {object} options
|
|
122
|
+
* @returns any
|
|
123
|
+
*/
|
|
96
124
|
async request(subject, json, options = { timeout: 300000 }) {
|
|
97
|
-
const respondTo = `
|
|
125
|
+
const respondTo = `gx2.r.${picoid(16)}`
|
|
98
126
|
|
|
99
127
|
let payload = codec.encode({ $r: respondTo, p: json })
|
|
100
128
|
|
|
@@ -102,10 +130,10 @@ class Connection {
|
|
|
102
130
|
if (payload.length > this.getMaxPayloadSize())
|
|
103
131
|
payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })))
|
|
104
132
|
|
|
105
|
-
await this.#nc.publish(subject, payload)
|
|
106
|
-
|
|
107
133
|
let response = await this.#nc.subscribe(respondTo, { max: 1, ...options })
|
|
108
134
|
|
|
135
|
+
await this.#nc.publish(subject, payload)
|
|
136
|
+
|
|
109
137
|
for await (let event of response)
|
|
110
138
|
return codec.decode(event.data)
|
|
111
139
|
}
|
package/src/Request.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Service } from './Service.js'
|
|
|
4
4
|
import { hash, sleep } from './Util.js'
|
|
5
5
|
import { RequestOptionsClass } from './RequestOptions.js'
|
|
6
6
|
import { isStream, streamToString } from './Stream.js'
|
|
7
|
+
import { inspect } from 'node:util'
|
|
7
8
|
|
|
8
9
|
const REGISTRY_TIMEOUT = 300000
|
|
9
10
|
|
|
@@ -91,7 +92,7 @@ export async function Request(service, method, args = [], context = [], options)
|
|
|
91
92
|
},
|
|
92
93
|
options)
|
|
93
94
|
} catch (e) {
|
|
94
|
-
console.debug('GxError: Request',
|
|
95
|
+
console.debug('GxError: Request', inspect({
|
|
95
96
|
originator, service, method, args, context, options,
|
|
96
97
|
error: e, duration: Date.now() - requestBegin
|
|
97
98
|
}))
|
package/test/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TRANSPORT=nats://phobos.tria.hr:4222
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Service, Remote } from 'geonix'
|
|
2
|
+
|
|
3
|
+
const calc = Remote('Calculator')
|
|
4
|
+
const tp = Remote('TimeProvider')
|
|
5
|
+
|
|
6
|
+
class Logger {
|
|
7
|
+
|
|
8
|
+
constructor(prefix) {
|
|
9
|
+
this.prefix = prefix
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
log(...args) {
|
|
13
|
+
console.log(`${new Date().toISOString()}|${this.prefix}|`, ...args)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class BaseService extends Service {
|
|
18
|
+
|
|
19
|
+
logger = new Logger(this.constructor.name)
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CalculatorRepository {
|
|
25
|
+
|
|
26
|
+
constructor(service) {
|
|
27
|
+
this.logger = service.logger
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async getCurrentTime() {
|
|
31
|
+
this.logger.log('getCurrentTime')
|
|
32
|
+
return await Remote('TimeProvider').now()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class Calculator extends BaseService {
|
|
38
|
+
|
|
39
|
+
repo = new CalculatorRepository(this)
|
|
40
|
+
|
|
41
|
+
async onStart() {
|
|
42
|
+
this.logger.log('current time =', await this.repo.getCurrentTime())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
thisHere() {
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class TimeProvider extends BaseService {
|
|
52
|
+
|
|
53
|
+
now() {
|
|
54
|
+
return new Date().toISOString()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Calculator.start()
|
|
60
|
+
TimeProvider.start()
|
package/test/package.json
CHANGED
package/test/private.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const OverlayObject = (object, overlay) => {
|
|
2
|
+
return new Proxy(object, {
|
|
3
|
+
get: (t, p) => overlay[p] !== undefined ? overlay[p] : t[p]
|
|
4
|
+
}
|
|
5
|
+
)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class Test {
|
|
9
|
+
|
|
10
|
+
#me = { works: true }
|
|
11
|
+
|
|
12
|
+
get me() { return this.#me }
|
|
13
|
+
|
|
14
|
+
external() {
|
|
15
|
+
return this.me
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
call(method) {
|
|
19
|
+
try {
|
|
20
|
+
const methodContext = { context: 'this is context value' }
|
|
21
|
+
const $context = OverlayObject(this, methodContext)
|
|
22
|
+
return instance[method].apply($context)
|
|
23
|
+
} catch (e) {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const instance = new Test()
|
|
30
|
+
|
|
31
|
+
console.log(instance.call('external'))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Service, Remote, registry } from '../exports.js'
|
|
2
|
+
import { sleep } from '../src/Util.js'
|
|
3
|
+
|
|
4
|
+
class First extends Service {
|
|
5
|
+
|
|
6
|
+
getTime() {
|
|
7
|
+
return new Date().toISOString()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class Second extends Service {
|
|
13
|
+
|
|
14
|
+
first = Remote('First')
|
|
15
|
+
|
|
16
|
+
async onStart() {
|
|
17
|
+
while (true) {
|
|
18
|
+
console.clear()
|
|
19
|
+
console.log('Time =', await this.first.getTime())
|
|
20
|
+
console.log('REGISTRY =', registry.getEntries())
|
|
21
|
+
|
|
22
|
+
await sleep(1000)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
First.start({ port: 30001 })
|
|
29
|
+
Second.start({ port: 30002 })
|
package/test/stream.js
CHANGED
|
@@ -8,7 +8,7 @@ await connection.waitUntilReady()
|
|
|
8
8
|
|
|
9
9
|
const hash = data => createHash('sha512').update(data).digest('base64')
|
|
10
10
|
|
|
11
|
-
const PAYLOAD_SIZE = 1024 * 1024 *
|
|
11
|
+
const PAYLOAD_SIZE = 1024 * 1024 * 10
|
|
12
12
|
const TEMP_FILE = '/tmp/geonix.stream_test'
|
|
13
13
|
|
|
14
14
|
console.time('test')
|
package/test/stream2.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
import { randomBytes } from 'node:crypto'
|
|
3
|
+
import { Stream, Remote, getReadable, connection, Service, streamToBuffer } from 'geonix'
|
|
4
|
+
import { createWriteStream, readFileSync } from 'node:fs'
|
|
5
|
+
import { createHash } from 'node:crypto'
|
|
6
|
+
import { pipeline } from 'node:stream/promises'
|
|
7
|
+
|
|
8
|
+
const hash = data => createHash('sha256').update(data).digest('base64')
|
|
9
|
+
const self = Remote('StreamTest')
|
|
10
|
+
|
|
11
|
+
class StreamTest extends Service {
|
|
12
|
+
|
|
13
|
+
async onStart() {
|
|
14
|
+
const perform = async (n) => {
|
|
15
|
+
const fileName = `${n}.random`
|
|
16
|
+
const { checksum, stream } = await self.readFile(fileName)
|
|
17
|
+
const data = await streamToBuffer(stream)
|
|
18
|
+
const verification = hash(data)
|
|
19
|
+
|
|
20
|
+
console.log(`${fileName} - ${data.length} bytes - ${checksum === verification}`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const jobs = []
|
|
24
|
+
for (let n = 0; n < 1024; n++)
|
|
25
|
+
jobs.push(perform(n))
|
|
26
|
+
|
|
27
|
+
await Promise.all(jobs)
|
|
28
|
+
|
|
29
|
+
console.log('done')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async readFile(fileName, size = 1024 * Math.round(Math.random() * 1024)) {
|
|
33
|
+
const bytes = randomBytes(size)
|
|
34
|
+
const checksum = hash(bytes)
|
|
35
|
+
|
|
36
|
+
return { checksum, stream: Stream(bytes) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
StreamTest.start()
|
package/src/Serialization.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export function serialize(input) {
|
|
2
|
-
const process = (value) => {
|
|
3
|
-
if (value instanceof Buffer) {
|
|
4
|
-
console.log('this is buffer')
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
if (typeof value === 'object')
|
|
8
|
-
for (let prop in value)
|
|
9
|
-
serialize()
|
|
10
|
-
|
|
11
|
-
return value
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let state = input
|
|
15
|
-
|
|
16
|
-
process(state)
|
|
17
|
-
|
|
18
|
-
return JSON.stringify(state)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function deserialize(input) {
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const input = {
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const s = serialize(input)
|
|
30
|
-
const ds = deserialize(s)
|
|
31
|
-
|
|
32
|
-
console.log(' serialized =', s)
|
|
33
|
-
console.log('deserialized =', ds)
|