@synnaxlabs/client 0.17.0 → 0.17.1
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/.turbo/turbo-build.log +5 -5
- package/dist/channel/client.d.ts +6 -2
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +8 -3
- package/dist/client.js.map +1 -1
- package/examples/node/basicReadWrite.js +67 -0
- package/examples/node/package-lock.json +69 -57
- package/examples/node/package.json +1 -1
- package/examples/node/streamWrite.js +23 -0
- package/package.json +5 -5
- package/src/channel/channel.spec.ts +68 -2
- package/src/channel/client.ts +18 -6
- package/examples/node/basicReadWriter.js +0 -66
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DataType, Synnax, TimeRange, TimeSpan, TimeStamp } from "@synnaxlabs/client";
|
|
2
|
+
|
|
3
|
+
// This example demonstrates the basics of reading and writing data from an index and data
|
|
4
|
+
// channel in Synnax. We'll write a sine wave of data to a channel and then read it back.
|
|
5
|
+
|
|
6
|
+
// Connect to a locally running, insecure Synnax cluster. If your connection parameters
|
|
7
|
+
// are different, enter them here.
|
|
8
|
+
const client = new Synnax({
|
|
9
|
+
host: "localhost",
|
|
10
|
+
port: 9090,
|
|
11
|
+
username: "synnax",
|
|
12
|
+
password: "seldon",
|
|
13
|
+
secure: false
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Create an index channel that will be used to store our timestamps.
|
|
17
|
+
const timeChannel = await client.channels.create({
|
|
18
|
+
name: "basic_read_write_time",
|
|
19
|
+
isIndex: true,
|
|
20
|
+
dataType: DataType.TIMESTAMP
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Create a channel that will be used to store our data.
|
|
24
|
+
const indexChannel = await client.channels.create({
|
|
25
|
+
name: "basic_read_write_data",
|
|
26
|
+
isIndex: false,
|
|
27
|
+
dataType: DataType.FLOAT32,
|
|
28
|
+
// We need to specify the index channel that we want to use to store the timestamps
|
|
29
|
+
// for this data channel.
|
|
30
|
+
index: timeChannel.key,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const N_SAMPLES = 5000;
|
|
34
|
+
|
|
35
|
+
// We'll start our write at the current time. This timestamp should be the same as or
|
|
36
|
+
// just before the first timestamp we write.
|
|
37
|
+
const start = TimeStamp.now();
|
|
38
|
+
|
|
39
|
+
// Generate a new timestamp every millisecond for N_SAMPLES.
|
|
40
|
+
const time = BigInt64Array.from({ length: N_SAMPLES }, (_, i) => start.add(TimeSpan.milliseconds(i)).valueOf());
|
|
41
|
+
// Generate a sine wave for N_SAMPLES.
|
|
42
|
+
const data = Float32Array.from({ length: N_SAMPLES }, (_, i) => Math.sin(i / 100));
|
|
43
|
+
|
|
44
|
+
// Write the data to the channel. Note that we need to write the timestamps first,
|
|
45
|
+
// otherwise writing the data will fail. Notice how we align the writes with the 'start'
|
|
46
|
+
// timestamp.
|
|
47
|
+
await timeChannel.write(start, time);
|
|
48
|
+
await indexChannel.write(start, data);
|
|
49
|
+
|
|
50
|
+
// Define the time range to read the data back from
|
|
51
|
+
const tr = new TimeRange(start, start.add(TimeSpan.milliseconds(N_SAMPLES)));
|
|
52
|
+
|
|
53
|
+
// Read the data back. The order doesn't matter here.
|
|
54
|
+
const readTime = await timeChannel.read(tr);
|
|
55
|
+
const readData = await indexChannel.read(tr);
|
|
56
|
+
|
|
57
|
+
// Print out some information.
|
|
58
|
+
console.log({
|
|
59
|
+
firstTimestamp: readTime.at(0),
|
|
60
|
+
firstData: readData.at(0),
|
|
61
|
+
lastTimestamp: readTime.at(N_SAMPLES - 1),
|
|
62
|
+
lastData: readData.at(N_SAMPLES - 1),
|
|
63
|
+
returnLength: readData.length,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Make sure to close the client when you're done.
|
|
67
|
+
client.close();
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@synnaxlabs/client": "^0.
|
|
12
|
+
"@synnaxlabs/client": "^0.17.0"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"node_modules/@grpc/grpc-js": {
|
|
@@ -215,9 +215,9 @@
|
|
|
215
215
|
}
|
|
216
216
|
},
|
|
217
217
|
"node_modules/@opentelemetry/api-logs": {
|
|
218
|
-
"version": "0.
|
|
219
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.
|
|
220
|
-
"integrity": "sha512-
|
|
218
|
+
"version": "0.50.0",
|
|
219
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.50.0.tgz",
|
|
220
|
+
"integrity": "sha512-JdZuKrhOYggqOpUljAq4WWNi5nB10PmgoF0y2CvedLGXd0kSawb/UBnWT8gg1ND3bHCNHStAIVT0ELlxJJRqrA==",
|
|
221
221
|
"peer": true,
|
|
222
222
|
"dependencies": {
|
|
223
223
|
"@opentelemetry/api": "^1.0.0"
|
|
@@ -643,11 +643,11 @@
|
|
|
643
643
|
}
|
|
644
644
|
},
|
|
645
645
|
"node_modules/@opentelemetry/context-zone": {
|
|
646
|
-
"version": "1.
|
|
647
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/context-zone/-/context-zone-1.
|
|
648
|
-
"integrity": "sha512-
|
|
646
|
+
"version": "1.23.0",
|
|
647
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/context-zone/-/context-zone-1.23.0.tgz",
|
|
648
|
+
"integrity": "sha512-7piNTrpH+gZNMDDOHIJXCSwp0Xslh3R96HWH5HwXw+4PykR4+jVoXvd6jziQxudX9rFAfu2B64A10DHs4ZWrfA==",
|
|
649
649
|
"dependencies": {
|
|
650
|
-
"@opentelemetry/context-zone-peer-dep": "1.
|
|
650
|
+
"@opentelemetry/context-zone-peer-dep": "1.23.0",
|
|
651
651
|
"zone.js": "^0.11.0 || ^0.13.0 || ^0.14.0"
|
|
652
652
|
},
|
|
653
653
|
"engines": {
|
|
@@ -655,9 +655,9 @@
|
|
|
655
655
|
}
|
|
656
656
|
},
|
|
657
657
|
"node_modules/@opentelemetry/context-zone-peer-dep": {
|
|
658
|
-
"version": "1.
|
|
659
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/context-zone-peer-dep/-/context-zone-peer-dep-1.
|
|
660
|
-
"integrity": "sha512-
|
|
658
|
+
"version": "1.23.0",
|
|
659
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/context-zone-peer-dep/-/context-zone-peer-dep-1.23.0.tgz",
|
|
660
|
+
"integrity": "sha512-3ia5w2y3CGHIhMSggttliGbeRBWclIyMMXdfRCcit1NHg1ocieA9qYxyUEetbOvPrQpoti3O3k+5eyQUv7r8nw==",
|
|
661
661
|
"engines": {
|
|
662
662
|
"node": ">=14"
|
|
663
663
|
},
|
|
@@ -667,11 +667,11 @@
|
|
|
667
667
|
}
|
|
668
668
|
},
|
|
669
669
|
"node_modules/@opentelemetry/core": {
|
|
670
|
-
"version": "1.
|
|
671
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.
|
|
672
|
-
"integrity": "sha512-
|
|
670
|
+
"version": "1.23.0",
|
|
671
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.23.0.tgz",
|
|
672
|
+
"integrity": "sha512-hdQ/a9TMzMQF/BO8Cz1juA43/L5YGtCSiKoOHmrTEf7VMDAZgy8ucpWx3eQTnQ3gBloRcWtzvcrMZABC3PTSKQ==",
|
|
673
673
|
"dependencies": {
|
|
674
|
-
"@opentelemetry/semantic-conventions": "1.
|
|
674
|
+
"@opentelemetry/semantic-conventions": "1.23.0"
|
|
675
675
|
},
|
|
676
676
|
"engines": {
|
|
677
677
|
"node": ">=14"
|
|
@@ -3185,12 +3185,12 @@
|
|
|
3185
3185
|
}
|
|
3186
3186
|
},
|
|
3187
3187
|
"node_modules/@opentelemetry/resources": {
|
|
3188
|
-
"version": "1.
|
|
3189
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.
|
|
3190
|
-
"integrity": "sha512
|
|
3188
|
+
"version": "1.23.0",
|
|
3189
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.23.0.tgz",
|
|
3190
|
+
"integrity": "sha512-iPRLfVfcEQynYGo7e4Di+ti+YQTAY0h5mQEUJcHlU9JOqpb4x965O6PZ+wMcwYVY63G96KtdS86YCM1BF1vQZg==",
|
|
3191
3191
|
"dependencies": {
|
|
3192
|
-
"@opentelemetry/core": "1.
|
|
3193
|
-
"@opentelemetry/semantic-conventions": "1.
|
|
3192
|
+
"@opentelemetry/core": "1.23.0",
|
|
3193
|
+
"@opentelemetry/semantic-conventions": "1.23.0"
|
|
3194
3194
|
},
|
|
3195
3195
|
"engines": {
|
|
3196
3196
|
"node": ">=14"
|
|
@@ -3425,13 +3425,13 @@
|
|
|
3425
3425
|
}
|
|
3426
3426
|
},
|
|
3427
3427
|
"node_modules/@opentelemetry/sdk-trace-base": {
|
|
3428
|
-
"version": "1.
|
|
3429
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.
|
|
3430
|
-
"integrity": "sha512-
|
|
3428
|
+
"version": "1.23.0",
|
|
3429
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.23.0.tgz",
|
|
3430
|
+
"integrity": "sha512-PzBmZM8hBomUqvCddF/5Olyyviayka44O5nDWq673np3ctnvwMOvNrsUORZjKja1zJbwEuD9niAGbnVrz3jwRQ==",
|
|
3431
3431
|
"dependencies": {
|
|
3432
|
-
"@opentelemetry/core": "1.
|
|
3433
|
-
"@opentelemetry/resources": "1.
|
|
3434
|
-
"@opentelemetry/semantic-conventions": "1.
|
|
3432
|
+
"@opentelemetry/core": "1.23.0",
|
|
3433
|
+
"@opentelemetry/resources": "1.23.0",
|
|
3434
|
+
"@opentelemetry/semantic-conventions": "1.23.0"
|
|
3435
3435
|
},
|
|
3436
3436
|
"engines": {
|
|
3437
3437
|
"node": ">=14"
|
|
@@ -3513,13 +3513,13 @@
|
|
|
3513
3513
|
}
|
|
3514
3514
|
},
|
|
3515
3515
|
"node_modules/@opentelemetry/sdk-trace-web": {
|
|
3516
|
-
"version": "1.
|
|
3517
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-1.
|
|
3518
|
-
"integrity": "sha512-
|
|
3516
|
+
"version": "1.23.0",
|
|
3517
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-1.23.0.tgz",
|
|
3518
|
+
"integrity": "sha512-tx9N3hIkd6k567BeujBnpXYdhu3ptYVk0ZkhdcjyQ3I8ZDJ+/JkVtaVNLAuf8hp1buTqNDmxSipALMxEmK2fnw==",
|
|
3519
3519
|
"dependencies": {
|
|
3520
|
-
"@opentelemetry/core": "1.
|
|
3521
|
-
"@opentelemetry/sdk-trace-base": "1.
|
|
3522
|
-
"@opentelemetry/semantic-conventions": "1.
|
|
3520
|
+
"@opentelemetry/core": "1.23.0",
|
|
3521
|
+
"@opentelemetry/sdk-trace-base": "1.23.0",
|
|
3522
|
+
"@opentelemetry/semantic-conventions": "1.23.0"
|
|
3523
3523
|
},
|
|
3524
3524
|
"engines": {
|
|
3525
3525
|
"node": ">=14"
|
|
@@ -3529,9 +3529,9 @@
|
|
|
3529
3529
|
}
|
|
3530
3530
|
},
|
|
3531
3531
|
"node_modules/@opentelemetry/semantic-conventions": {
|
|
3532
|
-
"version": "1.
|
|
3533
|
-
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.
|
|
3534
|
-
"integrity": "sha512-
|
|
3532
|
+
"version": "1.23.0",
|
|
3533
|
+
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.23.0.tgz",
|
|
3534
|
+
"integrity": "sha512-MiqFvfOzfR31t8cc74CTP1OZfz7MbqpAnLCra8NqQoaHJX6ncIRTdYOQYBDQ2uFISDq0WY8Y9dDTWvsgzzBYRg==",
|
|
3535
3535
|
"engines": {
|
|
3536
3536
|
"node": ">=14"
|
|
3537
3537
|
}
|
|
@@ -3639,26 +3639,38 @@
|
|
|
3639
3639
|
"node": ">=18"
|
|
3640
3640
|
}
|
|
3641
3641
|
},
|
|
3642
|
+
"node_modules/@synnaxlabs/alamos/node_modules/@synnaxlabs/x": {
|
|
3643
|
+
"version": "0.13.0",
|
|
3644
|
+
"resolved": "https://registry.npmjs.org/@synnaxlabs/x/-/x-0.13.0.tgz",
|
|
3645
|
+
"integrity": "sha512-9Sh5Io7/Ywegk/axxwHA2wDsmdYL28RQYKUo+gkXtzM6+uj1JSpFvyZFVRSx21uP3p6ABE9MwFCZcCY2/N1iWw==",
|
|
3646
|
+
"dependencies": {
|
|
3647
|
+
"async-mutex": "^0.4.0",
|
|
3648
|
+
"js-convert-case": "^4.2.0",
|
|
3649
|
+
"msgpackr": "^1.9.9",
|
|
3650
|
+
"nanoid": "^5.0.2",
|
|
3651
|
+
"typescript": "^5.3.3",
|
|
3652
|
+
"zod": "3.22.4"
|
|
3653
|
+
}
|
|
3654
|
+
},
|
|
3642
3655
|
"node_modules/@synnaxlabs/client": {
|
|
3643
|
-
"version": "0.
|
|
3644
|
-
"resolved": "https://registry.npmjs.org/@synnaxlabs/client/-/client-0.
|
|
3645
|
-
"integrity": "sha512-
|
|
3656
|
+
"version": "0.17.0",
|
|
3657
|
+
"resolved": "https://registry.npmjs.org/@synnaxlabs/client/-/client-0.17.0.tgz",
|
|
3658
|
+
"integrity": "sha512-ydQpLQ0MUpkvJ/TqHidWNSRSdz6DoSctSbaCu/+TuDy74bIamDWBMQu5fmsTcA5NeQzzmFZgiOMRaFOa9fG1gg==",
|
|
3646
3659
|
"dependencies": {
|
|
3647
|
-
"@synnaxlabs/freighter": "0.
|
|
3648
|
-
"@synnaxlabs/x": "0.
|
|
3660
|
+
"@synnaxlabs/freighter": "0.9.1",
|
|
3661
|
+
"@synnaxlabs/x": "0.14.1",
|
|
3649
3662
|
"async-mutex": "^0.4.0",
|
|
3650
3663
|
"zod": "3.22.4"
|
|
3651
3664
|
}
|
|
3652
3665
|
},
|
|
3653
3666
|
"node_modules/@synnaxlabs/freighter": {
|
|
3654
|
-
"version": "0.
|
|
3655
|
-
"resolved": "https://registry.npmjs.org/@synnaxlabs/freighter/-/freighter-0.
|
|
3656
|
-
"integrity": "sha512-
|
|
3667
|
+
"version": "0.9.1",
|
|
3668
|
+
"resolved": "https://registry.npmjs.org/@synnaxlabs/freighter/-/freighter-0.9.1.tgz",
|
|
3669
|
+
"integrity": "sha512-0ulbbzZ5XixGJgy/ri6ecl9qNrU2NrSj5Sb+vfSb3438CXeTmSY+Q1aJ8/Ksk5sl97AHbtKIGZyuV75AHX6RHw==",
|
|
3657
3670
|
"dependencies": {
|
|
3658
3671
|
"@synnaxlabs/alamos": "0.3.0",
|
|
3659
|
-
"@synnaxlabs/x": "0.
|
|
3672
|
+
"@synnaxlabs/x": "0.14.1",
|
|
3660
3673
|
"js-convert-case": "^4.2.0",
|
|
3661
|
-
"msgpackr": "^1.10.0",
|
|
3662
3674
|
"node-fetch": "2.6.11",
|
|
3663
3675
|
"ws": "^8.15.1",
|
|
3664
3676
|
"zod": "3.22.4"
|
|
@@ -3668,9 +3680,9 @@
|
|
|
3668
3680
|
}
|
|
3669
3681
|
},
|
|
3670
3682
|
"node_modules/@synnaxlabs/x": {
|
|
3671
|
-
"version": "0.
|
|
3672
|
-
"resolved": "https://registry.npmjs.org/@synnaxlabs/x/-/x-0.
|
|
3673
|
-
"integrity": "sha512
|
|
3683
|
+
"version": "0.14.1",
|
|
3684
|
+
"resolved": "https://registry.npmjs.org/@synnaxlabs/x/-/x-0.14.1.tgz",
|
|
3685
|
+
"integrity": "sha512-+rLxNBvFwZjU0JVRslzGoB5OCixITlRIsfibRMGV/P5lUzylA1BKBiAsjrg8i4gWtTx3pQUyrunTFbiTe0HWmA==",
|
|
3674
3686
|
"dependencies": {
|
|
3675
3687
|
"async-mutex": "^0.4.0",
|
|
3676
3688
|
"js-convert-case": "^4.2.0",
|
|
@@ -3874,9 +3886,9 @@
|
|
|
3874
3886
|
}
|
|
3875
3887
|
},
|
|
3876
3888
|
"node_modules/@types/node": {
|
|
3877
|
-
"version": "20.12.
|
|
3878
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.
|
|
3879
|
-
"integrity": "sha512-
|
|
3889
|
+
"version": "20.12.3",
|
|
3890
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.3.tgz",
|
|
3891
|
+
"integrity": "sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw==",
|
|
3880
3892
|
"dependencies": {
|
|
3881
3893
|
"undici-types": "~5.26.4"
|
|
3882
3894
|
}
|
|
@@ -3919,9 +3931,9 @@
|
|
|
3919
3931
|
}
|
|
3920
3932
|
},
|
|
3921
3933
|
"node_modules/@types/serve-static": {
|
|
3922
|
-
"version": "1.15.
|
|
3923
|
-
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.
|
|
3924
|
-
"integrity": "sha512-
|
|
3934
|
+
"version": "1.15.7",
|
|
3935
|
+
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
|
3936
|
+
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
|
3925
3937
|
"dependencies": {
|
|
3926
3938
|
"@types/http-errors": "*",
|
|
3927
3939
|
"@types/node": "*",
|
|
@@ -4500,9 +4512,9 @@
|
|
|
4500
4512
|
}
|
|
4501
4513
|
},
|
|
4502
4514
|
"node_modules/joi": {
|
|
4503
|
-
"version": "17.12.
|
|
4504
|
-
"resolved": "https://registry.npmjs.org/joi/-/joi-17.12.
|
|
4505
|
-
"integrity": "sha512-
|
|
4515
|
+
"version": "17.12.3",
|
|
4516
|
+
"resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz",
|
|
4517
|
+
"integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==",
|
|
4506
4518
|
"dependencies": {
|
|
4507
4519
|
"@hapi/hoek": "^9.3.0",
|
|
4508
4520
|
"@hapi/topo": "^5.1.0",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// This example demonstrates how to write data to an index channel and its corresponding
|
|
2
|
+
// data channel in Synnax in a streaming fashion. Streaming data is ideal for live
|
|
3
|
+
// applications (such as data acquisition from a sensor) or for very large datasets that
|
|
4
|
+
// cannot be written all at once.
|
|
5
|
+
|
|
6
|
+
import { Synnax } from "@synnaxlabs/client";
|
|
7
|
+
|
|
8
|
+
// Connect to a locally running, insecure Synnax cluster. If your connection parameters
|
|
9
|
+
// are different, enter them here.
|
|
10
|
+
const client = new Synnax({
|
|
11
|
+
host: "localhost",
|
|
12
|
+
port: 9090,
|
|
13
|
+
username: "synnax",
|
|
14
|
+
password: "seldon",
|
|
15
|
+
secure: false
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Create an index channel that will be used to store our timestamps.
|
|
19
|
+
const timeChannel = await client.channels.create({
|
|
20
|
+
name: "stream_write_example_time",
|
|
21
|
+
isIndex: true,
|
|
22
|
+
dataType: "timestamp"
|
|
23
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synnaxlabs/client",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.17.
|
|
4
|
+
"version": "0.17.1",
|
|
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/
|
|
22
|
-
"@synnaxlabs/
|
|
21
|
+
"@synnaxlabs/x": "0.14.1",
|
|
22
|
+
"@synnaxlabs/freighter": "0.9.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^20.10.5",
|
|
@@ -27,9 +27,9 @@
|
|
|
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",
|
|
30
31
|
"@synnaxlabs/tsconfig": "0.0.2",
|
|
31
|
-
"eslint-config-synnaxlabs": "0.0.1"
|
|
32
|
-
"@synnaxlabs/vite-plugin": "0.0.1"
|
|
32
|
+
"eslint-config-synnaxlabs": "0.0.1"
|
|
33
33
|
},
|
|
34
34
|
"main": "dist/client.cjs",
|
|
35
35
|
"module": "dist/client.js",
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { DataType, Rate } from "@synnaxlabs/x";
|
|
11
|
-
import { describe, test, expect } from "vitest";
|
|
10
|
+
import { DataType, Rate, TimeStamp } from "@synnaxlabs/x";
|
|
11
|
+
import { describe, test, expect, it } from "vitest";
|
|
12
12
|
|
|
13
13
|
import { QueryError } from "@/errors";
|
|
14
14
|
import { newClient } from "@/setupspecs";
|
|
@@ -62,6 +62,72 @@ describe("Channel", () => {
|
|
|
62
62
|
expect(channels[0].name).toEqual("test1");
|
|
63
63
|
expect(channels[1].name).toEqual("test2");
|
|
64
64
|
});
|
|
65
|
+
describe("retrieveIfNameExists", () => {
|
|
66
|
+
it("should retrieve the existing channel when it exists", async () => {
|
|
67
|
+
const name = `test-${Math.random()}-${TimeStamp.now().valueOf()}`
|
|
68
|
+
const channel = await client.channels.create({
|
|
69
|
+
name,
|
|
70
|
+
leaseholder: 1,
|
|
71
|
+
rate: Rate.hz(1),
|
|
72
|
+
dataType: DataType.FLOAT32,
|
|
73
|
+
});
|
|
74
|
+
const channelTwo = await client.channels.create({
|
|
75
|
+
name,
|
|
76
|
+
leaseholder: 1,
|
|
77
|
+
rate: Rate.hz(1),
|
|
78
|
+
dataType: DataType.FLOAT32,
|
|
79
|
+
},
|
|
80
|
+
{retrieveIfNameExists: true}
|
|
81
|
+
);
|
|
82
|
+
expect(channelTwo.key).toEqual(channel.key);
|
|
83
|
+
});
|
|
84
|
+
it("should create a new channel when it does not exist", async () => {
|
|
85
|
+
const name = `test-${Math.random()}-${TimeStamp.now().valueOf()}`
|
|
86
|
+
const channel = await client.channels.create({
|
|
87
|
+
name,
|
|
88
|
+
leaseholder: 1,
|
|
89
|
+
rate: Rate.hz(1),
|
|
90
|
+
dataType: DataType.FLOAT32,
|
|
91
|
+
});
|
|
92
|
+
const channelTwo = await client.channels.create({
|
|
93
|
+
name: `${name}-2`,
|
|
94
|
+
leaseholder: 1,
|
|
95
|
+
rate: Rate.hz(1),
|
|
96
|
+
dataType: DataType.FLOAT32,
|
|
97
|
+
},
|
|
98
|
+
{retrieveIfNameExists: true}
|
|
99
|
+
);
|
|
100
|
+
expect(channelTwo.key).not.toEqual(channel.key);
|
|
101
|
+
});
|
|
102
|
+
it("should retrieve and create the correct channels when creating many", async () => {
|
|
103
|
+
const name = `test-${Math.random()}-${TimeStamp.now().valueOf()}`
|
|
104
|
+
const channel = await client.channels.create({
|
|
105
|
+
name,
|
|
106
|
+
leaseholder: 1,
|
|
107
|
+
rate: Rate.hz(1),
|
|
108
|
+
dataType: DataType.FLOAT32,
|
|
109
|
+
});
|
|
110
|
+
const channelTwo = await client.channels.create([
|
|
111
|
+
{
|
|
112
|
+
name,
|
|
113
|
+
leaseholder: 1,
|
|
114
|
+
rate: Rate.hz(1),
|
|
115
|
+
dataType: DataType.FLOAT32,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: `${name}-2`,
|
|
119
|
+
leaseholder: 1,
|
|
120
|
+
rate: Rate.hz(1),
|
|
121
|
+
dataType: DataType.FLOAT32,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
{retrieveIfNameExists: true}
|
|
125
|
+
);
|
|
126
|
+
expect(channelTwo.length).toEqual(2);
|
|
127
|
+
expect(channelTwo[0].key).toEqual(channel.key);
|
|
128
|
+
expect(channelTwo[1].key).not.toEqual(channel.key);
|
|
129
|
+
});
|
|
130
|
+
})
|
|
65
131
|
});
|
|
66
132
|
test("retrieve by key", async () => {
|
|
67
133
|
const channel = await client.channels.create({
|
package/src/channel/client.ts
CHANGED
|
@@ -39,6 +39,10 @@ import {
|
|
|
39
39
|
import { MultipleResultsError, NoResultsError, ValidationError } from "@/errors";
|
|
40
40
|
import { type framer } from "@/framer";
|
|
41
41
|
|
|
42
|
+
interface CreateOptions {
|
|
43
|
+
retrieveIfNameExists?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
/**
|
|
43
47
|
* Represents a Channel in a Synnax database. Typically, channels should not be
|
|
44
48
|
* instantiated directly, but instead created via the `.channels.create` or retrieved
|
|
@@ -216,7 +220,7 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
216
220
|
* });
|
|
217
221
|
* ```
|
|
218
222
|
*/
|
|
219
|
-
async create(channel: NewPayload): Promise<Channel>;
|
|
223
|
+
async create(channel: NewPayload, options?: CreateOptions): Promise<Channel>;
|
|
220
224
|
|
|
221
225
|
/**
|
|
222
226
|
* Creates multiple channels with the given properties. The order of the channels
|
|
@@ -241,13 +245,21 @@ export class Client implements AsyncTermSearcher<string, Key, Channel> {
|
|
|
241
245
|
*
|
|
242
246
|
* @param channels
|
|
243
247
|
*/
|
|
244
|
-
async create(channels: NewPayload[]): Promise<Channel[]>;
|
|
248
|
+
async create(channels: NewPayload[], options?: CreateOptions): Promise<Channel[]>;
|
|
245
249
|
|
|
246
|
-
async create(channels: NewPayload | NewPayload[]): Promise<Channel | Channel[]> {
|
|
250
|
+
async create(channels: NewPayload | NewPayload[], options: CreateOptions = {}): Promise<Channel | Channel[]> {
|
|
251
|
+
const { retrieveIfNameExists = false } = options;
|
|
247
252
|
const single = !Array.isArray(channels);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
253
|
+
let toCreate = toArray(channels);
|
|
254
|
+
let created: Channel[] = [];
|
|
255
|
+
if (retrieveIfNameExists) {
|
|
256
|
+
const res = await this.retriever.retrieve(toCreate.map((c) => c.name));
|
|
257
|
+
const existingNames = new Set(res.map((c) => c.name));
|
|
258
|
+
toCreate = toCreate.filter((c) => !existingNames.has(c.name));
|
|
259
|
+
created = this.sugar(res);
|
|
260
|
+
}
|
|
261
|
+
created = created.concat(this.sugar(await this.creator.create(toCreate)));
|
|
262
|
+
return single ? created[0] : created;
|
|
251
263
|
}
|
|
252
264
|
|
|
253
265
|
/**
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { DataType, Synnax, TimeSpan, TimeStamp } from "@synnaxlabs/client";
|
|
2
|
-
|
|
3
|
-
const client = new Synnax({
|
|
4
|
-
host: "localhost",
|
|
5
|
-
port: 9090,
|
|
6
|
-
username: "synnax",
|
|
7
|
-
password: "seldon",
|
|
8
|
-
secure: false
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
const time_channel = await client.channels.create({
|
|
12
|
-
name: "basic_read_write_time",
|
|
13
|
-
isIndex: true,
|
|
14
|
-
dataType: DataType.TIMESTAMP
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const data_channel = await client.channels.create({
|
|
18
|
-
name: "basic_read_write_data",
|
|
19
|
-
isIndex: false,
|
|
20
|
-
dataType: DataType.FLOAT32,
|
|
21
|
-
index: time_channel.key,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const N_SAMPLES = 500;
|
|
25
|
-
|
|
26
|
-
const start = TimeStamp.now();
|
|
27
|
-
|
|
28
|
-
console.log(BigInt(start.valueOf().toString()) - BigInt(start.bigInt.toString()))
|
|
29
|
-
|
|
30
|
-
const data = Float32Array.from({ length: N_SAMPLES }, (_, i) => Math.sin(i / 100));
|
|
31
|
-
const time = BigInt64Array.from({ length: N_SAMPLES }, (_, i) => BigInt(start.add(TimeSpan.milliseconds(i)).valueOf()));
|
|
32
|
-
console.log(time[0], start, Number(time[0]) - start.valueOf())
|
|
33
|
-
|
|
34
|
-
console.log(time_channel.key, data_channel.key)
|
|
35
|
-
|
|
36
|
-
// await client.telem.write(time_channel.key, start, time);
|
|
37
|
-
// await client.telem.write(data_channel.key, start, data);
|
|
38
|
-
|
|
39
|
-
const w1 = await client.telem.newWriter({
|
|
40
|
-
start,
|
|
41
|
-
channels: time_channel.key,
|
|
42
|
-
});
|
|
43
|
-
try {
|
|
44
|
-
await w1.write(time_channel.key, time);
|
|
45
|
-
console.log(await w1.commit());
|
|
46
|
-
} finally {
|
|
47
|
-
await w1.close();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const w = await client.telem.newWriter({
|
|
51
|
-
start,
|
|
52
|
-
channels: data_channel.key,
|
|
53
|
-
});
|
|
54
|
-
try {
|
|
55
|
-
await w.write(data_channel.key, data);
|
|
56
|
-
console.log(await w.commit());
|
|
57
|
-
} finally {
|
|
58
|
-
await w.close();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// await client.telem.write(data_channel.key, start, data);
|
|
63
|
-
|
|
64
|
-
// console.log("HERE")
|
|
65
|
-
|
|
66
|
-
client.close();
|