topazcube 0.1.11 → 0.1.13
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/dist/server.cjs +59 -50
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +3 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +59 -50
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/src/server.ts +69 -57
package/src/server.ts
CHANGED
|
@@ -115,13 +115,25 @@ export default class TopazCubeServer {
|
|
|
115
115
|
_wss: WebSocketServer | null = null
|
|
116
116
|
_exited = false
|
|
117
117
|
|
|
118
|
+
log(...args: any[]) {
|
|
119
|
+
this.log(this.name + ':', ...args);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
warn(...args: any[]) {
|
|
123
|
+
this.warn(this.name + ':', ...args);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
error(...args: any[]) {
|
|
127
|
+
this.error(this.name + ':', ...args);
|
|
128
|
+
}
|
|
129
|
+
|
|
118
130
|
constructor({
|
|
119
131
|
name = 'TopazCubeServer',
|
|
120
132
|
cycle = 100,
|
|
121
133
|
port = 8799,
|
|
122
134
|
useHttps = false,
|
|
123
135
|
key = './cert/key.pem',
|
|
124
|
-
cert = './cert/
|
|
136
|
+
cert = './cert/cert.pem',
|
|
125
137
|
MongoUrl = 'mongodb://localhost:27017',
|
|
126
138
|
database = 'topazcube',
|
|
127
139
|
collection = 'documents',
|
|
@@ -176,10 +188,10 @@ export default class TopazCubeServer {
|
|
|
176
188
|
}).listen(this.port)
|
|
177
189
|
this._wss = new WebSocketServer({ server: httpsServer })
|
|
178
190
|
httpsServer = null
|
|
179
|
-
|
|
191
|
+
this.log(this.name + ' running on HTTPS port ' + this.port)
|
|
180
192
|
} else {
|
|
181
193
|
this._wss = new WebSocketServer({ port: this.port })
|
|
182
|
-
|
|
194
|
+
this.log(this.name + ' running on port ' + this.port)
|
|
183
195
|
}
|
|
184
196
|
this._wss.on('connection', (client: WebSocket) => {
|
|
185
197
|
this._onConnected(client)
|
|
@@ -213,17 +225,17 @@ export default class TopazCubeServer {
|
|
|
213
225
|
}
|
|
214
226
|
|
|
215
227
|
// Process other keypresses
|
|
216
|
-
|
|
228
|
+
this.log(`Key pressed: ${key}`)
|
|
217
229
|
|
|
218
230
|
// Example: 's' to save all documents
|
|
219
231
|
if (key == 's') {
|
|
220
|
-
|
|
232
|
+
this.log('Saving all documents...')
|
|
221
233
|
this._saveAllDocuments()
|
|
222
234
|
}
|
|
223
235
|
|
|
224
236
|
// Example: 'i' to print server info
|
|
225
237
|
if (key == 'i') {
|
|
226
|
-
|
|
238
|
+
this.log(
|
|
227
239
|
`Server: ${this.name}, Clients: ${this.clients.length}, Documents: ${Object.keys(this.documents).length}`
|
|
228
240
|
)
|
|
229
241
|
}
|
|
@@ -260,7 +272,7 @@ export default class TopazCubeServer {
|
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
_makeReactive(name: string): void {
|
|
263
|
-
//
|
|
275
|
+
//this.log(`Making document '${name}' reactive`, this.documents[name])
|
|
264
276
|
let ep: any = false
|
|
265
277
|
if (this.allowFastPatch) {
|
|
266
278
|
ep = fastPatchProperties
|
|
@@ -360,7 +372,7 @@ export default class TopazCubeServer {
|
|
|
360
372
|
let updateTime = t1 - now
|
|
361
373
|
this.stats.tUpdate.push(updateTime)
|
|
362
374
|
|
|
363
|
-
//
|
|
375
|
+
//this.log(`update ${this.update} patch: ${this.update % this.patchCycleDivider}`, )
|
|
364
376
|
|
|
365
377
|
let patchTime = 0
|
|
366
378
|
if (this.update % this.patchCycleDivider == 0) {
|
|
@@ -369,7 +381,7 @@ export default class TopazCubeServer {
|
|
|
369
381
|
patchTime = t2 - t1
|
|
370
382
|
this.stats.tPatch.push(patchTime)
|
|
371
383
|
if (this.allowFastPatch) {
|
|
372
|
-
|
|
384
|
+
this.log(`update ${this.update} dt:${dtms}ms RTC:${this.stats._sendRTCUpdate}bytes, tUpdate: ${updateTime}ms, tPatch: ${patchTime}ms`, )
|
|
373
385
|
}
|
|
374
386
|
this.stats._sendRTCUpdate = 0
|
|
375
387
|
}
|
|
@@ -396,7 +408,7 @@ export default class TopazCubeServer {
|
|
|
396
408
|
this.stats[key] = 0
|
|
397
409
|
}
|
|
398
410
|
}
|
|
399
|
-
//
|
|
411
|
+
//this.log('stats', this.stats)
|
|
400
412
|
}
|
|
401
413
|
|
|
402
414
|
/*= MESSAGES ===============================================================*/
|
|
@@ -418,7 +430,7 @@ export default class TopazCubeServer {
|
|
|
418
430
|
client.dataChannel = null
|
|
419
431
|
client.peerConnection = null
|
|
420
432
|
|
|
421
|
-
|
|
433
|
+
this.log('client connected', client.ID)
|
|
422
434
|
this.clients.push(client)
|
|
423
435
|
client.on('error', () => {
|
|
424
436
|
this._onError(client, arguments)
|
|
@@ -472,7 +484,7 @@ export default class TopazCubeServer {
|
|
|
472
484
|
let ping = time - message.st
|
|
473
485
|
client.ctdiff = message.ct + ping / 2 - time
|
|
474
486
|
client.ping = ping
|
|
475
|
-
//
|
|
487
|
+
//this.log(time, "PENG ping, ctdiff", message, ping, client.ctdiff, "ms")
|
|
476
488
|
/*
|
|
477
489
|
} else if (message.c == 'rtc-offer') {
|
|
478
490
|
this._processOffer(client, message)
|
|
@@ -503,7 +515,7 @@ export default class TopazCubeServer {
|
|
|
503
515
|
}
|
|
504
516
|
|
|
505
517
|
_onError(client: ClientType, args: IArguments): void {
|
|
506
|
-
|
|
518
|
+
this.error('onError:', args)
|
|
507
519
|
}
|
|
508
520
|
|
|
509
521
|
_onDisconnected(client: ClientType): void {
|
|
@@ -513,7 +525,7 @@ export default class TopazCubeServer {
|
|
|
513
525
|
if (client.peerConnection) {
|
|
514
526
|
client.peerConnection.close()
|
|
515
527
|
}
|
|
516
|
-
|
|
528
|
+
this.log('client disconnected')
|
|
517
529
|
let index = this.clients.indexOf(client)
|
|
518
530
|
if (index !== -1) {
|
|
519
531
|
this.clients.splice(index, 1)
|
|
@@ -531,7 +543,7 @@ export default class TopazCubeServer {
|
|
|
531
543
|
}
|
|
532
544
|
let t3 = Date.now()
|
|
533
545
|
if (data.length > 4096) {
|
|
534
|
-
|
|
546
|
+
this.log(`Big message ${dl} -> ${data.length} (${(100.0 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`)
|
|
535
547
|
}
|
|
536
548
|
this.stats.send += data.byteLength
|
|
537
549
|
if (this.simulateLatency) {
|
|
@@ -542,7 +554,7 @@ export default class TopazCubeServer {
|
|
|
542
554
|
client.send(data)
|
|
543
555
|
}
|
|
544
556
|
} catch (e) {
|
|
545
|
-
|
|
557
|
+
this.error('Error sending message:', e, message)
|
|
546
558
|
}
|
|
547
559
|
}
|
|
548
560
|
|
|
@@ -657,9 +669,9 @@ export default class TopazCubeServer {
|
|
|
657
669
|
}
|
|
658
670
|
}
|
|
659
671
|
|
|
660
|
-
|
|
661
|
-
//
|
|
662
|
-
//
|
|
672
|
+
this.log("--------------------------------------------------")
|
|
673
|
+
//this.log("changed", changed)
|
|
674
|
+
//this.log("count", count)
|
|
663
675
|
|
|
664
676
|
// create encoded changes
|
|
665
677
|
//
|
|
@@ -770,7 +782,7 @@ export default class TopazCubeServer {
|
|
|
770
782
|
}
|
|
771
783
|
//this.broadcastRTC(record, sus)
|
|
772
784
|
let t3 = Date.now()
|
|
773
|
-
|
|
785
|
+
this.log(`_sendPatches: ${name} encode_changes: ${t2-t1}ms broadcast:${t3-t2}ms`)
|
|
774
786
|
}
|
|
775
787
|
}
|
|
776
788
|
}
|
|
@@ -788,7 +800,7 @@ export default class TopazCubeServer {
|
|
|
788
800
|
let e = entities[id]
|
|
789
801
|
if (!e) { return }
|
|
790
802
|
e['__changed_'+property] = true
|
|
791
|
-
//
|
|
803
|
+
//this.log('propertyChange', e)
|
|
792
804
|
}
|
|
793
805
|
|
|
794
806
|
|
|
@@ -796,7 +808,7 @@ export default class TopazCubeServer {
|
|
|
796
808
|
|
|
797
809
|
/*
|
|
798
810
|
async _processOffer(client: ClientType, data: any): Promise<void> {
|
|
799
|
-
//
|
|
811
|
+
//this.log("RTC: Offer received", data);
|
|
800
812
|
const peerConnection = new wrtc.RTCPeerConnection({
|
|
801
813
|
iceServers: [
|
|
802
814
|
{ urls: 'stun:stun.l.google.com:19302' },
|
|
@@ -810,43 +822,43 @@ export default class TopazCubeServer {
|
|
|
810
822
|
|
|
811
823
|
peerConnection.onicecandidate = (event: any) => {
|
|
812
824
|
if (event.candidate) {
|
|
813
|
-
//
|
|
825
|
+
//this.log("RTC: ICE candidate generated", event.candidate.candidate.substring(0, 50) + "...");
|
|
814
826
|
this.send(client, {
|
|
815
827
|
c: 'rtc-candidate',
|
|
816
828
|
type: 'ice-candidate',
|
|
817
829
|
candidate: event.candidate, // .toJSON()
|
|
818
830
|
})
|
|
819
831
|
} else {
|
|
820
|
-
//
|
|
832
|
+
//this.log("RTC: ICE candidate gathering complete");
|
|
821
833
|
}
|
|
822
834
|
}
|
|
823
835
|
|
|
824
836
|
peerConnection.onconnectionstatechange = () => {
|
|
825
|
-
//
|
|
837
|
+
//this.log(`RTC: Connection state changed: ${peerConnection.connectionState}`);
|
|
826
838
|
if (peerConnection.connectionState === 'connected') {
|
|
827
839
|
client.webRTCConnected = true
|
|
828
|
-
|
|
840
|
+
this.log(`RTC: Connection established with client ${client.ID}`)
|
|
829
841
|
} else if (
|
|
830
842
|
peerConnection.connectionState === 'failed' ||
|
|
831
843
|
peerConnection.connectionState === 'disconnected' ||
|
|
832
844
|
peerConnection.connectionState === 'closed'
|
|
833
845
|
) {
|
|
834
846
|
client.webRTCConnected = false
|
|
835
|
-
|
|
847
|
+
this.log(`RTC: Connection failed or closed with client ${client.ID}`)
|
|
836
848
|
}
|
|
837
849
|
}
|
|
838
850
|
|
|
839
851
|
peerConnection.onicegatheringstatechange = () => {
|
|
840
|
-
//
|
|
852
|
+
//this.log(`RTC: ICE gathering state: ${peerConnection.iceGatheringState}`);
|
|
841
853
|
}
|
|
842
854
|
|
|
843
855
|
peerConnection.oniceconnectionstatechange = () => {
|
|
844
|
-
//
|
|
856
|
+
//this.log(`RTC: ICE connection state: ${peerConnection.iceConnectionState}`);
|
|
845
857
|
if (
|
|
846
858
|
peerConnection.iceConnectionState === 'connected' ||
|
|
847
859
|
peerConnection.iceConnectionState === 'completed'
|
|
848
860
|
) {
|
|
849
|
-
//
|
|
861
|
+
//this.log(`RTC: ICE connection established with client ${client.ID}`);
|
|
850
862
|
}
|
|
851
863
|
}
|
|
852
864
|
|
|
@@ -854,7 +866,7 @@ export default class TopazCubeServer {
|
|
|
854
866
|
await peerConnection.setRemoteDescription(
|
|
855
867
|
new wrtc.RTCSessionDescription(data)
|
|
856
868
|
)
|
|
857
|
-
//
|
|
869
|
+
//this.log("RTC: Remote description set successfully");
|
|
858
870
|
|
|
859
871
|
client.dataChannel = peerConnection.createDataChannel('serverchannel', {
|
|
860
872
|
ordered: true,
|
|
@@ -862,13 +874,13 @@ export default class TopazCubeServer {
|
|
|
862
874
|
})
|
|
863
875
|
|
|
864
876
|
client.dataChannel.onopen = () => {
|
|
865
|
-
//
|
|
877
|
+
//this.log(`RTC: Data channel opened for client ${client.ID}`);
|
|
866
878
|
// Try sending a test message
|
|
867
879
|
try {
|
|
868
880
|
const testData = { c: 'test', message: 'Hello WebRTC' }
|
|
869
881
|
this.sendRTC(client, testData)
|
|
870
882
|
} catch (e) {
|
|
871
|
-
|
|
883
|
+
this.error(
|
|
872
884
|
`RTC: Error sending test message to client ${client.ID}`,
|
|
873
885
|
e
|
|
874
886
|
)
|
|
@@ -876,23 +888,23 @@ export default class TopazCubeServer {
|
|
|
876
888
|
}
|
|
877
889
|
|
|
878
890
|
client.dataChannel.onclose = () => {
|
|
879
|
-
|
|
891
|
+
this.log(`RTC: Data channel closed for client ${client.ID}`)
|
|
880
892
|
}
|
|
881
893
|
|
|
882
894
|
client.dataChannel.onerror = (error: Event) => {
|
|
883
|
-
|
|
895
|
+
this.error(`RTC: Data channel error for client ${client.ID}:`, error)
|
|
884
896
|
}
|
|
885
897
|
|
|
886
898
|
client.dataChannel.onmessage = (event: MessageEvent) => {
|
|
887
899
|
try {
|
|
888
900
|
const data = decode(event.data)
|
|
889
|
-
|
|
901
|
+
this.log(
|
|
890
902
|
`RTC: Data channel message from client ${client.ID}:`,
|
|
891
903
|
data
|
|
892
904
|
)
|
|
893
905
|
//this.onMessage(client, data);
|
|
894
906
|
} catch (error) {
|
|
895
|
-
|
|
907
|
+
this.error(
|
|
896
908
|
`RTC: Error decoding message from client ${client.ID}:`,
|
|
897
909
|
error
|
|
898
910
|
)
|
|
@@ -903,14 +915,14 @@ export default class TopazCubeServer {
|
|
|
903
915
|
const answer = await peerConnection.createAnswer()
|
|
904
916
|
await peerConnection.setLocalDescription(answer)
|
|
905
917
|
|
|
906
|
-
//
|
|
918
|
+
//this.log(`RTC: Sending answer to client ${client.ID}`);
|
|
907
919
|
this.send(client, {
|
|
908
920
|
c: 'rtc-answer',
|
|
909
921
|
type: answer.type,
|
|
910
922
|
sdp: answer.sdp,
|
|
911
923
|
})
|
|
912
924
|
} catch (error) {
|
|
913
|
-
|
|
925
|
+
this.error(
|
|
914
926
|
`RTC: Error processing offer from client ${client.ID}:`,
|
|
915
927
|
error
|
|
916
928
|
)
|
|
@@ -918,19 +930,19 @@ export default class TopazCubeServer {
|
|
|
918
930
|
}
|
|
919
931
|
|
|
920
932
|
async _processICECandidate(client: ClientType, data: any): Promise<void> {
|
|
921
|
-
//
|
|
933
|
+
//this.log(`RTC: Processing ICE candidate from client ${client.ID}`);
|
|
922
934
|
try {
|
|
923
935
|
if (client.peerConnection && data.candidate) {
|
|
924
936
|
await client.peerConnection.addIceCandidate(
|
|
925
937
|
data.candidate
|
|
926
938
|
//new wrtc.RTCIceCandidate(data.candidate)
|
|
927
939
|
)
|
|
928
|
-
//
|
|
940
|
+
//this.log(`RTC: ICE candidate added successfully for client ${client.ID}`);
|
|
929
941
|
} else {
|
|
930
|
-
//
|
|
942
|
+
//this.warn(`RTC: Cannot add ICE candidate for client ${client.ID} - peerConnection not ready or candidate missing`);
|
|
931
943
|
}
|
|
932
944
|
} catch (error) {
|
|
933
|
-
|
|
945
|
+
this.error(`RTC: Error adding ICE candidate for client ${client.ID}`)
|
|
934
946
|
}
|
|
935
947
|
}
|
|
936
948
|
|
|
@@ -980,7 +992,7 @@ export default class TopazCubeServer {
|
|
|
980
992
|
|
|
981
993
|
|
|
982
994
|
if (data.length > 16384) {
|
|
983
|
-
|
|
995
|
+
this.log(`BroadcastRTC message ${dl} -> ${data.length} (${(100.0 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`)
|
|
984
996
|
}
|
|
985
997
|
|
|
986
998
|
let packages = this._splitRTCMessage(data)
|
|
@@ -1010,7 +1022,7 @@ export default class TopazCubeServer {
|
|
|
1010
1022
|
let packages: Uint8Array[]
|
|
1011
1023
|
if (data.byteLength > 65535) {
|
|
1012
1024
|
const now = Date.now()
|
|
1013
|
-
|
|
1025
|
+
this.warn(`RTC: Message too large: ${data.byteLength} bytes`)
|
|
1014
1026
|
// Split the message into smaller packages
|
|
1015
1027
|
packages = [];
|
|
1016
1028
|
let offset = 0;
|
|
@@ -1038,10 +1050,10 @@ export default class TopazCubeServer {
|
|
|
1038
1050
|
seq++;
|
|
1039
1051
|
}
|
|
1040
1052
|
|
|
1041
|
-
|
|
1053
|
+
this.log(`RTC: Large message split into ${packages.length} packages`);
|
|
1042
1054
|
} else {
|
|
1043
1055
|
packages = [data]
|
|
1044
|
-
|
|
1056
|
+
this.log(`RTC: Message - ${data.byteLength} bytes`)
|
|
1045
1057
|
}
|
|
1046
1058
|
return packages
|
|
1047
1059
|
}
|
|
@@ -1068,17 +1080,17 @@ export default class TopazCubeServer {
|
|
|
1068
1080
|
this.mongoClient = new MongoClient(this.MongoUrl)
|
|
1069
1081
|
try {
|
|
1070
1082
|
await this.mongoClient.connect()
|
|
1071
|
-
|
|
1083
|
+
this.log('Connected to MongoDB')
|
|
1072
1084
|
const db = this.mongoClient.db(this.database)
|
|
1073
1085
|
this.DB = db
|
|
1074
1086
|
} catch (error) {
|
|
1075
|
-
|
|
1087
|
+
this.error('Error connecting to MongoDB:', error)
|
|
1076
1088
|
this.mongoClient = null
|
|
1077
1089
|
}
|
|
1078
1090
|
}
|
|
1079
1091
|
|
|
1080
1092
|
async _loadDocument(name: string): Promise<void> {
|
|
1081
|
-
|
|
1093
|
+
this.log(`Loading document '${name}' from MongoDB`)
|
|
1082
1094
|
if (this.DB) {
|
|
1083
1095
|
try {
|
|
1084
1096
|
const doc = await this.DB.collection(this.collection).findOne({
|
|
@@ -1089,10 +1101,10 @@ export default class TopazCubeServer {
|
|
|
1089
1101
|
this.documents[name] = doc
|
|
1090
1102
|
}
|
|
1091
1103
|
} catch (error) {
|
|
1092
|
-
|
|
1104
|
+
this.error('Error loading document from MongoDB:', error)
|
|
1093
1105
|
}
|
|
1094
1106
|
} else {
|
|
1095
|
-
|
|
1107
|
+
this.warn('MongoDB client not initialized. Document not loaded.')
|
|
1096
1108
|
}
|
|
1097
1109
|
}
|
|
1098
1110
|
|
|
@@ -1101,18 +1113,18 @@ export default class TopazCubeServer {
|
|
|
1101
1113
|
try {
|
|
1102
1114
|
const doc = this.documents[name]
|
|
1103
1115
|
let newdoc = clonewo_(doc, '__')
|
|
1104
|
-
|
|
1116
|
+
this.log(`Saving document '${name}' to MongoDB`)
|
|
1105
1117
|
await this.DB.collection(this.collection).updateOne(
|
|
1106
1118
|
{ name: name },
|
|
1107
1119
|
{ $set: newdoc },
|
|
1108
1120
|
{ upsert: true }
|
|
1109
1121
|
)
|
|
1110
|
-
|
|
1122
|
+
this.log('Document saved to MongoDB')
|
|
1111
1123
|
} catch (error) {
|
|
1112
|
-
|
|
1124
|
+
this.error('Error saving document to MongoDB:', error)
|
|
1113
1125
|
}
|
|
1114
1126
|
} else {
|
|
1115
|
-
|
|
1127
|
+
this.warn('MongoDB client not initialized. Document not saved.')
|
|
1116
1128
|
}
|
|
1117
1129
|
}
|
|
1118
1130
|
|
|
@@ -1135,7 +1147,7 @@ export default class TopazCubeServer {
|
|
|
1135
1147
|
|
|
1136
1148
|
_exitSignal(signal: string): void {
|
|
1137
1149
|
if (!this._exited) {
|
|
1138
|
-
|
|
1150
|
+
this.log('\nEXIT: Caught interrupt signal ' + signal)
|
|
1139
1151
|
this._exited = true
|
|
1140
1152
|
clearInterval(this._loopiv)
|
|
1141
1153
|
this.onBeforeExit()
|