@synnaxlabs/client 0.17.1 → 0.17.3

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,41 @@
1
+ import { Synnax, TimeStamp } from "@synnaxlabs/client";
2
+
3
+ // This example demonstrates how to stream live data from a channel in Synnax.
4
+ // Live-streaming is useful for real-time data processing and analysis, and is an
5
+ // integral part of Synnax's control sequence and data streaming capabilities.
6
+
7
+ // This example is meant to be used in conjunction with the stream_write.py example, and
8
+ // assumes that example is running in a separate terminal.
9
+
10
+ // Connect to a locally running, insecure Synnax cluster. If your connection parameters
11
+ // are different, enter them here.
12
+ const client = new Synnax({
13
+ host: "localhost",
14
+ port: 9090,
15
+ username: "synnax",
16
+ password: "seldon",
17
+ secure: false
18
+ });
19
+
20
+ // We can just specify the names of the channels we'd like to stream from.
21
+ const read_from = ["stream_write_example_time", "stream_write_example_data"]
22
+
23
+ const streamer = await client.telem.newStreamer(read_from);
24
+
25
+ // It's very important that we close the streamer when we're done with it to release
26
+ // network connections and other resources, so we wrap the streaming loop in a try-finally
27
+ // block.
28
+ try {
29
+ // Loop through the frames in the streamer. Each iteration will block until a new
30
+ // frame is available, and then we'll just print it out.
31
+ for await (const frame of streamer)
32
+ console.log({
33
+ time: new TimeStamp(frame.get("stream_write_example_time")[0].at(0)).toString(),
34
+ data: frame.get("stream_write_example_data")[0].at(0)
35
+ })
36
+ } finally {
37
+ streamer.close();
38
+ // Close the client when we're done with it.
39
+ client.close();
40
+ }
41
+
@@ -9,7 +9,7 @@
9
9
  "version": "1.0.0",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
- "@synnaxlabs/client": "^0.17.0"
12
+ "@synnaxlabs/client": "^0.17.2"
13
13
  }
14
14
  },
15
15
  "node_modules/@grpc/grpc-js": {
@@ -3653,9 +3653,9 @@
3653
3653
  }
3654
3654
  },
3655
3655
  "node_modules/@synnaxlabs/client": {
3656
- "version": "0.17.0",
3657
- "resolved": "https://registry.npmjs.org/@synnaxlabs/client/-/client-0.17.0.tgz",
3658
- "integrity": "sha512-ydQpLQ0MUpkvJ/TqHidWNSRSdz6DoSctSbaCu/+TuDy74bIamDWBMQu5fmsTcA5NeQzzmFZgiOMRaFOa9fG1gg==",
3656
+ "version": "0.17.2",
3657
+ "resolved": "https://registry.npmjs.org/@synnaxlabs/client/-/client-0.17.2.tgz",
3658
+ "integrity": "sha512-9r8C7KbWBHluBRnu8qw34hf+u8JW1CkM6VmAT+51N+m0z2AZA0pbK01MNNIjLQAZ1bAdKpzc57BxqSzCwIceGQ==",
3659
3659
  "dependencies": {
3660
3660
  "@synnaxlabs/freighter": "0.9.1",
3661
3661
  "@synnaxlabs/x": "0.14.1",
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "ISC",
13
13
  "dependencies": {
14
- "@synnaxlabs/client": "^0.17.0"
14
+ "@synnaxlabs/client": "^0.17.2"
15
15
  }
16
16
  }
@@ -3,7 +3,7 @@
3
3
  // applications (such as data acquisition from a sensor) or for very large datasets that
4
4
  // cannot be written all at once.
5
5
 
6
- import { Synnax } from "@synnaxlabs/client";
6
+ import { Rate, Series, Synnax, TimeStamp, framer } from "@synnaxlabs/client";
7
7
 
8
8
  // Connect to a locally running, insecure Synnax cluster. If your connection parameters
9
9
  // are different, enter them here.
@@ -20,4 +20,59 @@ const timeChannel = await client.channels.create({
20
20
  name: "stream_write_example_time",
21
21
  isIndex: true,
22
22
  dataType: "timestamp"
23
- });
23
+ }, { retrieveIfNameExists: true });
24
+
25
+ // Create a data channel that will be used to store our fake sensor data.
26
+ const dataChannel = await client.channels.create({
27
+ name: "stream_write_example_data",
28
+ dataType: "float32",
29
+ index: timeChannel.key,
30
+ }, { retrieveIfNameExists: true });
31
+
32
+
33
+ // We'll start our write at the current time. This timestamps should be the same as or
34
+ // just before the first timestamp we write.
35
+ const start = TimeStamp.now();
36
+
37
+ // Set a rough rate of 20 Hz. This won't be exact because we're sleeping for a fixed
38
+ // amount of time, but it's close enough for demonstration purposes.
39
+ const roughRate = Rate.hz(40);
40
+
41
+ // Make the writer commit every 500 samples. This will make the data available for
42
+ // historical reads every 500 samples.
43
+ const commitInterval = 500;
44
+
45
+ const writer = await client.telem.newWriter({
46
+ start,
47
+ channels: [timeChannel.key, dataChannel.key]
48
+ });
49
+
50
+ try {
51
+ let i = 0;
52
+ while (true) {
53
+ await new Promise(resolve => setTimeout(resolve, roughRate.period.milliseconds));
54
+ i++;
55
+ const timestamp = TimeStamp.now();
56
+ const data = Math.sin(i / 10);
57
+ const fr = new framer.Frame({
58
+ [timeChannel.key]: new Series({ data: new timeChannel.dataType.Array([timestamp]) }),
59
+ [dataChannel.key]: new Series({ data: new dataChannel.dataType.Array([data]) })
60
+ });
61
+ await writer.write(fr);
62
+
63
+ if (i % 60 == 0)
64
+ console.log(`Writing sample ${i} at ${timestamp.toISOString()}`)
65
+
66
+ if (i % commitInterval == 0) {
67
+ // Commit the writer. This method will return false if the commit fails i.e.
68
+ // we've mad an invalid write or someone has already written to this region.
69
+ if (!await writer.commit()) {
70
+ console.error("Failed to commit data");
71
+ break;
72
+ };
73
+ }
74
+ }
75
+ } finally {
76
+ await writer.close();
77
+ }
78
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synnaxlabs/client",
3
3
  "private": false,
4
- "version": "0.17.1",
4
+ "version": "0.17.3",
5
5
  "type": "module",
6
6
  "description": "The Client Library for Synnax",
7
7
  "repository": "https://github.com/synnaxlabs/synnax/tree/main/client/ts",
@@ -18,8 +18,8 @@
18
18
  "dependencies": {
19
19
  "async-mutex": "^0.4.0",
20
20
  "zod": "3.22.4",
21
- "@synnaxlabs/x": "0.14.1",
22
- "@synnaxlabs/freighter": "0.9.1"
21
+ "@synnaxlabs/freighter": "0.9.1",
22
+ "@synnaxlabs/x": "0.14.1"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^20.10.5",
@@ -27,8 +27,8 @@
27
27
  "typescript": "^5.3.3",
28
28
  "vite": "^5.1.2",
29
29
  "vitest": "^1.2.2",
30
- "@synnaxlabs/vite-plugin": "0.0.1",
31
30
  "@synnaxlabs/tsconfig": "0.0.2",
31
+ "@synnaxlabs/vite-plugin": "0.0.1",
32
32
  "eslint-config-synnaxlabs": "0.0.1"
33
33
  },
34
34
  "main": "dist/client.cjs",
@@ -110,7 +110,11 @@ export class Frame {
110
110
  validateMatchedColsAndArrays(data_.keys, arrays);
111
111
  data_.keys.forEach((key, i) => this.push(key, arrays[i]));
112
112
  } else
113
- Object.entries(columnsOrData).forEach(([k, v]) => this.push(k, ...toArray(v)));
113
+ Object.entries(columnsOrData).forEach(([k, v]) => {
114
+ const key = parseInt(k);
115
+ if (!isNaN(key)) return this.push(key, ...toArray(v));
116
+ else this.push(k, ...toArray(v))
117
+ });
114
118
  return;
115
119
  }
116
120