topazcube 0.1.14 → 0.1.16

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 CHANGED
@@ -122,9 +122,9 @@ function clonewo_(obj, excludeStart = "_") {
122
122
  }
123
123
  if (obj instanceof Map) {
124
124
  const mapClone = /* @__PURE__ */ new Map();
125
- for (let [key, value] of obj) {
125
+ Array.from(obj.entries()).forEach(([key, value]) => {
126
126
  mapClone.set(clonewo_(key, excludeStart), clonewo_(value, excludeStart));
127
- }
127
+ });
128
128
  return mapClone;
129
129
  }
130
130
  let clone;
@@ -282,6 +282,7 @@ var import_ws = require("ws");
282
282
  var import_mongodb = require("mongodb");
283
283
  var import_gl_matrix = require("gl-matrix");
284
284
  import_gl_matrix.glMatrix.setMatrixArrayType(Array);
285
+ var wrtc = require("@roamhq/wrtc");
285
286
  var fastPatchProperties = {
286
287
  "type": true,
287
288
  // string 'enemy'
@@ -325,6 +326,7 @@ var LITTLE_ENDIAN = (() => {
325
326
  new DataView(buffer).setInt16(0, 256, true);
326
327
  return new Int16Array(buffer)[0] === 256;
327
328
  })();
329
+ var MAX_PACKAGE_SIZE = 65400;
328
330
  var TopazCubeServer = class {
329
331
  name = "TopazCubeServer";
330
332
  cycle = 100;
@@ -618,8 +620,8 @@ var TopazCubeServer = class {
618
620
  client.peerConnection = null;
619
621
  this.log("client connected", client.ID);
620
622
  this.clients.push(client);
621
- client.on("error", () => {
622
- this._onError(client, arguments);
623
+ client.on("error", (...args) => {
624
+ this._onError(client, args);
623
625
  });
624
626
  client.on("message", (message) => {
625
627
  let dec = decode(message);
@@ -956,258 +958,206 @@ var TopazCubeServer = class {
956
958
  e["__changed_" + property] = true;
957
959
  }
958
960
  /*= WEBRTC ===================================================================*/
959
- /*
960
- async _processOffer(client: ClientType, data: any): Promise<void> {
961
- //this.log("RTC: Offer received", data);
962
- const peerConnection = new wrtc.RTCPeerConnection({
963
- iceServers: [
964
- { urls: 'stun:stun.l.google.com:19302' },
965
- { urls: 'stun:stun.cloudflare.com:3478' },
966
- { urls: 'stun:freestun.net:3478' },
967
- ],
968
- iceCandidatePoolSize: 10,
969
- })
970
-
971
- client.peerConnection = peerConnection
972
-
973
- peerConnection.onicecandidate = (event: any) => {
974
- if (event.candidate) {
975
- //this.log("RTC: ICE candidate generated", event.candidate.candidate.substring(0, 50) + "...");
976
- this.send(client, {
977
- c: 'rtc-candidate',
978
- type: 'ice-candidate',
979
- candidate: event.candidate, // .toJSON()
980
- })
981
- } else {
982
- //this.log("RTC: ICE candidate gathering complete");
983
- }
984
- }
985
-
986
- peerConnection.onconnectionstatechange = () => {
987
- //this.log(`RTC: Connection state changed: ${peerConnection.connectionState}`);
988
- if (peerConnection.connectionState === 'connected') {
989
- client.webRTCConnected = true
990
- this.log(`RTC: Connection established with client ${client.ID}`)
991
- } else if (
992
- peerConnection.connectionState === 'failed' ||
993
- peerConnection.connectionState === 'disconnected' ||
994
- peerConnection.connectionState === 'closed'
995
- ) {
996
- client.webRTCConnected = false
997
- this.log(`RTC: Connection failed or closed with client ${client.ID}`)
998
- }
961
+ async _processOffer(client, data) {
962
+ const peerConnection = new wrtc.RTCPeerConnection({
963
+ iceServers: [
964
+ { urls: "stun:stun.l.google.com:19302" },
965
+ { urls: "stun:stun.cloudflare.com:3478" },
966
+ { urls: "stun:freestun.net:3478" }
967
+ ],
968
+ iceCandidatePoolSize: 10
969
+ });
970
+ client.peerConnection = peerConnection;
971
+ peerConnection.onicecandidate = (event) => {
972
+ if (event.candidate) {
973
+ this.send(client, {
974
+ c: "rtc-candidate",
975
+ type: "ice-candidate",
976
+ candidate: event.candidate
977
+ // .toJSON()
978
+ });
979
+ } else {
999
980
  }
1000
-
1001
- peerConnection.onicegatheringstatechange = () => {
1002
- //this.log(`RTC: ICE gathering state: ${peerConnection.iceGatheringState}`);
981
+ };
982
+ peerConnection.onconnectionstatechange = () => {
983
+ if (peerConnection.connectionState === "connected") {
984
+ client.webRTCConnected = true;
985
+ this.log(`RTC: Connection established with client ${client.ID}`);
986
+ } else if (peerConnection.connectionState === "failed" || peerConnection.connectionState === "disconnected" || peerConnection.connectionState === "closed") {
987
+ client.webRTCConnected = false;
988
+ this.log(`RTC: Connection failed or closed with client ${client.ID}`);
1003
989
  }
1004
-
1005
- peerConnection.oniceconnectionstatechange = () => {
1006
- //this.log(`RTC: ICE connection state: ${peerConnection.iceConnectionState}`);
1007
- if (
1008
- peerConnection.iceConnectionState === 'connected' ||
1009
- peerConnection.iceConnectionState === 'completed'
1010
- ) {
1011
- //this.log(`RTC: ICE connection established with client ${client.ID}`);
1012
- }
990
+ };
991
+ peerConnection.onicegatheringstatechange = () => {
992
+ };
993
+ peerConnection.oniceconnectionstatechange = () => {
994
+ if (peerConnection.iceConnectionState === "connected" || peerConnection.iceConnectionState === "completed") {
1013
995
  }
1014
-
1015
- try {
1016
- await peerConnection.setRemoteDescription(
1017
- new wrtc.RTCSessionDescription(data)
1018
- )
1019
- //this.log("RTC: Remote description set successfully");
1020
-
1021
- client.dataChannel = peerConnection.createDataChannel('serverchannel', {
1022
- ordered: true,
1023
- maxRetransmits: 1,
1024
- })
1025
-
1026
- client.dataChannel.onopen = () => {
1027
- //this.log(`RTC: Data channel opened for client ${client.ID}`);
1028
- // Try sending a test message
1029
- try {
1030
- const testData = { c: 'test', message: 'Hello WebRTC' }
1031
- this.sendRTC(client, testData)
1032
- } catch (e) {
1033
- this.error(
1034
- `RTC: Error sending test message to client ${client.ID}`,
1035
- e
1036
- )
1037
- }
1038
- }
1039
-
1040
- client.dataChannel.onclose = () => {
1041
- this.log(`RTC: Data channel closed for client ${client.ID}`)
1042
- }
1043
-
1044
- client.dataChannel.onerror = (error: Event) => {
1045
- this.error(`RTC: Data channel error for client ${client.ID}:`, error)
996
+ };
997
+ try {
998
+ await peerConnection.setRemoteDescription(
999
+ new wrtc.RTCSessionDescription(data)
1000
+ );
1001
+ client.dataChannel = peerConnection.createDataChannel("serverchannel", {
1002
+ ordered: true,
1003
+ maxRetransmits: 1
1004
+ });
1005
+ client.dataChannel.onopen = () => {
1006
+ try {
1007
+ const testData = { c: "test", message: "Hello WebRTC" };
1008
+ this.sendRTC(client, testData);
1009
+ } catch (e) {
1010
+ this.error(
1011
+ `RTC: Error sending test message to client ${client.ID}`,
1012
+ e
1013
+ );
1046
1014
  }
1047
-
1048
- client.dataChannel.onmessage = (event: MessageEvent) => {
1049
- try {
1050
- const data = decode(event.data)
1051
- this.log(
1052
- `RTC: Data channel message from client ${client.ID}:`,
1053
- data
1054
- )
1055
- //this.onMessage(client, data);
1056
- } catch (error) {
1057
- this.error(
1058
- `RTC: Error decoding message from client ${client.ID}:`,
1059
- error
1060
- )
1061
- }
1015
+ };
1016
+ client.dataChannel.onclose = () => {
1017
+ this.log(`RTC: Data channel closed for client ${client.ID}`);
1018
+ };
1019
+ client.dataChannel.onerror = (error) => {
1020
+ this.error(`RTC: Data channel error for client ${client.ID}:`, error);
1021
+ };
1022
+ client.dataChannel.onmessage = (event) => {
1023
+ try {
1024
+ const data2 = decode(event.data);
1025
+ this.log(
1026
+ `RTC: Data channel message from client ${client.ID}:`,
1027
+ data2
1028
+ );
1029
+ } catch (error) {
1030
+ this.error(
1031
+ `RTC: Error decoding message from client ${client.ID}:`,
1032
+ error
1033
+ );
1062
1034
  }
1063
-
1064
- // Create and send answer
1065
- const answer = await peerConnection.createAnswer()
1066
- await peerConnection.setLocalDescription(answer)
1067
-
1068
- //this.log(`RTC: Sending answer to client ${client.ID}`);
1069
- this.send(client, {
1070
- c: 'rtc-answer',
1071
- type: answer.type,
1072
- sdp: answer.sdp,
1073
- })
1074
- } catch (error) {
1075
- this.error(
1076
- `RTC: Error processing offer from client ${client.ID}:`,
1077
- error
1078
- )
1035
+ };
1036
+ const answer = await peerConnection.createAnswer();
1037
+ await peerConnection.setLocalDescription(answer);
1038
+ this.send(client, {
1039
+ c: "rtc-answer",
1040
+ type: answer.type,
1041
+ sdp: answer.sdp
1042
+ });
1043
+ } catch (error) {
1044
+ this.error(
1045
+ `RTC: Error processing offer from client ${client.ID}:`,
1046
+ error
1047
+ );
1048
+ }
1049
+ }
1050
+ async _processICECandidate(client, data) {
1051
+ try {
1052
+ if (client.peerConnection && data.candidate) {
1053
+ await client.peerConnection.addIceCandidate(
1054
+ data.candidate
1055
+ //new wrtc.RTCIceCandidate(data.candidate)
1056
+ );
1057
+ } else {
1079
1058
  }
1059
+ } catch (error) {
1060
+ this.error(`RTC: Error adding ICE candidate for client ${client.ID}`);
1080
1061
  }
1081
-
1082
- async _processICECandidate(client: ClientType, data: any): Promise<void> {
1083
- //this.log(`RTC: Processing ICE candidate from client ${client.ID}`);
1084
- try {
1085
- if (client.peerConnection && data.candidate) {
1086
- await client.peerConnection.addIceCandidate(
1087
- data.candidate
1088
- //new wrtc.RTCIceCandidate(data.candidate)
1089
- )
1090
- //this.log(`RTC: ICE candidate added successfully for client ${client.ID}`);
1091
- } else {
1092
- //this.warn(`RTC: Cannot add ICE candidate for client ${client.ID} - peerConnection not ready or candidate missing`);
1062
+ }
1063
+ _clientRTCOpen(client) {
1064
+ return client.dataChannel !== null && client.dataChannel !== void 0 && client.dataChannel.readyState === "open";
1065
+ }
1066
+ async sendRTC(client, message) {
1067
+ let data = encode(message);
1068
+ if (this.allowCompression) {
1069
+ data = await compress(data);
1070
+ }
1071
+ this.stats.sendRTC += data.byteLength;
1072
+ this.stats._sendRTCUpdate += data.byteLength;
1073
+ let packages = this._splitRTCMessage(data);
1074
+ if (this.simulateLatency) {
1075
+ setTimeout(() => {
1076
+ if (this._clientRTCOpen(client)) {
1077
+ packages.forEach((p) => {
1078
+ client.dataChannel.send(p);
1079
+ });
1093
1080
  }
1094
- } catch (error) {
1095
- this.error(`RTC: Error adding ICE candidate for client ${client.ID}`)
1081
+ }, this.simulateLatency);
1082
+ } else {
1083
+ if (this._clientRTCOpen(client)) {
1084
+ packages.forEach((p) => {
1085
+ client.dataChannel.send(p);
1086
+ });
1096
1087
  }
1097
1088
  }
1098
-
1099
- _clientRTCOpen(client: ClientType): boolean {
1100
- return client.dataChannel !== null && client.dataChannel !== undefined && client.dataChannel.readyState === 'open'
1089
+ }
1090
+ async broadcastRTC(message, clients = []) {
1091
+ if (clients.length == 0) {
1092
+ clients = this.clients;
1101
1093
  }
1102
-
1103
- async sendRTC(client: ClientType, message: any): Promise<void> {
1104
- let data = encode(message)
1105
- if (this.allowCompression) {
1106
- data = await compress(data)
1107
- }
1108
- this.stats.sendRTC += data.byteLength
1109
- this.stats._sendRTCUpdate += data.byteLength
1110
-
1111
- let packages = this._splitRTCMessage(data)
1112
-
1094
+ let t1 = Date.now();
1095
+ let data = encode(message);
1096
+ let dl = data.byteLength;
1097
+ let t2 = Date.now();
1098
+ if (this.allowCompression) {
1099
+ data = await compress(data);
1100
+ }
1101
+ let t3 = Date.now();
1102
+ if (data.length > 16384) {
1103
+ this.log(`BroadcastRTC message ${dl} -> ${data.length} (${(100 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`);
1104
+ }
1105
+ let packages = this._splitRTCMessage(data);
1106
+ for (let client of this.clients) {
1107
+ this.stats.sendRTC += data.byteLength;
1108
+ this.stats._sendRTCUpdate += data.byteLength;
1113
1109
  if (this.simulateLatency) {
1114
1110
  setTimeout(() => {
1115
- if (this._clientRTCOpen(client)) {
1111
+ if (client.dataChannel && client.dataChannel.readyState === "open") {
1116
1112
  packages.forEach((p) => {
1117
- client.dataChannel!.send(p)
1118
- })
1113
+ client?.dataChannel?.send(p);
1114
+ });
1119
1115
  }
1120
- }, this.simulateLatency)
1116
+ }, this.simulateLatency);
1121
1117
  } else {
1122
- if (this._clientRTCOpen(client)) {
1118
+ if (client.dataChannel && client.dataChannel.readyState === "open") {
1123
1119
  packages.forEach((p) => {
1124
- client.dataChannel!.send(p)
1125
- })
1120
+ client?.dataChannel?.send(p);
1121
+ });
1126
1122
  }
1127
1123
  }
1128
1124
  }
1129
-
1130
- async broadcastRTC(message: any, clients: ClientType[] = []): Promise<void> {
1131
- if (clients.length == 0) {
1132
- clients = this.clients
1133
- }
1134
- let t1 = Date.now()
1135
- let data = encode(message)
1136
- let dl = data.byteLength
1137
- let t2 = Date.now()
1138
- if (this.allowCompression) {
1139
- data = await compress(data)
1140
- }
1141
- let t3 = Date.now()
1142
-
1143
-
1144
- if (data.length > 16384) {
1145
- this.log(`BroadcastRTC message ${dl} -> ${data.length} (${(100.0 * data.length / dl).toFixed()}%) encoding:${t2 - t1}ms compression:${t3 - t1}ms`)
1146
- }
1147
-
1148
- let packages = this._splitRTCMessage(data)
1149
-
1150
- for (let client of this.clients) {
1151
- this.stats.sendRTC += data.byteLength
1152
- this.stats._sendRTCUpdate += data.byteLength
1153
- if (this.simulateLatency) {
1154
- setTimeout(() => {
1155
- if (client.dataChannel && client.dataChannel.readyState === 'open') {
1156
- packages.forEach((p) => {
1157
- client?.dataChannel?.send(p)
1158
- })
1159
- }
1160
- }, this.simulateLatency)
1161
- } else {
1162
- if (client.dataChannel && client.dataChannel.readyState === 'open') {
1163
- packages.forEach((p) => {
1164
- client?.dataChannel?.send(p)
1165
- })
1166
- }
1167
- }
1168
- }
1169
- }
1170
-
1171
- _splitRTCMessage(data: Uint8Array): Uint8Array[] {
1172
- let packages: Uint8Array[]
1173
- if (data.byteLength > 65535) {
1174
- const now = Date.now()
1175
- this.warn(`RTC: Message too large: ${data.byteLength} bytes`)
1176
- // Split the message into smaller packages
1177
- packages = [];
1178
- let offset = 0;
1179
- let mid = this.update +'-'+ now
1180
- let seq = 0
1181
-
1182
- // Create subsequent packages if needed
1183
- while (offset < data.byteLength) {
1184
- const remaining = data.byteLength - offset;
1185
- const chunkSize = Math.min(remaining, MAX_PACKAGE_SIZE);
1186
- const chunk = new Uint8Array(data.buffer, offset, chunkSize);
1187
- let cmessage = {
1188
- c: 'chunk',
1189
- t: now,
1190
- mid: mid,
1191
- seq: seq,
1192
- ofs: offset,
1193
- chs: chunkSize,
1194
- ts: data.byteLength,
1195
- data: chunk,
1196
- last: remaining <= MAX_PACKAGE_SIZE,
1197
- }
1198
- packages.push(encode(cmessage))
1199
- offset += chunkSize;
1200
- seq++;
1201
- }
1202
-
1203
- this.log(`RTC: Large message split into ${packages.length} packages`);
1204
- } else {
1205
- packages = [data]
1206
- this.log(`RTC: Message - ${data.byteLength} bytes`)
1125
+ }
1126
+ _splitRTCMessage(data) {
1127
+ let packages;
1128
+ if (data.byteLength > 65535) {
1129
+ const now = Date.now();
1130
+ this.warn(`RTC: Message too large: ${data.byteLength} bytes`);
1131
+ packages = [];
1132
+ let offset = 0;
1133
+ let mid = this.update + "-" + now;
1134
+ let seq = 0;
1135
+ while (offset < data.byteLength) {
1136
+ const remaining = data.byteLength - offset;
1137
+ const chunkSize = Math.min(remaining, MAX_PACKAGE_SIZE);
1138
+ const chunk = new Uint8Array(data.buffer, offset, chunkSize);
1139
+ let cmessage = {
1140
+ c: "chunk",
1141
+ t: now,
1142
+ mid,
1143
+ seq,
1144
+ ofs: offset,
1145
+ chs: chunkSize,
1146
+ ts: data.byteLength,
1147
+ data: chunk,
1148
+ last: remaining <= MAX_PACKAGE_SIZE
1149
+ };
1150
+ packages.push(encode(cmessage));
1151
+ offset += chunkSize;
1152
+ seq++;
1207
1153
  }
1208
- return packages
1154
+ this.log(`RTC: Large message split into ${packages.length} packages`);
1155
+ } else {
1156
+ packages = [data];
1157
+ this.log(`RTC: Message - ${data.byteLength} bytes`);
1209
1158
  }
1210
- */
1159
+ return packages;
1160
+ }
1211
1161
  /*= DATABASE =================================================================*/
1212
1162
  // properties (of the documents) that starts with __ are not saved to the database.
1213
1163
  // __properties are restored on hydration. (for example __physicsBody or __bigObject)