topazcube 0.1.15 → 0.1.17

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.js CHANGED
@@ -88,9 +88,9 @@ function clonewo_(obj, excludeStart = "_") {
88
88
  }
89
89
  if (obj instanceof Map) {
90
90
  const mapClone = /* @__PURE__ */ new Map();
91
- for (let [key, value] of obj) {
91
+ Array.from(obj.entries()).forEach(([key, value]) => {
92
92
  mapClone.set(clonewo_(key, excludeStart), clonewo_(value, excludeStart));
93
- }
93
+ });
94
94
  return mapClone;
95
95
  }
96
96
  let clone;
@@ -247,6 +247,7 @@ import fastjsonpatch from "fast-json-patch";
247
247
  import { WebSocketServer } from "ws";
248
248
  import { MongoClient } from "mongodb";
249
249
  import { glMatrix } from "gl-matrix";
250
+ import wrtc from "@roamhq/wrtc";
250
251
  glMatrix.setMatrixArrayType(Array);
251
252
  var fastPatchProperties = {
252
253
  "type": true,
@@ -291,6 +292,7 @@ var LITTLE_ENDIAN = (() => {
291
292
  new DataView(buffer).setInt16(0, 256, true);
292
293
  return new Int16Array(buffer)[0] === 256;
293
294
  })();
295
+ var MAX_PACKAGE_SIZE = 65400;
294
296
  var TopazCubeServer = class {
295
297
  name = "TopazCubeServer";
296
298
  cycle = 100;
@@ -584,8 +586,8 @@ var TopazCubeServer = class {
584
586
  client.peerConnection = null;
585
587
  this.log("client connected", client.ID);
586
588
  this.clients.push(client);
587
- client.on("error", () => {
588
- this._onError(client, arguments);
589
+ client.on("error", (...args) => {
590
+ this._onError(client, args);
589
591
  });
590
592
  client.on("message", (message) => {
591
593
  let dec = decode(message);
@@ -922,258 +924,206 @@ var TopazCubeServer = class {
922
924
  e["__changed_" + property] = true;
923
925
  }
924
926
  /*= WEBRTC ===================================================================*/
925
- /*
926
- async _processOffer(client: ClientType, data: any): Promise<void> {
927
- //this.log("RTC: Offer received", data);
928
- const peerConnection = new wrtc.RTCPeerConnection({
929
- iceServers: [
930
- { urls: 'stun:stun.l.google.com:19302' },
931
- { urls: 'stun:stun.cloudflare.com:3478' },
932
- { urls: 'stun:freestun.net:3478' },
933
- ],
934
- iceCandidatePoolSize: 10,
935
- })
936
-
937
- client.peerConnection = peerConnection
938
-
939
- peerConnection.onicecandidate = (event: any) => {
940
- if (event.candidate) {
941
- //this.log("RTC: ICE candidate generated", event.candidate.candidate.substring(0, 50) + "...");
942
- this.send(client, {
943
- c: 'rtc-candidate',
944
- type: 'ice-candidate',
945
- candidate: event.candidate, // .toJSON()
946
- })
947
- } else {
948
- //this.log("RTC: ICE candidate gathering complete");
949
- }
950
- }
951
-
952
- peerConnection.onconnectionstatechange = () => {
953
- //this.log(`RTC: Connection state changed: ${peerConnection.connectionState}`);
954
- if (peerConnection.connectionState === 'connected') {
955
- client.webRTCConnected = true
956
- this.log(`RTC: Connection established with client ${client.ID}`)
957
- } else if (
958
- peerConnection.connectionState === 'failed' ||
959
- peerConnection.connectionState === 'disconnected' ||
960
- peerConnection.connectionState === 'closed'
961
- ) {
962
- client.webRTCConnected = false
963
- this.log(`RTC: Connection failed or closed with client ${client.ID}`)
964
- }
927
+ async _processOffer(client, data) {
928
+ const peerConnection = new wrtc.RTCPeerConnection({
929
+ iceServers: [
930
+ { urls: "stun:stun.l.google.com:19302" },
931
+ { urls: "stun:stun.cloudflare.com:3478" },
932
+ { urls: "stun:freestun.net:3478" }
933
+ ],
934
+ iceCandidatePoolSize: 10
935
+ });
936
+ client.peerConnection = peerConnection;
937
+ peerConnection.onicecandidate = (event) => {
938
+ if (event.candidate) {
939
+ this.send(client, {
940
+ c: "rtc-candidate",
941
+ type: "ice-candidate",
942
+ candidate: event.candidate
943
+ // .toJSON()
944
+ });
945
+ } else {
965
946
  }
966
-
967
- peerConnection.onicegatheringstatechange = () => {
968
- //this.log(`RTC: ICE gathering state: ${peerConnection.iceGatheringState}`);
947
+ };
948
+ peerConnection.onconnectionstatechange = () => {
949
+ if (peerConnection.connectionState === "connected") {
950
+ client.webRTCConnected = true;
951
+ this.log(`RTC: Connection established with client ${client.ID}`);
952
+ } else if (peerConnection.connectionState === "failed" || peerConnection.connectionState === "disconnected" || peerConnection.connectionState === "closed") {
953
+ client.webRTCConnected = false;
954
+ this.log(`RTC: Connection failed or closed with client ${client.ID}`);
969
955
  }
970
-
971
- peerConnection.oniceconnectionstatechange = () => {
972
- //this.log(`RTC: ICE connection state: ${peerConnection.iceConnectionState}`);
973
- if (
974
- peerConnection.iceConnectionState === 'connected' ||
975
- peerConnection.iceConnectionState === 'completed'
976
- ) {
977
- //this.log(`RTC: ICE connection established with client ${client.ID}`);
978
- }
956
+ };
957
+ peerConnection.onicegatheringstatechange = () => {
958
+ };
959
+ peerConnection.oniceconnectionstatechange = () => {
960
+ if (peerConnection.iceConnectionState === "connected" || peerConnection.iceConnectionState === "completed") {
979
961
  }
980
-
981
- try {
982
- await peerConnection.setRemoteDescription(
983
- new wrtc.RTCSessionDescription(data)
984
- )
985
- //this.log("RTC: Remote description set successfully");
986
-
987
- client.dataChannel = peerConnection.createDataChannel('serverchannel', {
988
- ordered: true,
989
- maxRetransmits: 1,
990
- })
991
-
992
- client.dataChannel.onopen = () => {
993
- //this.log(`RTC: Data channel opened for client ${client.ID}`);
994
- // Try sending a test message
995
- try {
996
- const testData = { c: 'test', message: 'Hello WebRTC' }
997
- this.sendRTC(client, testData)
998
- } catch (e) {
999
- this.error(
1000
- `RTC: Error sending test message to client ${client.ID}`,
1001
- e
1002
- )
1003
- }
1004
- }
1005
-
1006
- client.dataChannel.onclose = () => {
1007
- this.log(`RTC: Data channel closed for client ${client.ID}`)
1008
- }
1009
-
1010
- client.dataChannel.onerror = (error: Event) => {
1011
- this.error(`RTC: Data channel error for client ${client.ID}:`, error)
962
+ };
963
+ try {
964
+ await peerConnection.setRemoteDescription(
965
+ new wrtc.RTCSessionDescription(data)
966
+ );
967
+ client.dataChannel = peerConnection.createDataChannel("serverchannel", {
968
+ ordered: true,
969
+ maxRetransmits: 1
970
+ });
971
+ client.dataChannel.onopen = () => {
972
+ try {
973
+ const testData = { c: "test", message: "Hello WebRTC" };
974
+ this.sendRTC(client, testData);
975
+ } catch (e) {
976
+ this.error(
977
+ `RTC: Error sending test message to client ${client.ID}`,
978
+ e
979
+ );
1012
980
  }
1013
-
1014
- client.dataChannel.onmessage = (event: MessageEvent) => {
1015
- try {
1016
- const data = decode(event.data)
1017
- this.log(
1018
- `RTC: Data channel message from client ${client.ID}:`,
1019
- data
1020
- )
1021
- //this.onMessage(client, data);
1022
- } catch (error) {
1023
- this.error(
1024
- `RTC: Error decoding message from client ${client.ID}:`,
1025
- error
1026
- )
1027
- }
981
+ };
982
+ client.dataChannel.onclose = () => {
983
+ this.log(`RTC: Data channel closed for client ${client.ID}`);
984
+ };
985
+ client.dataChannel.onerror = (error) => {
986
+ this.error(`RTC: Data channel error for client ${client.ID}:`, error);
987
+ };
988
+ client.dataChannel.onmessage = (event) => {
989
+ try {
990
+ const data2 = decode(event.data);
991
+ this.log(
992
+ `RTC: Data channel message from client ${client.ID}:`,
993
+ data2
994
+ );
995
+ } catch (error) {
996
+ this.error(
997
+ `RTC: Error decoding message from client ${client.ID}:`,
998
+ error
999
+ );
1028
1000
  }
1029
-
1030
- // Create and send answer
1031
- const answer = await peerConnection.createAnswer()
1032
- await peerConnection.setLocalDescription(answer)
1033
-
1034
- //this.log(`RTC: Sending answer to client ${client.ID}`);
1035
- this.send(client, {
1036
- c: 'rtc-answer',
1037
- type: answer.type,
1038
- sdp: answer.sdp,
1039
- })
1040
- } catch (error) {
1041
- this.error(
1042
- `RTC: Error processing offer from client ${client.ID}:`,
1043
- error
1044
- )
1001
+ };
1002
+ const answer = await peerConnection.createAnswer();
1003
+ await peerConnection.setLocalDescription(answer);
1004
+ this.send(client, {
1005
+ c: "rtc-answer",
1006
+ type: answer.type,
1007
+ sdp: answer.sdp
1008
+ });
1009
+ } catch (error) {
1010
+ this.error(
1011
+ `RTC: Error processing offer from client ${client.ID}:`,
1012
+ error
1013
+ );
1014
+ }
1015
+ }
1016
+ async _processICECandidate(client, data) {
1017
+ try {
1018
+ if (client.peerConnection && data.candidate) {
1019
+ await client.peerConnection.addIceCandidate(
1020
+ data.candidate
1021
+ //new wrtc.RTCIceCandidate(data.candidate)
1022
+ );
1023
+ } else {
1045
1024
  }
1025
+ } catch (error) {
1026
+ this.error(`RTC: Error adding ICE candidate for client ${client.ID}`);
1046
1027
  }
1047
-
1048
- async _processICECandidate(client: ClientType, data: any): Promise<void> {
1049
- //this.log(`RTC: Processing ICE candidate from client ${client.ID}`);
1050
- try {
1051
- if (client.peerConnection && data.candidate) {
1052
- await client.peerConnection.addIceCandidate(
1053
- data.candidate
1054
- //new wrtc.RTCIceCandidate(data.candidate)
1055
- )
1056
- //this.log(`RTC: ICE candidate added successfully for client ${client.ID}`);
1057
- } else {
1058
- //this.warn(`RTC: Cannot add ICE candidate for client ${client.ID} - peerConnection not ready or candidate missing`);
1028
+ }
1029
+ _clientRTCOpen(client) {
1030
+ return client.dataChannel !== null && client.dataChannel !== void 0 && client.dataChannel.readyState === "open";
1031
+ }
1032
+ async sendRTC(client, message) {
1033
+ let data = encode(message);
1034
+ if (this.allowCompression) {
1035
+ data = await compress(data);
1036
+ }
1037
+ this.stats.sendRTC += data.byteLength;
1038
+ this.stats._sendRTCUpdate += data.byteLength;
1039
+ let packages = this._splitRTCMessage(data);
1040
+ if (this.simulateLatency) {
1041
+ setTimeout(() => {
1042
+ if (this._clientRTCOpen(client)) {
1043
+ packages.forEach((p) => {
1044
+ client.dataChannel.send(p);
1045
+ });
1059
1046
  }
1060
- } catch (error) {
1061
- this.error(`RTC: Error adding ICE candidate for client ${client.ID}`)
1047
+ }, this.simulateLatency);
1048
+ } else {
1049
+ if (this._clientRTCOpen(client)) {
1050
+ packages.forEach((p) => {
1051
+ client.dataChannel.send(p);
1052
+ });
1062
1053
  }
1063
1054
  }
1064
-
1065
- _clientRTCOpen(client: ClientType): boolean {
1066
- return client.dataChannel !== null && client.dataChannel !== undefined && client.dataChannel.readyState === 'open'
1055
+ }
1056
+ async broadcastRTC(message, clients = []) {
1057
+ if (clients.length == 0) {
1058
+ clients = this.clients;
1067
1059
  }
1068
-
1069
- async sendRTC(client: ClientType, message: any): Promise<void> {
1070
- let data = encode(message)
1071
- if (this.allowCompression) {
1072
- data = await compress(data)
1073
- }
1074
- this.stats.sendRTC += data.byteLength
1075
- this.stats._sendRTCUpdate += data.byteLength
1076
-
1077
- let packages = this._splitRTCMessage(data)
1078
-
1060
+ let t1 = Date.now();
1061
+ let data = encode(message);
1062
+ let dl = data.byteLength;
1063
+ let t2 = Date.now();
1064
+ if (this.allowCompression) {
1065
+ data = await compress(data);
1066
+ }
1067
+ let t3 = Date.now();
1068
+ if (data.length > 16384) {
1069
+ this.log(`BroadcastRTC message ${dl} -> ${data.length} (${(100 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`);
1070
+ }
1071
+ let packages = this._splitRTCMessage(data);
1072
+ for (let client of this.clients) {
1073
+ this.stats.sendRTC += data.byteLength;
1074
+ this.stats._sendRTCUpdate += data.byteLength;
1079
1075
  if (this.simulateLatency) {
1080
1076
  setTimeout(() => {
1081
- if (this._clientRTCOpen(client)) {
1077
+ if (client.dataChannel && client.dataChannel.readyState === "open") {
1082
1078
  packages.forEach((p) => {
1083
- client.dataChannel!.send(p)
1084
- })
1079
+ client?.dataChannel?.send(p);
1080
+ });
1085
1081
  }
1086
- }, this.simulateLatency)
1082
+ }, this.simulateLatency);
1087
1083
  } else {
1088
- if (this._clientRTCOpen(client)) {
1084
+ if (client.dataChannel && client.dataChannel.readyState === "open") {
1089
1085
  packages.forEach((p) => {
1090
- client.dataChannel!.send(p)
1091
- })
1086
+ client?.dataChannel?.send(p);
1087
+ });
1092
1088
  }
1093
1089
  }
1094
1090
  }
1095
-
1096
- async broadcastRTC(message: any, clients: ClientType[] = []): Promise<void> {
1097
- if (clients.length == 0) {
1098
- clients = this.clients
1099
- }
1100
- let t1 = Date.now()
1101
- let data = encode(message)
1102
- let dl = data.byteLength
1103
- let t2 = Date.now()
1104
- if (this.allowCompression) {
1105
- data = await compress(data)
1106
- }
1107
- let t3 = Date.now()
1108
-
1109
-
1110
- if (data.length > 16384) {
1111
- this.log(`BroadcastRTC message ${dl} -> ${data.length} (${(100.0 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`)
1112
- }
1113
-
1114
- let packages = this._splitRTCMessage(data)
1115
-
1116
- for (let client of this.clients) {
1117
- this.stats.sendRTC += data.byteLength
1118
- this.stats._sendRTCUpdate += data.byteLength
1119
- if (this.simulateLatency) {
1120
- setTimeout(() => {
1121
- if (client.dataChannel && client.dataChannel.readyState === 'open') {
1122
- packages.forEach((p) => {
1123
- client?.dataChannel?.send(p)
1124
- })
1125
- }
1126
- }, this.simulateLatency)
1127
- } else {
1128
- if (client.dataChannel && client.dataChannel.readyState === 'open') {
1129
- packages.forEach((p) => {
1130
- client?.dataChannel?.send(p)
1131
- })
1132
- }
1133
- }
1134
- }
1135
- }
1136
-
1137
- _splitRTCMessage(data: Uint8Array): Uint8Array[] {
1138
- let packages: Uint8Array[]
1139
- if (data.byteLength > 65535) {
1140
- const now = Date.now()
1141
- this.warn(`RTC: Message too large: ${data.byteLength} bytes`)
1142
- // Split the message into smaller packages
1143
- packages = [];
1144
- let offset = 0;
1145
- let mid = this.update +'-'+ now
1146
- let seq = 0
1147
-
1148
- // Create subsequent packages if needed
1149
- while (offset < data.byteLength) {
1150
- const remaining = data.byteLength - offset;
1151
- const chunkSize = Math.min(remaining, MAX_PACKAGE_SIZE);
1152
- const chunk = new Uint8Array(data.buffer, offset, chunkSize);
1153
- let cmessage = {
1154
- c: 'chunk',
1155
- t: now,
1156
- mid: mid,
1157
- seq: seq,
1158
- ofs: offset,
1159
- chs: chunkSize,
1160
- ts: data.byteLength,
1161
- data: chunk,
1162
- last: remaining <= MAX_PACKAGE_SIZE,
1163
- }
1164
- packages.push(encode(cmessage))
1165
- offset += chunkSize;
1166
- seq++;
1167
- }
1168
-
1169
- this.log(`RTC: Large message split into ${packages.length} packages`);
1170
- } else {
1171
- packages = [data]
1172
- this.log(`RTC: Message - ${data.byteLength} bytes`)
1091
+ }
1092
+ _splitRTCMessage(data) {
1093
+ let packages;
1094
+ if (data.byteLength > 65535) {
1095
+ const now = Date.now();
1096
+ this.warn(`RTC: Message too large: ${data.byteLength} bytes`);
1097
+ packages = [];
1098
+ let offset = 0;
1099
+ let mid = this.update + "-" + now;
1100
+ let seq = 0;
1101
+ while (offset < data.byteLength) {
1102
+ const remaining = data.byteLength - offset;
1103
+ const chunkSize = Math.min(remaining, MAX_PACKAGE_SIZE);
1104
+ const chunk = new Uint8Array(data.buffer, offset, chunkSize);
1105
+ let cmessage = {
1106
+ c: "chunk",
1107
+ t: now,
1108
+ mid,
1109
+ seq,
1110
+ ofs: offset,
1111
+ chs: chunkSize,
1112
+ ts: data.byteLength,
1113
+ data: chunk,
1114
+ last: remaining <= MAX_PACKAGE_SIZE
1115
+ };
1116
+ packages.push(encode(cmessage));
1117
+ offset += chunkSize;
1118
+ seq++;
1173
1119
  }
1174
- return packages
1120
+ this.log(`RTC: Large message split into ${packages.length} packages`);
1121
+ } else {
1122
+ packages = [data];
1123
+ this.log(`RTC: Message - ${data.byteLength} bytes`);
1175
1124
  }
1176
- */
1125
+ return packages;
1126
+ }
1177
1127
  /*= DATABASE =================================================================*/
1178
1128
  // properties (of the documents) that starts with __ are not saved to the database.
1179
1129
  // __properties are restored on hydration. (for example __physicsBody or __bigObject)