relayx-js 1.0.9 → 1.0.10
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/examples/example_chat.js +9 -11
- package/examples/example_send_data_on_connect.js +3 -9
- package/package.json +12 -4
- package/realtime/realtime.js +33 -95
- package/tests/test.js +6 -18
package/examples/example_chat.js
CHANGED
|
@@ -8,10 +8,10 @@ const rl = readline.createInterface({
|
|
|
8
8
|
|
|
9
9
|
async function run(){
|
|
10
10
|
var realtime = new Realtime({
|
|
11
|
-
api_key:
|
|
12
|
-
secret:
|
|
11
|
+
api_key: process.env.user_key,
|
|
12
|
+
secret: process.env.secret
|
|
13
13
|
});
|
|
14
|
-
await realtime.init(
|
|
14
|
+
await realtime.init(false, {
|
|
15
15
|
max_retries: 2,
|
|
16
16
|
debug: true
|
|
17
17
|
});
|
|
@@ -32,8 +32,8 @@ async function run(){
|
|
|
32
32
|
console.log("power-telemetry", data);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
await realtime.on("
|
|
36
|
-
console.log("
|
|
35
|
+
await realtime.on("test232", (data) => {
|
|
36
|
+
console.log("test232", data);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
realtime.on(MESSAGE_RESEND, (data) => {
|
|
@@ -57,11 +57,11 @@ async function run(){
|
|
|
57
57
|
var pastDate = new Date(past)
|
|
58
58
|
|
|
59
59
|
var end = new Date();
|
|
60
|
-
var past = end.setDate(end.getDate()
|
|
60
|
+
var past = end.setDate(end.getDate())
|
|
61
61
|
var endDate = new Date(past)
|
|
62
62
|
|
|
63
|
-
var history = await realtime.history(topic, pastDate
|
|
64
|
-
|
|
63
|
+
var history = await realtime.history(topic, pastDate)
|
|
64
|
+
console.log(history)
|
|
65
65
|
})
|
|
66
66
|
}else if(input == "off"){
|
|
67
67
|
rl.question("topic to off(): ", async (topic) => {
|
|
@@ -83,9 +83,7 @@ async function run(){
|
|
|
83
83
|
})
|
|
84
84
|
}else{
|
|
85
85
|
rl.question("topic: ", async (topic) => {
|
|
86
|
-
var output = await realtime.publish(topic,
|
|
87
|
-
"data": input
|
|
88
|
-
});
|
|
86
|
+
var output = await realtime.publish(topic, input);
|
|
89
87
|
})
|
|
90
88
|
}
|
|
91
89
|
});
|
|
@@ -2,8 +2,8 @@ import { Realtime, CONNECTED, RECONNECT, DISCONNECTED, MESSAGE_RESEND } from "..
|
|
|
2
2
|
|
|
3
3
|
async function run(){
|
|
4
4
|
var realtime = new Realtime({
|
|
5
|
-
api_key:
|
|
6
|
-
secret:
|
|
5
|
+
api_key: process.env.user_key,
|
|
6
|
+
secret: process.env.secret
|
|
7
7
|
});
|
|
8
8
|
await realtime.init(true, {
|
|
9
9
|
max_retries: 2,
|
|
@@ -16,19 +16,13 @@ async function run(){
|
|
|
16
16
|
for (let angle = 0; angle <= 18000; angle++){
|
|
17
17
|
|
|
18
18
|
var value = Math.floor(Math.random() * (100 + 1))
|
|
19
|
-
// console.log(value)
|
|
20
|
-
|
|
21
|
-
// await realtime.publish("test-power", {
|
|
22
|
-
// "value": value,
|
|
23
|
-
// "time": Date.now() + 2000
|
|
24
|
-
// })
|
|
25
19
|
|
|
26
20
|
var sent = await realtime.publish("power-telemetry", {
|
|
27
21
|
"value": value,
|
|
28
22
|
"time": Date.now()
|
|
29
23
|
});
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
console.log(`Message sent => ${sent}`);
|
|
32
26
|
|
|
33
27
|
await realtime.sleep(100)
|
|
34
28
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "relayx-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"main": "realtime/realtime.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "NODE_ENV=test node tests/test.js"
|
|
8
8
|
},
|
|
9
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"realtime",
|
|
11
|
+
"realtime-communication",
|
|
12
|
+
"relay",
|
|
13
|
+
"relay-x",
|
|
14
|
+
"relay-x-js"
|
|
15
|
+
],
|
|
10
16
|
"author": "Relay",
|
|
11
17
|
"license": "Apache 2.0",
|
|
12
18
|
"description": "A powerful library for integrating real-time communication into your software stack, powered by the Relay Network.",
|
|
13
19
|
"dependencies": {
|
|
20
|
+
"@msgpack/msgpack": "^3.1.1",
|
|
14
21
|
"@nats-io/jetstream": "^3.0.0-35",
|
|
15
|
-
"axios": "1.
|
|
22
|
+
"axios": "^1.8.4",
|
|
16
23
|
"jest": "^29.7.0",
|
|
17
|
-
"nats": "^2.28.2"
|
|
24
|
+
"nats": "^2.28.2",
|
|
25
|
+
"uuid": "^11.1.0"
|
|
18
26
|
},
|
|
19
27
|
"devDependencies": {
|
|
20
28
|
"@babel/core": "^7.26.0",
|
package/realtime/realtime.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { connect, JSONCodec, Events, DebugEvents, AckPolicy, ReplayPolicy, credsAuthenticator } from "nats";
|
|
3
|
-
import { DeliverPolicy, jetstream
|
|
4
|
-
import {
|
|
3
|
+
import { DeliverPolicy, jetstream } from "@nats-io/jetstream";
|
|
4
|
+
import { encode, decode } from "@msgpack/msgpack";
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
6
|
|
|
6
7
|
export class Realtime {
|
|
7
8
|
|
|
@@ -10,8 +11,6 @@ export class Realtime {
|
|
|
10
11
|
#natsClient = null;
|
|
11
12
|
#codec = JSONCodec();
|
|
12
13
|
#jetstream = null;
|
|
13
|
-
#jsManager = null;
|
|
14
|
-
#streamTracker = [];
|
|
15
14
|
#consumerMap = {};
|
|
16
15
|
|
|
17
16
|
#event_func = {};
|
|
@@ -36,9 +35,6 @@ export class Realtime {
|
|
|
36
35
|
// Offline messages
|
|
37
36
|
#offlineMessageBuffer = [];
|
|
38
37
|
|
|
39
|
-
// Test Variables
|
|
40
|
-
#timeout = 1000;
|
|
41
|
-
|
|
42
38
|
#maxPublishRetries = 5;
|
|
43
39
|
|
|
44
40
|
constructor(config){
|
|
@@ -62,6 +58,7 @@ export class Realtime {
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
this.namespace = null;
|
|
61
|
+
this.topicHash = null;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
/*
|
|
@@ -161,8 +158,10 @@ export class Realtime {
|
|
|
161
158
|
|
|
162
159
|
if(data["status"] == "NAMESPACE_RETRIEVE_SUCCESS"){
|
|
163
160
|
this.namespace = data["data"]["namespace"]
|
|
161
|
+
this.topicHash = data["data"]["hash"]
|
|
164
162
|
}else{
|
|
165
163
|
this.namespace = null;
|
|
164
|
+
this.topicHash = null;
|
|
166
165
|
return
|
|
167
166
|
}
|
|
168
167
|
}
|
|
@@ -189,7 +188,6 @@ export class Realtime {
|
|
|
189
188
|
token: this.api_key,
|
|
190
189
|
});
|
|
191
190
|
|
|
192
|
-
this.#jsManager = await jetstreamManager(this.#natsClient);
|
|
193
191
|
this.#jetstream = await jetstream(this.#natsClient);
|
|
194
192
|
|
|
195
193
|
await this.#getNameSpace()
|
|
@@ -225,7 +223,6 @@ export class Realtime {
|
|
|
225
223
|
this.#log(`client disconnected - ${s.data}`);
|
|
226
224
|
|
|
227
225
|
this.connected = false;
|
|
228
|
-
this.#streamTracker = [];
|
|
229
226
|
this.#consumerMap = {};
|
|
230
227
|
|
|
231
228
|
if (DISCONNECTED in this.#event_func){
|
|
@@ -248,8 +245,6 @@ export class Realtime {
|
|
|
248
245
|
this.reconnecting = false;
|
|
249
246
|
this.connected = true;
|
|
250
247
|
|
|
251
|
-
// this.#subscribeToTopics();
|
|
252
|
-
|
|
253
248
|
if(RECONNECT in this.#event_func){
|
|
254
249
|
this.#event_func[RECONNECT](this.#RECONNECTED);
|
|
255
250
|
}
|
|
@@ -418,13 +413,12 @@ export class Realtime {
|
|
|
418
413
|
"start": Date.now()
|
|
419
414
|
}
|
|
420
415
|
|
|
421
|
-
|
|
416
|
+
this.#log("Encoding message via msg pack...")
|
|
417
|
+
var encodedMessage = encode(message);
|
|
422
418
|
|
|
423
419
|
if(this.connected){
|
|
424
420
|
if(!this.#topicMap.includes(topic)){
|
|
425
421
|
this.#topicMap.push(topic);
|
|
426
|
-
|
|
427
|
-
await this.#createOrGetStream();
|
|
428
422
|
}else{
|
|
429
423
|
this.#log(`${topic} exists locally, moving on...`)
|
|
430
424
|
}
|
|
@@ -487,12 +481,8 @@ export class Realtime {
|
|
|
487
481
|
end = end.toISOString();
|
|
488
482
|
}
|
|
489
483
|
|
|
490
|
-
console.log(`END => ${end}`)
|
|
491
|
-
|
|
492
|
-
await this.#createOrGetStream();
|
|
493
|
-
|
|
494
484
|
var opts = {
|
|
495
|
-
name: topic
|
|
485
|
+
name: `${topic}_${uuidv4()}_history`,
|
|
496
486
|
filter_subjects: [this.#getStreamTopic(topic)],
|
|
497
487
|
replay_policy: ReplayPolicy.Instant,
|
|
498
488
|
opt_start_time: start,
|
|
@@ -503,30 +493,33 @@ export class Realtime {
|
|
|
503
493
|
this.#log(this.#topicMap)
|
|
504
494
|
this.#log("Consumer is consuming");
|
|
505
495
|
|
|
506
|
-
this.#consumerMap[topic] = consumer;
|
|
507
|
-
|
|
508
|
-
const msgs = await consumer.consume();
|
|
509
|
-
|
|
510
496
|
var history = [];
|
|
511
497
|
|
|
512
|
-
|
|
513
|
-
|
|
498
|
+
while(true){
|
|
499
|
+
var msg = await consumer.next({
|
|
500
|
+
expires: 1000
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
if(msg == null){
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
514
506
|
|
|
515
507
|
if(end != null || end != undefined){
|
|
516
|
-
if(
|
|
508
|
+
if(msg.timestamp > end){
|
|
517
509
|
break
|
|
518
510
|
}
|
|
519
511
|
}
|
|
520
512
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
513
|
+
this.#log("Decoding msgpack message...")
|
|
514
|
+
var data = decode(msg.data);
|
|
515
|
+
this.#log(data);
|
|
516
|
+
|
|
524
517
|
history.push(data.message);
|
|
525
518
|
}
|
|
526
519
|
|
|
527
520
|
var del = await consumer.delete();
|
|
528
521
|
|
|
529
|
-
this.#log("History pull done"
|
|
522
|
+
this.#log("History pull done: " + del);
|
|
530
523
|
|
|
531
524
|
return history;
|
|
532
525
|
}
|
|
@@ -569,10 +562,8 @@ export class Realtime {
|
|
|
569
562
|
* @param {string} topic
|
|
570
563
|
*/
|
|
571
564
|
async #startConsumer(topic){
|
|
572
|
-
await this.#createOrGetStream();
|
|
573
|
-
|
|
574
565
|
var opts = {
|
|
575
|
-
name: topic
|
|
566
|
+
name: `${topic}_${uuidv4()}`,
|
|
576
567
|
filter_subjects: [this.#getStreamTopic(topic), this.#getStreamTopic(topic) + "_presence"],
|
|
577
568
|
replay_policy: ReplayPolicy.Instant,
|
|
578
569
|
opt_start_time: new Date(),
|
|
@@ -587,11 +578,10 @@ export class Realtime {
|
|
|
587
578
|
|
|
588
579
|
await consumer.consume({
|
|
589
580
|
callback: (msg) => {
|
|
590
|
-
console.log("TIMESTAMP", msg.info)
|
|
591
|
-
|
|
592
|
-
msg.ack();
|
|
593
581
|
try{
|
|
594
|
-
|
|
582
|
+
this.#log("Decoding msgpack message...")
|
|
583
|
+
var data = decode(msg.data);
|
|
584
|
+
|
|
595
585
|
var room = data.room;
|
|
596
586
|
|
|
597
587
|
this.#log(data);
|
|
@@ -605,9 +595,11 @@ export class Realtime {
|
|
|
605
595
|
"data": data.message
|
|
606
596
|
});
|
|
607
597
|
}
|
|
598
|
+
|
|
599
|
+
msg.ack();
|
|
608
600
|
}catch(err){
|
|
609
601
|
this.#log("Consumer err " + err);
|
|
610
|
-
msg.nack();
|
|
602
|
+
msg.nack(5000);
|
|
611
603
|
}
|
|
612
604
|
}
|
|
613
605
|
});
|
|
@@ -634,40 +626,6 @@ export class Realtime {
|
|
|
634
626
|
return del;
|
|
635
627
|
}
|
|
636
628
|
|
|
637
|
-
/**
|
|
638
|
-
* Gets stream if it exists or creates one
|
|
639
|
-
* @param {string} streamName
|
|
640
|
-
*/
|
|
641
|
-
async #createOrGetStream(){
|
|
642
|
-
const streamName = this.#getStreamName();
|
|
643
|
-
var stream = null;
|
|
644
|
-
|
|
645
|
-
try{
|
|
646
|
-
stream = await this.#jsManager.streams.info(streamName);
|
|
647
|
-
}catch(err){
|
|
648
|
-
stream = null;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
this.#log(`STREAM => ${stream}`)
|
|
652
|
-
|
|
653
|
-
if (stream == null){
|
|
654
|
-
// Stream does not exist, create one
|
|
655
|
-
await this.#jsManager.streams.add({
|
|
656
|
-
name: streamName,
|
|
657
|
-
subjects: [...this.#getStreamTopicList(), ...this.#getPresenceTopics()],
|
|
658
|
-
num_replicas: 3
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
this.#log(`${streamName} created`);
|
|
662
|
-
}else{
|
|
663
|
-
var subs = [...stream.config.subjects, ...this.#getStreamTopicList(), ...this.#getPresenceTopics()];
|
|
664
|
-
stream.config.subjects = [...new Set(subs)];
|
|
665
|
-
await this.#jsManager.streams.update(streamName, stream.config);
|
|
666
|
-
|
|
667
|
-
this.#log(`${streamName} exists, updating and moving on...`);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
629
|
// Utility functions
|
|
672
630
|
#getClientId(){
|
|
673
631
|
return this.#natsClient?.info?.client_id
|
|
@@ -701,34 +659,14 @@ export class Realtime {
|
|
|
701
659
|
}
|
|
702
660
|
|
|
703
661
|
#getStreamTopic(topic){
|
|
704
|
-
if(this.
|
|
705
|
-
return this.
|
|
662
|
+
if(this.topicHash != null){
|
|
663
|
+
return this.topicHash + "." + topic;
|
|
706
664
|
}else{
|
|
707
665
|
this.close();
|
|
708
|
-
throw new Error("$
|
|
666
|
+
throw new Error("$topicHash is null. Cannot initialize program with null $topicHash")
|
|
709
667
|
}
|
|
710
668
|
}
|
|
711
669
|
|
|
712
|
-
#getStreamTopicList(){
|
|
713
|
-
var topics = [];
|
|
714
|
-
|
|
715
|
-
this.#topicMap.forEach((topic) => {
|
|
716
|
-
topics.push(this.#getStreamTopic(topic))
|
|
717
|
-
})
|
|
718
|
-
|
|
719
|
-
return topics
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
#getPresenceTopics(){
|
|
723
|
-
var presence = [];
|
|
724
|
-
|
|
725
|
-
this.#topicMap.forEach((topic) => {
|
|
726
|
-
presence.push(this.#getStreamTopic(topic) + "_presence")
|
|
727
|
-
})
|
|
728
|
-
|
|
729
|
-
return presence
|
|
730
|
-
}
|
|
731
|
-
|
|
732
670
|
sleep(ms) {
|
|
733
671
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
734
672
|
}
|
package/tests/test.js
CHANGED
|
@@ -116,6 +116,7 @@ test('init() function test', async () => {
|
|
|
116
116
|
|
|
117
117
|
test("Namespace check test", async () => {
|
|
118
118
|
assert.strictEqual(realTimeEnabled.namespace.length > 0, true)
|
|
119
|
+
assert.strictEqual(realTimeEnabled.topicHash.length > 0, true)
|
|
119
120
|
});
|
|
120
121
|
|
|
121
122
|
test("Retry method test", async () => {
|
|
@@ -401,17 +402,19 @@ test("Get stream name test", () => {
|
|
|
401
402
|
});
|
|
402
403
|
|
|
403
404
|
realtime.namespace = "spacex-dragon-program"
|
|
405
|
+
realtime.topicHash = "topic_hash";
|
|
404
406
|
|
|
405
407
|
var getStreamName = realtime.testGetStreamName();
|
|
406
408
|
var getStreamTopic = realtime.testGetStreamTopic();
|
|
407
409
|
|
|
408
410
|
var name = getStreamName();
|
|
409
|
-
assert.strictEqual(name,
|
|
411
|
+
assert.strictEqual(name, `${realtime.namespace}_stream`);
|
|
410
412
|
|
|
411
413
|
var topic = getStreamTopic("hello_world")
|
|
412
|
-
assert.strictEqual(topic,
|
|
414
|
+
assert.strictEqual(topic, `${realtime.topicHash}.hello_world`)
|
|
413
415
|
|
|
414
416
|
realtime.namespace = null;
|
|
417
|
+
realtime.topicHash = null;
|
|
415
418
|
|
|
416
419
|
assert.throws(() => {
|
|
417
420
|
getStreamName();
|
|
@@ -422,7 +425,7 @@ test("Get stream name test", () => {
|
|
|
422
425
|
assert.throws(() => {
|
|
423
426
|
getStreamTopic("hello_world");
|
|
424
427
|
},
|
|
425
|
-
new Error("$
|
|
428
|
+
new Error("$topicHash is null. Cannot initialize program with null $topicHash"),
|
|
426
429
|
"Expected error was not thrown")
|
|
427
430
|
});
|
|
428
431
|
|
|
@@ -508,19 +511,4 @@ test("History test", async () => {
|
|
|
508
511
|
},
|
|
509
512
|
new Error("$start must be a Date object"),
|
|
510
513
|
"Expected error was not thrown");
|
|
511
|
-
|
|
512
|
-
await realTimeEnabled.history("hello", new Date());
|
|
513
|
-
|
|
514
|
-
await realTimeEnabled.history("hello", new Date(), new Date());
|
|
515
|
-
|
|
516
|
-
var start = new Date();
|
|
517
|
-
var past = start.setDate(start.getDate() - 4)
|
|
518
|
-
var pastDate = new Date(past)
|
|
519
|
-
|
|
520
|
-
var end = new Date();
|
|
521
|
-
var past = end.setDate(end.getDate() - 2)
|
|
522
|
-
var endDate = new Date(past)
|
|
523
|
-
|
|
524
|
-
var history = await realTimeEnabled.history("hello", pastDate, endDate)
|
|
525
|
-
assert.strictEqual(history.length > 0, true)
|
|
526
514
|
})
|