geonix 1.20.0 → 1.20.2

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/Service.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { codec, connection } from "./Connection.js";
2
- import { picoid, sleep, hash, getSecondsSinceMidnight, OverlayObject, GeonixVersion, getFirstItemFromAsyncIterable } from "./Util.js";
2
+ import { picoid, sleep, hash, getSecondsSinceMidnight, OverlayObject, GeonixVersion, getFirstItemFromAsyncIterable, getNetworkAddresses } from "./Util.js";
3
3
  import { webserver } from "./WebServer.js";
4
4
  import { createConnection } from "net";
5
5
  import { EOL } from "os";
6
6
  import cookieParser from "cookie-parser";
7
7
  import express from "express";
8
8
  import { isStream, streamToString } from "./Stream.js";
9
+ import { logger } from "./Logger.js";
9
10
 
10
11
  const protectedMethodNames = ["constructor", "onStart"];
11
12
  const endpointMatcher = /^((?<options>.+)\|)?(?<verb>WS|SUB|GET|POST|PATCH|PUT|DELETE|HEAD|OPTIONS|ALL)\s(?<url>.*)/;
@@ -15,14 +16,33 @@ const ERROR_END_DELIMITER = "-".repeat(40);
15
16
 
16
17
  const json = express.json({ limit: "100mb" });
17
18
  const raw = express.raw({ type: "*/*", limit: "100mb" });
19
+ const cookies = cookieParser();
20
+
21
+ /**
22
+ * @typedef {Object} ServiceOptions
23
+ * @property {Object} middleware
24
+ * @property {boolean} middleware.json Enable JSON middleware
25
+ * @property {boolean} middleware.raw Enable RAW middleware
26
+ * @property {boolean} middleware.cookies Enable cookies middleware
27
+ * @property {boolean} fullBeacon Enable full beacon
28
+ */
29
+ const defaultServiceOptions = {
30
+ middleware: {
31
+ json: true,
32
+ raw: true,
33
+ cookies: true
34
+ },
35
+ fullBeacon: true
36
+ };
18
37
 
19
38
  export class Service {
20
39
 
21
40
  static serviceClasses = [];
22
41
 
23
42
  static start(options = {}) {
24
- if (!this.serviceClasses.includes(this.prototype.constructor.name))
43
+ if (!this.serviceClasses.includes(this.prototype.constructor.name)) {
25
44
  this.serviceClasses.push(this.prototype.constructor.name);
45
+ }
26
46
 
27
47
  const instance = new this();
28
48
  instance.#start(options);
@@ -31,21 +51,28 @@ export class Service {
31
51
  // ---------------------------------------------------------------------------------------------
32
52
 
33
53
  #me = {};
34
- #options = {};
54
+ #options = defaultServiceOptions;
35
55
 
36
56
  async #start(options = {}) {
37
- this.#options = options;
57
+ this.#options = { ...this.#options, ...options };
38
58
 
39
59
  await webserver.waitUntilReady();
40
60
  await connection.waitUntilReady();
41
61
 
42
- const fields = Object.getOwnPropertyNames(this).filter(isEndpointFilter).concat(Object.getOwnPropertyNames(this.constructor.prototype));
62
+ const fields = Object.getOwnPropertyNames(this)
63
+ .filter(isEndpointFilter)
64
+ .concat(Object.getOwnPropertyNames(this.constructor.prototype));
43
65
 
44
66
  // preserve order of endpoints as defined in the source
45
67
  const serviceSource = this.constructor.toString().split("\n");
46
68
  fields.sort((a, b, ia = -1, ib = -1) => {
47
- for (let line = 0; line < serviceSource.length; line++) ia = serviceSource[line].includes(a) ? line : ia;
48
- for (let line = 0; line < serviceSource.length; line++) ib = serviceSource[line].includes(b) ? line : ib;
69
+ for (let line = 0; line < serviceSource.length; line++) {
70
+ ia = serviceSource[line].includes(a) ? line : ia;
71
+ }
72
+
73
+ for (let line = 0; line < serviceSource.length; line++) {
74
+ ib = serviceSource[line].includes(b) ? line : ib;
75
+ }
49
76
  return ia - ib;
50
77
  });
51
78
 
@@ -65,7 +92,7 @@ export class Service {
65
92
  // geonix version
66
93
  gx: GeonixVersion,
67
94
  // IP addresses
68
- a: webserver.getAddresses().map(address => `${address}:${webserver.getPort()}`)
95
+ a: getNetworkAddresses().map(address => `${address}:${webserver.getPort()}`)
69
96
  };
70
97
 
71
98
  // check if method takes context as first argument
@@ -79,7 +106,7 @@ export class Service {
79
106
  this.#directListener();
80
107
  this.#webserver();
81
108
 
82
- console.log("gx.service.start", this.#me.n, this.#me.v);
109
+ logger.info("gx.service.start", this.#me.n, this.#me.v);
83
110
 
84
111
  // execute onStart method, if present
85
112
  if (this.onStart) {
@@ -93,7 +120,11 @@ export class Service {
93
120
  */
94
121
  async #beacon() {
95
122
  while (true) {
96
- connection.publish("gx2.beacon", { i: this.#me.i });
123
+ if (this.#options.fullBeacon) {
124
+ connection.publish("gx2.beacon", this.#me);
125
+ } else {
126
+ connection.publish("gx2.beacon", { i: this.#me.i });
127
+ }
97
128
  await sleep(1000);
98
129
  }
99
130
  }
@@ -108,11 +139,9 @@ export class Service {
108
139
  for await (let event of subscription) {
109
140
  let call = codec.decode(event.data);
110
141
 
111
- if (isStream(call))
112
- call = JSON.parse(await streamToString(call));
142
+ if (isStream(call)) { call = JSON.parse(await streamToString(call)); }
113
143
 
114
- if (call.$r && call.p)
115
- this.#onCall(call.p, (json) => connection.publish(call.$r, json));
144
+ if (call.$r && call.p) { this.#onCall(call.p, (json) => connection.publish(call.$r, json)); }
116
145
  }
117
146
  }
118
147
 
@@ -126,11 +155,13 @@ export class Service {
126
155
  for await (let event of subscription) {
127
156
  let call = codec.decode(event.data);
128
157
 
129
- if (isStream(call))
158
+ if (isStream(call)) {
130
159
  call = JSON.parse(await streamToString(call));
160
+ }
131
161
 
132
- if (call.$r && call.p)
162
+ if (call.$r && call.p) {
133
163
  this.#onCall(call.p, (json) => connection.publish(call.$r, json));
164
+ }
134
165
  }
135
166
  }
136
167
 
@@ -142,11 +173,24 @@ export class Service {
142
173
  const endpoints = this.#me.m
143
174
  .filter(isEndpointFilter);
144
175
 
145
- if (!endpoints || endpoints.length === 0)
176
+ if (!endpoints || endpoints.length === 0) {
146
177
  return;
178
+ }
147
179
 
148
180
  const router = webserver.router();
149
- router.use(json, raw, cookieParser());
181
+
182
+ // setup defualt middlewares
183
+ if (this.#options.middleware.json) {
184
+ router.use(json);
185
+ }
186
+ if (this.#options.middleware.raw) {
187
+ router.use(raw);
188
+ }
189
+ if (this.#options.middleware.cookies) {
190
+ router.use(cookies);
191
+ }
192
+
193
+ // register endpoints
150
194
  for (let endpoint of endpoints) {
151
195
  let { verb, url: uri } = endpointMatcher.exec(endpoint)?.groups || {};
152
196
  verb = verb.toLowerCase();
@@ -158,8 +202,9 @@ export class Service {
158
202
 
159
203
  handlers = [...handlersBefore, ...handlers, ...handlersAfter];
160
204
 
161
- for (let n = 0; n < handlers.length; n++)
205
+ for (let n = 0; n < handlers.length; n++) {
162
206
  handlers[n] = handlers[n].bind(this);
207
+ }
163
208
 
164
209
  switch (verb) {
165
210
  case "ws":
@@ -180,8 +225,9 @@ export class Service {
180
225
  async #sub(subject, handler) {
181
226
  const subscription = await connection.subscribe(`gx.sub.${subject}`);
182
227
  const processor = async () => {
183
- for await (const event of subscription)
228
+ for await (const event of subscription) {
184
229
  handler(event.data);
230
+ }
185
231
  };
186
232
  processor();
187
233
  }
@@ -198,13 +244,15 @@ export class Service {
198
244
  const method = this[methodName];
199
245
  let _args = args;
200
246
 
201
- if (!method)
247
+ if (!method) {
202
248
  return respond({ e: `unknown method (${this.#me.n}.${methodName})` });
249
+ }
203
250
 
204
251
  try {
205
252
  // inject context as first argument
206
- if (method.takesContext)
253
+ if (method.takesContext) {
207
254
  _args = [OverlayObject(context, { caller, me: this.#me }), ..._args];
255
+ }
208
256
 
209
257
  respond({ r: await method.apply(this, _args) });
210
258
  } catch (e) {
package/src/Stream.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import { Readable } from "stream";
2
2
  import { connection } from "./Connection.js";
3
- import { picoid, StreamChunker } from "./Util.js";
3
+ import { getFirstItemFromAsyncIterable, getNetworkAddresses, picoid, StreamChunker } from "./Util.js";
4
+ import { logger } from "./Logger.js";
5
+ import { webserver } from "./WebServer.js";
4
6
 
5
7
  const CHUNK_SIZE = 1024 * 128;
6
8
 
7
9
  export const stats = {};
10
+ export const activeStreams = {};
8
11
 
9
12
  /**
10
13
  * Converts data to stream
@@ -14,15 +17,17 @@ export const stats = {};
14
17
  * @returns
15
18
  */
16
19
  export function Stream(data, tag = "_") {
17
- if (isStream(data))
20
+ if (isStream(data)) {
18
21
  return data;
22
+ }
19
23
 
20
24
  const id = picoid();
21
25
  let readable = data;
22
26
 
23
27
  // convert Buffer or string to a Readable
24
- if (!(readable.pipe && readable.readable))
28
+ if (!(readable.pipe && readable.readable)) {
25
29
  readable = Readable.from(Buffer.from(data));
30
+ }
26
31
 
27
32
  // split the stream is smaller chunks
28
33
  const transform = StreamChunker(Math.min(connection.getMaxPayloadSize(), CHUNK_SIZE));
@@ -30,23 +35,38 @@ export function Stream(data, tag = "_") {
30
35
  readable = transform;
31
36
 
32
37
  stats[tag] = stats[tag] !== undefined ? stats[tag] + 1 : 1;
38
+ activeStreams[id] = readable;
33
39
 
34
- const controlHandler = async () => {
40
+ // NATS handler
41
+ (async () => {
35
42
  const control = await connection.subscribe(`gx2.stream.${id}.a`, { max: 1 });
36
43
 
37
- for await (const event of control)
38
- if (event.data.length === 0) {
39
- readable.on("data", chunk => connection.publishRaw(`gx2.stream.${id}.b`, chunk));
40
- readable.on("close", () => {
41
- connection.publishRaw(`gx2.stream.${id}.b`);
42
- stats[tag]--;
43
- });
44
- }
44
+ const event = await getFirstItemFromAsyncIterable(control);
45
+ if (activeStreams[id] !== undefined && event.data.length === 0) {
46
+ // remove stream from the list
47
+ delete activeStreams[id];
48
+
49
+ // kickstart the stream
50
+ readable.on("data", chunk => connection.publishRaw(`gx2.stream.${id}.b`, chunk));
51
+ readable.on("close", () => {
52
+ connection.publishRaw(`gx2.stream.${id}.b`);
53
+ stats[tag]--;
54
+ });
55
+ }
56
+ })();
57
+
58
+ const result = {
59
+ $: "stream",
60
+ id
45
61
  };
46
62
 
47
- controlHandler();
63
+ // get the port and addresses of the webserver
64
+ const addresses = webserver.getPort() ? getNetworkAddresses().map(address => `${address}:${webserver.getPort()}`) : undefined;
65
+ if (addresses) {
66
+ result.a = addresses;
67
+ }
48
68
 
49
- return { $: "stream", id };
69
+ return result;
50
70
  }
51
71
 
52
72
  export function isStream(object) {
@@ -54,23 +74,43 @@ export function isStream(object) {
54
74
  }
55
75
 
56
76
  export async function getReadable(object) {
57
- if (!isStream(object))
77
+ if (!isStream(object)) {
58
78
  return object;
79
+ }
80
+
81
+ // get stream via HTTP
82
+ if (object.a.length > 0) {
83
+ for (const address of object.a) {
84
+ try {
85
+ const uri = `http://${address}/!!_____stream/${object.id}`;
86
+ const response = await fetch(uri);
87
+
88
+ if (response.status === 200) {
89
+ return Readable.fromWeb(response.body);
90
+ }
91
+ } catch {
92
+ // ignore errors
93
+ }
94
+ }
95
+ }
59
96
 
97
+ // get stream via NATS
60
98
  const readable = new Readable({ read: () => null });
61
99
  const subscription = await connection.subscribe(`gx2.stream.${object.id}.b`);
62
100
 
63
101
  const dataHandler = async () => {
64
- for await (const event of subscription)
102
+ for await (const event of subscription) {
65
103
  try {
66
104
  if (event.data.length === 0) {
67
105
  readable.push(null);
68
106
  subscription.drain();
69
- } else
107
+ } else {
70
108
  readable.push(event.data);
109
+ }
71
110
  } catch (e) {
72
- console.error("Stream.getReadable.dataHandler.error:", e);
111
+ logger.error("Stream.getReadable.dataHandler.error:", e);
73
112
  }
113
+ }
74
114
  };
75
115
  dataHandler();
76
116
 
@@ -82,17 +122,18 @@ export async function getReadable(object) {
82
122
 
83
123
  export async function streamToBuffer(object) {
84
124
  let readable = object;
85
- if (isStream(readable))
125
+ if (isStream(readable)) {
86
126
  readable = await getReadable(readable);
127
+ }
87
128
 
88
129
  return Buffer.concat(await readable.toArray());
89
130
  }
90
131
 
91
132
  export async function streamToString(object) {
92
133
  let readable = object;
93
- if (isStream(readable))
134
+ if (isStream(readable)) {
94
135
  readable = await getReadable(readable);
136
+ }
95
137
 
96
138
  return Buffer.concat(await readable.toArray()).toString();
97
- }
98
-
139
+ }
package/src/Util.js CHANGED
@@ -3,6 +3,7 @@ import { URL, fileURLToPath } from "url";
3
3
  import { readFile } from "fs/promises";
4
4
  import { join } from "path";
5
5
  import { Transform } from "node:stream";
6
+ import { networkInterfaces } from "os";
6
7
  import * as http from "http";
7
8
  import * as https from "https";
8
9
  import * as net from "net";
@@ -60,7 +61,6 @@ export const createServerAtPort = (port, pkg, handler) =>
60
61
  new Promise((resolve) => {
61
62
  const server = pkg.createServer(handler);
62
63
  server.on("error", (_error) => {
63
- // console.log('error', error.message)
64
64
  resolve(null);
65
65
  });
66
66
  server.listen(port, () => {
@@ -78,14 +78,16 @@ export const createServerAtPort = (port, pkg, handler) =>
78
78
  * @returns
79
79
  */
80
80
  export const createServerAtFreePort = async (pkg, handler, start = 30000, poolSize = 20000) => {
81
- for (let port = start; port < start + poolSize; port++)
81
+ for (let port = start; port < start + poolSize; port++) {
82
82
  try {
83
83
  const result = await createServerAtPort(port, pkg, handler);
84
- // console.log(port, '=', result)
85
- if (result) return result;
84
+ if (result) {
85
+ return result;
86
+ }
86
87
  } catch {
87
88
  // silenty ignore errors
88
89
  }
90
+ }
89
91
  };
90
92
 
91
93
  /**
@@ -121,10 +123,11 @@ export const getFunctionParams = (fn) => {
121
123
  const endParenthesisPosition = code.indexOf(")");
122
124
  let params;
123
125
 
124
- if (endParenthesisPosition != -1)
126
+ if (endParenthesisPosition != -1) {
125
127
  params = code.substring(code.indexOf("(") + 1, endParenthesisPosition);
126
- else
128
+ } else {
127
129
  params = code.substring(0, code.indexOf("=>"));
130
+ }
128
131
 
129
132
  params = params
130
133
  // cleanup spaces
@@ -135,8 +138,9 @@ export const getFunctionParams = (fn) => {
135
138
  // remove potential default values
136
139
  for (let index = 0; index < params.length; index++) {
137
140
  const defaultValueAssignmentPosition = params[index].indexOf("=");
138
- if (defaultValueAssignmentPosition != -1)
141
+ if (defaultValueAssignmentPosition != -1) {
139
142
  params[index] = params[index].substring(0, defaultValueAssignmentPosition - 1);
143
+ }
140
144
  }
141
145
 
142
146
  return params;
@@ -153,8 +157,10 @@ export const proxyHttp = (target, req, res) =>
153
157
  const protocol = req.protocol === "https" ? https : http;
154
158
  const proxyReq = protocol.request(remoteTarget, options, (proxyRes) => {
155
159
  res.status(proxyRes.statusCode);
156
- for (const header in proxyRes.headers)
160
+ for (const header in proxyRes.headers) {
157
161
  res.set(header, proxyRes.headers[header]);
162
+ }
163
+
158
164
  proxyRes.pipe(res);
159
165
  });
160
166
  proxyReq.on("error", (error) => reject(error));
@@ -207,4 +213,19 @@ export async function getFirstItemFromAsyncIterable(asyncIterable) {
207
213
  const iterator = asyncIterable[Symbol.asyncIterator]();
208
214
  const result = await iterator.next();
209
215
  return result.value;
216
+ }
217
+
218
+ export function getNetworkAddresses() {
219
+ const list = [];
220
+ const interfaces = networkInterfaces();
221
+
222
+ for (let interfaceAddresses of Object.values(interfaces)) {
223
+ for (let addressObject of interfaceAddresses) {
224
+ if (addressObject.family === "IPv4") {
225
+ list.push(addressObject.address);
226
+ }
227
+ }
228
+ }
229
+
230
+ return list;
210
231
  }
package/src/WebServer.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import "express-async-errors";
2
2
  import express, { Router } from "express";
3
3
  import expressWs from "express-ws";
4
- import { networkInterfaces } from "os";
5
4
  import { createServerAtFreePort, createServerAtPort, sleep } from "./Util.js";
6
5
  import * as http from "http";
7
6
  import { Service } from "./Service.js";
8
7
  import * as path from "path";
8
+ import { logger } from "./Logger.js";
9
+ import { activeStreams } from "./Stream.js";
9
10
 
10
11
  export const HEALTH_CHECK_ENDPOINT = "/pA4vY7fT9oG5aI8cA4yV3qW5fP9qR1vI";
11
12
 
@@ -16,12 +17,14 @@ export const ServeStatic = (root, options = {}) => {
16
17
  router.use((req, res, next) => {
17
18
  if (options.root) {
18
19
  // remove trailing slash
19
- if (options.root.endsWith("/"))
20
+ if (options.root.endsWith("/")) {
20
21
  options.root = options.root.slice(0, -1);
22
+ }
21
23
 
22
24
  // replace root prefix
23
- if (req.url.startsWith(options.root))
25
+ if (req.url.startsWith(options.root)) {
24
26
  req.url = req.url.replace(options.root, "");
27
+ }
25
28
  }
26
29
 
27
30
  next();
@@ -29,11 +32,12 @@ export const ServeStatic = (root, options = {}) => {
29
32
 
30
33
  router.use(express.static(root, options));
31
34
 
32
- if (options.indexOn404)
35
+ if (options.indexOn404) {
33
36
  router.get("*", (req, res) => {
34
- console.log(path.join(absoluteRoot, "index.html"));
37
+ logger.info(path.join(absoluteRoot, "index.html"));
35
38
  res.sendFile(path.join(absoluteRoot, "index.html"));
36
39
  });
40
+ }
37
41
 
38
42
  return router;
39
43
  };
@@ -47,31 +51,43 @@ class WebServer {
47
51
  #started = false;
48
52
 
49
53
  async start() {
50
- if (this.#started)
51
- return;
54
+ if (this.#started) { return; }
52
55
 
53
56
  this.#started = true;
54
57
 
55
- let port, server;
58
+ let srv;
56
59
  if (process.env.LOCAL_PORT) {
57
- ({ server, port } = await createServerAtPort(process.env.LOCAL_PORT, http, this.#app));
60
+ srv = await createServerAtPort(process.env.LOCAL_PORT, http, this.#app);
58
61
  } else {
59
- ({ server, port } = await createServerAtFreePort(http, this.#app));
62
+ srv = await createServerAtFreePort(http, this.#app);
63
+ }
64
+
65
+ if (!srv) {
66
+ throw new Error("gx.webserver.start: unable to start");
60
67
  }
61
68
 
62
- this.#server = server;
63
- this.#port = port;
69
+ this.#server = srv.server;
70
+ this.#port = srv.port;
64
71
 
65
- expressWs(this.#app, server);
72
+ expressWs(this.#app, srv.server);
73
+
74
+ // stream endpoint
75
+ this.#app.get("/!!_____stream/:id", (req, res) => {
76
+ const id = req.params.id;
77
+
78
+ if (activeStreams[id]) {
79
+ res.status(200);
80
+ activeStreams[id].pipe(res);
81
+ delete activeStreams[id];
82
+ } else {
83
+ res.status(404).send({ error: 404 });
84
+ }
85
+ });
66
86
 
67
87
  this.#app.get(HEALTH_CHECK_ENDPOINT, (req, res) => {
68
88
  res.send({ status: "healthy", services: Service.serviceClasses });
69
89
  });
70
90
 
71
- // this.#app.use((req, res, next) => {
72
- // next()
73
- // })
74
-
75
91
  // wait for 2 seconds and then set fall-through handler
76
92
  // this should provide more than enough time to start all the services
77
93
  setTimeout(() => {
@@ -88,23 +104,11 @@ class WebServer {
88
104
  this.#app.disable("x-powered-by");
89
105
  this.#app.disable("etag");
90
106
 
91
- console.log(`gx.webserver.start: listening on http://127.0.0.1:${this.#port}`);
107
+ logger.info(`gx.webserver.start: listening on http://127.0.0.1:${this.#port}`);
92
108
 
93
109
  this.#ready = true;
94
110
  }
95
111
 
96
- getAddresses() {
97
- const list = [];
98
- const interfaces = networkInterfaces();
99
-
100
- for (let interfaceAddresses of Object.values(interfaces))
101
- for (let addressObject of interfaceAddresses)
102
- if (addressObject.family === "IPv4")
103
- list.push(addressObject.address);
104
-
105
- return list;
106
- }
107
-
108
112
  getPort() {
109
113
  return this.#port;
110
114
  }
@@ -118,14 +122,15 @@ class WebServer {
118
122
  async waitUntilReady() {
119
123
  await this.start();
120
124
 
121
- while (!this.#ready)
125
+ while (!this.#ready) {
122
126
  await sleep(100);
127
+ }
123
128
  }
124
129
 
125
130
  stop() {
126
131
  if (this.#server) {
127
132
  this.#server.close();
128
- console.log("gx.webserver.stop");
133
+ logger.info("gx.webserver.stop");
129
134
  }
130
135
  }
131
136
 
package/test/gateway.js CHANGED
@@ -2,14 +2,14 @@ import { Gateway, Service } from "../exports.js";
2
2
 
3
3
  class TestService extends Service {
4
4
 
5
- 'GET /'(req, res) {
6
- res.send('Hello World')
5
+ "GET /"(req, res) {
6
+ res.send("Hello World");
7
7
  }
8
8
  }
9
9
 
10
- TestService.start()
10
+ TestService.start();
11
11
  Gateway.start({
12
12
  beforeRequest: (req, res) => {
13
- res.set('X-Test', 'Test')
13
+ res.set("X-Test", "Test");
14
14
  }
15
- })
15
+ });
package/test/stream.js CHANGED
@@ -1,38 +1,43 @@
1
- import { randomBytes } from 'node:crypto'
2
- import { Stream, getReadable, connection } from 'geonix'
3
- import { createWriteStream, readFileSync } from 'node:fs'
4
- import { createHash } from 'node:crypto'
5
- import { pipeline } from 'node:stream/promises'
1
+ import { randomBytes } from "node:crypto";
2
+ import { Stream, getReadable, connection } from "geonix";
3
+ import { createWriteStream, readFileSync } from "node:fs";
4
+ import { createHash } from "node:crypto";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { webserver } from "../src/WebServer.js";
6
7
 
7
- await connection.waitUntilReady()
8
+ await connection.waitUntilReady();
8
9
 
9
- const hash = data => createHash('sha512').update(data).digest('base64')
10
+ const hash = data => createHash("sha512").update(data).digest("base64");
10
11
 
11
- const PAYLOAD_SIZE = 1024 * 1024 * 1024
12
- const TEMP_FILE = '/tmp/geonix.stream_test'
12
+ const PAYLOAD_SIZE = 1024 * 1024 * 1024;
13
+ const TEMP_FILE = "/tmp/geonix.stream_test";
13
14
 
14
- console.time('test')
15
+ await webserver.start();
16
+
17
+ console.time("test");
15
18
  try {
16
- const payload = randomBytes(PAYLOAD_SIZE)
17
- const sourceHash = hash(payload)
19
+ const payload = randomBytes(PAYLOAD_SIZE);
20
+ const sourceHash = hash(payload);
21
+
22
+ const stream = Stream(payload);
18
23
 
19
- const source = await getReadable(Stream(payload))
20
- const dest = createWriteStream(TEMP_FILE)
24
+ const source = await getReadable(stream);
25
+ const dest = createWriteStream(TEMP_FILE);
21
26
 
22
- await pipeline(source, dest)
27
+ await pipeline(source, dest);
23
28
 
24
- const check = readFileSync(TEMP_FILE)
25
- const destHash = hash(check)
29
+ const check = readFileSync(TEMP_FILE);
30
+ const destHash = hash(check);
26
31
 
27
32
  if (sourceHash == destHash) {
28
- console.log('MATCH')
33
+ console.log("MATCH");
29
34
  } else {
30
- console.error('Destination does not match the source!')
31
- console.log(payload)
32
- console.log(check)
35
+ console.error("Destination does not match the source!");
36
+ console.log("P =", payload);
37
+ console.log("C =", check);
33
38
  }
34
39
  } catch (e) {
35
- console.error(e)
40
+ console.error(e);
36
41
  } finally {
37
- console.timeEnd('test')
42
+ console.timeEnd("test");
38
43
  }