sonic-ws 1.3.2 → 1.3.3

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.
Files changed (46) hide show
  1. package/dist/index.d.ts +0 -4
  2. package/dist/version.d.ts +1 -5
  3. package/dist/version.js +23 -4
  4. package/dist/ws/Connection.d.ts +0 -4
  5. package/dist/ws/Connection.js +124 -4
  6. package/dist/ws/PacketProcessor.d.ts +0 -4
  7. package/dist/ws/PacketProcessor.js +50 -4
  8. package/dist/ws/client/core/ClientCore.d.ts +0 -4
  9. package/dist/ws/client/core/ClientCore.js +249 -4
  10. package/dist/ws/client/node/ClientNode.d.ts +0 -4
  11. package/dist/ws/client/node/ClientNode.js +34 -4
  12. package/dist/ws/debug/DebugServer.d.ts +0 -4
  13. package/dist/ws/debug/DebugServer.js +605 -4
  14. package/dist/ws/packets/PacketProcessors.d.ts +0 -4
  15. package/dist/ws/packets/PacketProcessors.js +315 -4
  16. package/dist/ws/packets/PacketType.d.ts +0 -4
  17. package/dist/ws/packets/PacketType.js +59 -4
  18. package/dist/ws/packets/Packets.d.ts +0 -4
  19. package/dist/ws/packets/Packets.js +275 -4
  20. package/dist/ws/server/SonicWSConnection.d.ts +0 -4
  21. package/dist/ws/server/SonicWSConnection.js +296 -4
  22. package/dist/ws/server/SonicWSServer.d.ts +1 -5
  23. package/dist/ws/server/SonicWSServer.js +305 -4
  24. package/dist/ws/util/BufferUtil.d.ts +0 -4
  25. package/dist/ws/util/BufferUtil.js +40 -4
  26. package/dist/ws/util/StringUtil.d.ts +0 -4
  27. package/dist/ws/util/StringUtil.js +49 -4
  28. package/dist/ws/util/enums/EnumHandler.d.ts +0 -4
  29. package/dist/ws/util/enums/EnumHandler.js +58 -4
  30. package/dist/ws/util/enums/EnumType.d.ts +0 -4
  31. package/dist/ws/util/enums/EnumType.js +70 -4
  32. package/dist/ws/util/packets/BatchHelper.d.ts +0 -4
  33. package/dist/ws/util/packets/BatchHelper.js +83 -4
  34. package/dist/ws/util/packets/CompressionUtil.d.ts +5 -9
  35. package/dist/ws/util/packets/CompressionUtil.js +275 -4
  36. package/dist/ws/util/packets/HashUtil.d.ts +0 -4
  37. package/dist/ws/util/packets/HashUtil.js +120 -4
  38. package/dist/ws/util/packets/JSONUtil.d.ts +0 -4
  39. package/dist/ws/util/packets/JSONUtil.js +177 -4
  40. package/dist/ws/util/packets/PacketHolder.d.ts +0 -4
  41. package/dist/ws/util/packets/PacketHolder.js +124 -4
  42. package/dist/ws/util/packets/PacketUtils.d.ts +0 -4
  43. package/dist/ws/util/packets/PacketUtils.js +281 -4
  44. package/dist/ws/util/packets/RateHandler.d.ts +0 -4
  45. package/dist/ws/util/packets/RateHandler.js +64 -4
  46. package/package.json +3 -3
@@ -1,6 +1,607 @@
1
- /**
1
+ "use strict";
2
+ /*
2
3
  * Copyright 2026 Lily (liwybloc)
3
- * Licensed under the Apache License, Version 2.0.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
4
16
  */
5
-
6
- var e=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DebugServer=void 0;const t=require("../Connection"),o=require("../packets/PacketType"),s=require("../server/SonicWSServer"),n=require("../util/packets/PacketUtils"),a=e(require("http")),c=e(require("open")),d=require("../util/enums/EnumHandler");exports.DebugServer=class{constructor(e,i){if(i.port??=0,i.password??="",i.port<0||i.port>=65536)throw new Error("Port out of range!");const l=a.default.createServer((e,t)=>{t.writeHead(200,{"Content-Type":"text/html"}),t.end('<!doctypehtml><meta charset=UTF-8><script src=https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/bundled/SonicWS_bundle.js><\/script><title>SonicWS Debug Menu</title><style>body{margin:0;font-family:Inter,Arial,sans-serif;background:#0f1115;color:#e6e6e6;height:100vh;display:flex}#sidebar{width:260px;background:#141821;border-right:1px solid #1f2533;display:flex;flex-direction:column}#sidebar-header{padding:16px;font-weight:600;font-size:18px;border-bottom:1px solid #1f2533;cursor:pointer;transition:color .2s}#sidebar-header:hover{color:#ddd}#socket-list{flex:1;overflow-y:auto}.socket-item{padding:10px 14px;cursor:pointer;border-bottom:1px solid #1f2533}.socket-item:hover{background:#1b2030}.socket-item.active{background:#22294a}.socket-id{font-size:12px;opacity:.7}#main{flex:1;display:flex;flex-direction:column}#main-header{padding:17px;border-bottom:1px solid #1f2533;display:flex;justify-content:space-between;align-items:center}#stats{display:flex;gap:20px;font-size:13px}#packets{flex:1;overflow-y:auto;padding:12px}.packet{background:#1a1f2e;border-radius:6px;padding:6px 8px;margin-bottom:4px;font-size:12px;cursor:pointer}.packet.sent{border-left:3px solid #3cff7a}.packet.recv{border-left:3px solid #ff5a5a}.packet-details{display:none;margin-top:4px;opacity:.75;font-size:11px}.packet.expanded .packet-details{display:block}button{background:0 0}</style><div id=sidebar><div id=sidebar-header>Sonic WS Debug Menu</div><div id=socket-list></div></div><div id=main><div id=main-header><button id=close-socket style=display:none>❌</button><div id=socket-title>Server Home</div><div id=stats></div></div><div id=home style=display:block;padding:16px><h2>Server Dashboard</h2><div id=global-stats style=margin-bottom:16px></div><h3>Connection Logs</h3><ul id=connection-logs style=max-height:200px;overflow-y:auto;padding-left:16px></ul><div style=margin-top:16px><table style=width:100%;border-collapse:collapse><thead><tr><th style="border-bottom:1px solid #444;text-align:left">Socket ID<th style="border-bottom:1px solid #444;text-align:left">Name<th style="border-bottom:1px solid #444;text-align:left">Status<tbody id=connection-table></table></div></div><div id=packets></div></div><script>const socketList=document.getElementById("socket-list"),packetsDiv=document.getElementById("packets"),socketTitle=document.getElementById("socket-title"),debugTitle=document.getElementById("sidebar-header"),statsDiv=document.getElementById("stats"),home=document.getElementById("home"),closeSocketBtn=document.getElementById("close-socket");debugTitle.onclick=()=>{null!==activeId&&(activeId=null,packetsDiv.style.display="none",home.style.display="block",closeSocketBtn.style.display="none",renderGlobalStats())};const globalStats={totalSockets:0,totalSent:0,totalRecv:0,totalSentBytes:0,totalRecvBytes:0,totalSaved:0,startTime:0};function formatMilliseconds(e){if(e<1)return"0.0s";const t=[{label:"week",value:6048e5},{label:"day",value:864e5},{label:"hour",value:36e5},{label:"minute",value:6e4}],s=[];for(const{label:o,value:n}of t){const t=Math.floor(e/n);t>0&&(s.push(t+" "+o+(1!==t?"s":"")),e-=t*n)}if(e>0||0===s.length){const t=(e/1e3).toFixed(1);s.push(t+"s")}if(1===s.length)return s[0];const o=s.pop();return s.join(", ")+" and "+o}const globalStatsDiv=document.getElementById("global-stats");function renderGlobalStats(){const e=globalStats,t=formatMilliseconds(Date.now()-e.startTime);globalStatsDiv.innerHTML="<div><strong>Total Sockets:</strong> "+e.totalSockets+"</div><div><strong>Total Sent Packets:</strong> "+e.totalSent+"</div><div><strong>Total Received Packets:</strong> "+e.totalRecv+"</div><div><strong>Total Sent Bytes:</strong> "+e.totalSentBytes+" B</div><div><strong>Total Received Bytes:</strong> "+e.totalRecvBytes+" B</div><div><strong>Total Bandwidth Saved:</strong> "+e.totalSaved+" B</div><div><strong>Uptime:</strong> "+t+"</div>"}function updateConnectionTable(){const e=document.getElementById("connection-table");e.innerHTML="",sockets.forEach((t=>{const s=document.createElement("tr");s.innerHTML="<td>"+t.id+"</td><td>"+t.name+\'</td><td style="color:\'+(t.el.style.color||"#0f0")+\'">\'+("#f00"===t.el.style.color?"Disconnected":"Connected")+"</td>",e.appendChild(s)}))}setInterval(renderGlobalStats,50),setInterval(updateConnectionTable,1e3);const sockets=new Map;let activeId=null;function selectSocket(e){activeId=e,[...socketList.children].forEach((t=>t.classList.toggle("active",t.dataset.id==e)));const t=sockets.get(e);socketTitle.textContent=t.name,packetsDiv.innerHTML="",t.packets.forEach((e=>packetsDiv.appendChild(e.el))),renderStats(t),home.style.display="none",packetsDiv.style.display="block",closeSocketBtn.style.display="block"}function renderStats(e){statsDiv.innerHTML="<div>Sent: "+e.sent+"</div><div>Recv: "+e.recv+"</div><div>Sent bytes: "+e.sentBytes+"</div><div>Recv bytes: "+e.recvBytes+"</div><div>Saved: "+e.saved+"</div>"}function addSocket(e,t){const s=document.createElement("div");s.className="socket-item",s.dataset.id=e,s.innerHTML="<div>"+t+\'</div><div class="socket-id">#\'+e+"</div>",s.onclick=()=>selectSocket(e),socketList.appendChild(s),sockets.set(e,{id:e,name:t,el:s,packets:[],sent:0,recv:0,sentBytes:0,recvBytes:0,saved:0})}function removeSocket(e,t,s,o){const n=sockets.get(e);if(!n)return console.error("Unknown socket!!",e);n.el.dataset.id=e+"-closed",n.el.onclick=()=>selectSocket(e+"-closed"),sockets.set(e+"-closed",n),sockets.delete(e),activeId==e&&(activeId=e+"-closed");const c=n.el.childNodes[0];c.style.color="#f00";let l=document.createElement("span");l.style.display="inline-block",l.style.width="10px",l.style.height="10px",l.style.borderRadius="50%",l.style.background="#ff5a5a",l.style.marginLeft="8px",c.appendChild(l);const a=document.createElement("li");a.textContent="Socket #"+e+" disconnected — Code: "+t+", Reason: "+s+", Closure Cause: "+o,document.getElementById("connection-logs").appendChild(a),requestAnimationFrame((()=>l.style.width="100%")),setTimeout((()=>{l.remove(),n.el.remove(),activeId==e+"-closed"&&(packetsDiv.style.display="none",home.style.display="block",closeSocketBtn.style.display="none")}),3e4)}function addPacket(e,t,s,o,n,c,l,a){const d=sockets.get(e);if(!d)return console.error("Unknown socket!!",e);const i=document.createElement("div");i.className="packet "+("sent"===t?"sent":"recv"),i.innerHTML="<div>"+s+("undefined"!==c?" — "+c:"")+\'</div><div class="packet-details">Raw Bytes: \'+o+"b (saved: ~"+n+"b)<br>Processed At: "+new Date(l).toISOString()+"<br>Processing Time: "+a.toFixed(2)+"ms</div>",i.onclick=()=>i.classList.toggle("expanded"),d.packets.push({el:i}),"sent"===t?(d.sent++,d.sentBytes+=o):(d.recv++,d.recvBytes+=o),d.saved+=n,activeId===e&&(packetsDiv.appendChild(i),renderStats(d))}function setStat(e,t){globalStats[Object.keys(globalStats)[e]]=t,null===activeId&&renderGlobalStats()}closeSocketBtn.onclick=()=>{null!==activeId&&ws.send("close",Number(activeId))};const ws=new SonicWS("ws://"+location.host);ws.on("connection",(e=>addSocket(e,"Socket "+e))),ws.on("disconnection",(([e,t],[s,o])=>removeSocket(e,t,s,o))),ws.on("nameChange",(([e],[t])=>{const s=sockets.get(e);if(!s)return console.error("Unknown socket!!",e);s.name=t,s.el.firstChild.textContent=t,activeId===e&&(socketTitle.textContent=t)})),ws.on("packet",(([e,t,s],[o],[n],[c],[l,a])=>{console.log("Received packet",{id:e,size:t,saved:s,dir:o,tag:n,values:c,time:l,processTime:a}),addPacket(e,o,n,t,s,c,l,a)})),ws.on("stats",(e=>{console.log("Received stats",e),e.forEach(((e,t)=>setStat(t,e)))})),ws.on("stat",((e,t)=>setStat(e,t)));const lastKnownPassword=localStorage.getItem("password"),empty=!localStorage.getItem("req");let usedPass="";ws.on_ready((()=>{empty?ws.send("password",""):ws.send("password",usedPass=lastKnownPassword??prompt("Please enter password"))})),ws.on_close((()=>{window.location.reload()})),ws.on("authenticated",(e=>{e?(localStorage.setItem("req",usedPass.length>0),localStorage.setItem("password",usedPass)):(localStorage.setItem("req",!0),localStorage.removeItem("password"),window.location.reload())}));<\/script>')}),r=(0,d.DefineEnum)("type",["sent","recv"]),p=new s.SonicWSServer({clientPackets:[(0,n.CreatePacket)({tag:"password",type:o.PacketType.STRINGS_UTF16}),(0,n.CreatePacket)({tag:"close",type:o.PacketType.UVARINT})],serverPackets:[(0,n.CreatePacket)({tag:"authenticated",type:o.PacketType.BOOLEANS}),(0,n.CreatePacket)({tag:"connection",type:o.PacketType.UVARINT}),(0,n.CreateObjPacket)({tag:"disconnection",types:[o.PacketType.UVARINT,o.PacketType.STRINGS],noDataRange:!0}),(0,n.CreateObjPacket)({tag:"nameChange",types:[o.PacketType.UVARINT,o.PacketType.STRINGS_UTF16],noDataRange:!0}),(0,n.CreateObjPacket)({tag:"packet",types:[o.PacketType.VARINT,r,o.PacketType.STRINGS_UTF16,o.PacketType.STRINGS_UTF16,o.PacketType.FLOATS],noDataRange:!0,dataBatching:50,maxBatchSize:0}),(0,n.CreatePacket)({tag:"stats",type:o.PacketType.UVARINT,noDataRange:!0,dontSpread:!0}),(0,n.CreatePacket)({tag:"stat",type:o.PacketType.UVARINT,dataMax:2})],websocketOptions:{server:l}}),v=new Proxy({totalSockets:0,totalSent:0,totalRecv:0,totalSentBytes:0,totalRecvBytes:0,totalSaved:0,startTime:Date.now()},{set(e,t,o){const s=String(t);return e[s]!==o&&(e[s]=o,p.broadcast("stat",Object.keys(v).indexOf(s),o)),!0}}),k={};p.on_connect(o=>{let s=!1;const n=o.send.bind(o);let a=[];o.send=async(e,...t)=>{console.log(s,e,t),s?n(e,...t):a.push([e,t])},o.send("stats",...Object.values(v)),e.connections.forEach(e=>{o.send("connection",e.id),o.send("nameChange",e.id,e.getName()),k[e.id]?.forEach(e=>{o.send("packet",...e)})}),o.on("password",e=>{i.password!=e?(n("authenticated",!1),setTimeout(()=>o.close(1008),1e3)):(s=!0,o.send("authenticated",!0),a.forEach(([e,t])=>n(e,...t)))}),o.on("close",o=>{s&&e.connectionMap[o]?.close(t.CloseCodes.MANUAL_SHUTDOWN)})});const u=[],g={},y=new TextEncoder,m=e=>y.encode(JSON.stringify(e)??"[]").length;e.addMiddleware(new class{onClientConnect(e){v.totalSockets++,k[e.id]=[],u.push(e),p.broadcast("connection",e.id);const t={},o={};e.addMiddleware(new class{onNameChange(t){p.broadcast("nameChange",e.id,t)}onSend_pre(e,o,s,n){t[e]??=[],t[e].push([o,n,s])}onSend_post(o,s,n){v.totalSentBytes+=n,v.totalSent++;const[a,c,d]=t[o].shift(),i=m(a)-n;v.totalSaved+=i;const l=[[e.id,n+1,i],r.wrap("sent"),o,JSON.stringify(a),[d,performance.now()-c]];k[e.id].push(l),p.broadcast("packet",...l)}onReceive_pre(e,t,s){v.totalRecvBytes+=s,v.totalRecv++,o[e]??=[],o[e].push([t,performance.now(),Date.now()])}onReceive_post(t,s){const[n,a,c]=o[t].shift(),d=m(s)-n.length;v.totalSaved+=d;const i=[[e.id,n.length+1,d],r.wrap("recv"),t,JSON.stringify(s),[c,performance.now()-a]];k[e.id].push(i),p.broadcast("packet",...i)}})}onClientDisconnect(e,o,s){v.totalSockets--,p.broadcast("disconnection",[e.id,o],[s?.toString()??"UNKNOWN",(0,t.getClosureCause)(o)]),delete k[e.id],u.splice(u.indexOf(e),1)}onPacketBroadcast_pre(e,t,...o){g[e]??=[],g[e].push([o,performance.now(),Date.now()])}onPacketBroadcast_post(e,t,o,s){const[n,a,c]=g[e].shift();t.recipients.forEach(t=>{u.includes(t)&&(t.callMiddleware("onSend_pre",e,n,c,a),t.callMiddleware("onSend_post",e,o,s))})}}),l.listen(i.port,()=>{const e=l.address();console.log(`SWS Debug server running at http://localhost:${e.port}`),(0,c.default)(`http://localhost:${e.port}`)})}};
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.DebugServer = void 0;
22
+ const Connection_1 = require("../Connection");
23
+ const PacketType_1 = require("../packets/PacketType");
24
+ const SonicWSServer_1 = require("../server/SonicWSServer");
25
+ const PacketUtils_1 = require("../util/packets/PacketUtils");
26
+ const http_1 = __importDefault(require("http"));
27
+ const open_1 = __importDefault(require("open"));
28
+ const EnumHandler_1 = require("../util/enums/EnumHandler");
29
+ class DebugServer {
30
+ constructor(host, data) {
31
+ data.port ??= 0;
32
+ data.password ??= "";
33
+ if (data.port < 0 || data.port >= 65536)
34
+ throw new Error("Port out of range!");
35
+ /*
36
+ * `
37
+ <!DOCTYPE html>
38
+ <html>
39
+ <head>
40
+ <meta charset="UTF-8">
41
+ <script src="https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/bundled/SonicWS_bundle"></script>
42
+ <title>SonicWS Debug Menu</title>
43
+ <style>
44
+ body {
45
+ margin: 0;
46
+ font-family: Inter, Arial, sans-serif;
47
+ background: #0f1115;
48
+ color: #e6e6e6;
49
+ height: 100vh;
50
+ display: flex;
51
+ }
52
+
53
+ #sidebar {
54
+ width: 260px;
55
+ background: #141821;
56
+ border-right: 1px solid #1f2533;
57
+ display: flex;
58
+ flex-direction: column;
59
+ }
60
+
61
+ #sidebar-header {
62
+ padding: 16px;
63
+ font-weight: 600;
64
+ font-size: 18px;
65
+ border-bottom: 1px solid #1f2533;
66
+ cursor: pointer;
67
+ transition: color 0.2s;
68
+ }
69
+ #sidebar-header:hover {
70
+ color: #dddddd;
71
+ }
72
+
73
+ #socket-list {
74
+ flex: 1;
75
+ overflow-y: auto;
76
+ }
77
+
78
+ .socket-item {
79
+ padding: 10px 14px;
80
+ cursor: pointer;
81
+ border-bottom: 1px solid #1f2533;
82
+ }
83
+
84
+ .socket-item:hover {
85
+ background: #1b2030;
86
+ }
87
+
88
+ .socket-item.active {
89
+ background: #22294a;
90
+ }
91
+
92
+ .socket-id {
93
+ font-size: 12px;
94
+ opacity: 0.7;
95
+ }
96
+
97
+ #main {
98
+ flex: 1;
99
+ display: flex;
100
+ flex-direction: column;
101
+ }
102
+
103
+ #main-header {
104
+ padding: 17px;
105
+ border-bottom: 1px solid #1f2533;
106
+ display: flex;
107
+ justify-content: space-between;
108
+ align-items: center;
109
+ }
110
+
111
+ #stats {
112
+ display: flex;
113
+ gap: 20px;
114
+ font-size: 13px;
115
+ }
116
+
117
+ #packets {
118
+ flex: 1;
119
+ overflow-y: auto;
120
+ padding: 12px;
121
+ }
122
+
123
+ .packet {
124
+ background: #1a1f2e;
125
+ border-radius: 6px;
126
+ padding: 6px 8px;
127
+ margin-bottom: 4px;
128
+ font-size: 12px;
129
+ cursor: pointer;
130
+ }
131
+
132
+ .packet.sent { border-left: 3px solid #3cff7a; }
133
+ .packet.recv { border-left: 3px solid #ff5a5a; }
134
+
135
+ .packet-details {
136
+ display: none;
137
+ margin-top: 4px;
138
+ opacity: 0.75;
139
+ font-size: 11px;
140
+ }
141
+
142
+ .packet.expanded .packet-details {
143
+ display: block;
144
+ }
145
+
146
+ button {
147
+ background: none;
148
+ }
149
+ </style>
150
+ </head>
151
+ <body>
152
+ <div id="sidebar">
153
+ <div id="sidebar-header">Sonic WS Debug Menu</div>
154
+ <div id="socket-list"></div>
155
+ </div>
156
+
157
+ <div id="main">
158
+ <div id="main-header">
159
+ <button id="close-socket" style="display:none;">❌</button>
160
+ <div id="socket-title">Server Home</div>
161
+ <div id="stats"></div>
162
+ </div>
163
+ <div id="home" style="display: block; padding: 16px;">
164
+ <h2>Server Dashboard</h2>
165
+ <div id="global-stats" style="margin-bottom:16px;"></div>
166
+ <h3>Connection Logs</h3>
167
+ <ul id="connection-logs" style="max-height:200px; overflow-y:auto; padding-left:16px;"></ul>
168
+ <div style="margin-top:16px;">
169
+ <table style="width:100%; border-collapse:collapse;">
170
+ <thead>
171
+ <tr>
172
+ <th style="border-bottom:1px solid #444; text-align:left;">Socket ID</th>
173
+ <th style="border-bottom:1px solid #444; text-align:left;">Name</th>
174
+ <th style="border-bottom:1px solid #444; text-align:left;">Status</th>
175
+ </tr>
176
+ </thead>
177
+ <tbody id="connection-table"></tbody>
178
+ </table>
179
+ </div>
180
+ </div>
181
+ <div id="packets"></div>
182
+ </div>
183
+
184
+ <script>
185
+ const socketList = document.getElementById('socket-list');
186
+ const packetsDiv = document.getElementById('packets');
187
+ const socketTitle = document.getElementById('socket-title');
188
+ const debugTitle = document.getElementById('sidebar-header');
189
+ const statsDiv = document.getElementById('stats');
190
+ const home = document.getElementById('home');
191
+ const closeSocketBtn = document.getElementById('close-socket');
192
+
193
+ debugTitle.onclick = () => {
194
+ if(activeId !== null) {
195
+ activeId = null;
196
+ packetsDiv.style.display = 'none';
197
+ home.style.display = 'block';
198
+ closeSocketBtn.style.display = 'none';
199
+ renderGlobalStats();
200
+ }
201
+ };
202
+
203
+ const globalStats = {
204
+ totalSockets: 0,
205
+ totalSent: 0,
206
+ totalRecv: 0,
207
+ totalSentBytes: 0,
208
+ totalRecvBytes: 0,
209
+ totalSaved: 0,
210
+ startTime: 0,
211
+ };
212
+
213
+ function formatMilliseconds(ms) {
214
+ if (ms < 1) return '0.0s';
215
+
216
+ const units = [
217
+ { label: 'week', value: 7 * 24 * 60 * 60 * 1000 },
218
+ { label: 'day', value: 24 * 60 * 60 * 1000 },
219
+ { label: 'hour', value: 60 * 60 * 1000 },
220
+ { label: 'minute', value: 60 * 1000 },
221
+ ];
222
+
223
+ const parts = [];
224
+
225
+ for (const { label, value } of units) {
226
+ const amount = Math.floor(ms / value);
227
+ if (amount > 0) {
228
+ parts.push(amount + ' ' + label + (amount !== 1 ? 's' : ''));
229
+ ms -= amount * value;
230
+ }
231
+ }
232
+
233
+ if (ms > 0 || parts.length === 0) {
234
+ const seconds = (ms / 1000).toFixed(1);
235
+ parts.push(seconds + 's');
236
+ }
237
+
238
+ if (parts.length === 1) return parts[0];
239
+ const last = parts.pop();
240
+ return parts.join(', ') + ' and ' + last;
241
+ }
242
+
243
+
244
+ const globalStatsDiv = document.getElementById('global-stats');
245
+ function renderGlobalStats() {
246
+ const stats = globalStats;
247
+ const uptime = Date.now() - stats.startTime;
248
+ const formattedUptime = formatMilliseconds(uptime);
249
+
250
+ globalStatsDiv.innerHTML = '<div><strong>Total Sockets:</strong> ' + stats.totalSockets + '</div><div><strong>Total Sent Packets:</strong> ' + stats.totalSent + '</div><div><strong>Total Received Packets:</strong> ' + stats.totalRecv + '</div><div><strong>Total Sent Bytes:</strong> ' + stats.totalSentBytes + ' B</div><div><strong>Total Received Bytes:</strong> ' + stats.totalRecvBytes + ' B</div><div><strong>Total Bandwidth Saved:</strong> ' + stats.totalSaved + ' B</div><div><strong>Uptime:</strong> ' + formattedUptime + '</div>';
251
+ }
252
+ setInterval(renderGlobalStats, 50);
253
+
254
+ function updateConnectionTable() {
255
+ const tbody = document.getElementById('connection-table');
256
+ tbody.innerHTML = '';
257
+ sockets.forEach(s => {
258
+ const row = document.createElement('tr');
259
+ row.innerHTML = '<td>' + s.id + '</td><td>' + s.name + '</td><td style="color:' + (s.el.style.color || '#0f0') + '">' + (s.el.style.color === '#f00' ? 'Disconnected' : 'Connected') + '</td>';
260
+ tbody.appendChild(row);
261
+ });
262
+ }
263
+ setInterval(updateConnectionTable, 1000);
264
+
265
+ const sockets = new Map();
266
+ let activeId = null;
267
+
268
+ function selectSocket(id) {
269
+ activeId = id;
270
+ [...socketList.children].forEach(e => e.classList.toggle('active', e.dataset.id == id));
271
+
272
+ const s = sockets.get(id);
273
+ socketTitle.textContent = s.name;
274
+ packetsDiv.innerHTML = '';
275
+ s.packets.forEach(p => packetsDiv.appendChild(p.el));
276
+ renderStats(s);
277
+ home.style.display = 'none';
278
+ packetsDiv.style.display = 'block';
279
+ closeSocketBtn.style.display = 'block';
280
+ }
281
+
282
+ closeSocketBtn.onclick = () => {
283
+ if(activeId === null) return;
284
+ ws.send("close", Number(activeId));
285
+ }
286
+
287
+ function renderStats(s) {
288
+ statsDiv.innerHTML = "<div>Sent: " + s.sent + "</div><div>Recv: " + s.recv + "</div><div>Sent bytes: " + s.sentBytes + "</div><div>Recv bytes: " + s.recvBytes + "</div><div>Saved: " + s.saved + "</div>";
289
+ }
290
+
291
+ function addSocket(id, name) {
292
+ const el = document.createElement('div');
293
+ el.className = 'socket-item';
294
+ el.dataset.id = id;
295
+ el.innerHTML = "<div>" + name + "</div><div class=\\"socket-id\\">#" + id + "</div>";
296
+ el.onclick = () => selectSocket(id);
297
+ socketList.appendChild(el);
298
+
299
+ sockets.set(id, {
300
+ id,
301
+ name,
302
+ el,
303
+ packets: [],
304
+ sent: 0,
305
+ recv: 0,
306
+ sentBytes: 0,
307
+ recvBytes: 0,
308
+ saved: 0
309
+ });
310
+ }
311
+
312
+ function removeSocket(id, code, reason, codeReason) {
313
+ const s = sockets.get(id);
314
+ if (!s) return console.error("Unknown socket!!", id);
315
+
316
+ s.el.dataset.id = id + "-closed";
317
+ s.el.onclick = () => selectSocket(id + "-closed");
318
+ sockets.set(id + "-closed", s);
319
+ sockets.delete(id);
320
+
321
+ if(activeId == id) activeId = id + "-closed";
322
+
323
+ const nameNode = s.el.childNodes[0];
324
+ nameNode.style.color = "#f00";
325
+
326
+ let circle = document.createElement('span');
327
+ circle.style.display = 'inline-block';
328
+ circle.style.width = '10px';
329
+ circle.style.height = '10px';
330
+ circle.style.borderRadius = '50%';
331
+ circle.style.background = '#ff5a5a';
332
+ circle.style.marginLeft = '8px';
333
+ nameNode.appendChild(circle);
334
+
335
+ // add disconnection info to home page logs
336
+ const logItem = document.createElement('li');
337
+ logItem.textContent = 'Socket #' + id + ' disconnected — Code: ' + code + ', Reason: ' + reason + ', Closure Cause: ' + codeReason;
338
+ document.getElementById('connection-logs').appendChild(logItem);
339
+
340
+ requestAnimationFrame(() => circle.style.width = '100%');
341
+ setTimeout(() => {
342
+ circle.remove();
343
+ s.el.remove();
344
+ if(activeId == id + "-closed") {
345
+ packetsDiv.style.display = 'none';
346
+ home.style.display = 'block';
347
+ closeSocketBtn.style.display = 'none';
348
+ }
349
+ }, 30000);
350
+ }
351
+
352
+ function addPacket(id, dir, tag, rawSize, saved, info, date, processTime) {
353
+ const s = sockets.get(id);
354
+ if (!s) return console.error("Unknown socket!!", id);
355
+
356
+ const el = document.createElement('div');
357
+ el.className = 'packet ' + (dir === 'sent' ? 'sent' : 'recv');
358
+ el.innerHTML = '<div>' + tag + (info !== "undefined" ? ' — ' + info : '') + '</div><div class="packet-details">Raw Bytes: ' + rawSize + 'b (saved: ~' + saved + 'b)<br>Processed At: ' + new Date(date).toISOString() + '<br>Processing Time: ' + processTime.toFixed(2) + 'ms</div>';
359
+
360
+ el.onclick = () => el.classList.toggle('expanded');
361
+
362
+ s.packets.push({ el });
363
+ if (dir === 'sent') {
364
+ s.sent++;
365
+ s.sentBytes += rawSize;
366
+ } else {
367
+ s.recv++;
368
+ s.recvBytes += rawSize;
369
+ }
370
+ s.saved += saved;
371
+
372
+ if (activeId === id) {
373
+ packetsDiv.appendChild(el);
374
+ renderStats(s);
375
+ }
376
+ }
377
+
378
+ function setStat(i, v) {
379
+ globalStats[Object.keys(globalStats)[i]] = v;
380
+ if (activeId === null) renderGlobalStats();
381
+ }
382
+
383
+ const ws = new SonicWS('ws://' + location.host);
384
+
385
+ ws.on("connection", id => addSocket(id, "Socket " + id));
386
+ ws.on("disconnection", ([id, code], [reason, codeReason]) => removeSocket(id, code, reason, codeReason));
387
+ ws.on("nameChange", ([id], [name]) => {
388
+ const s = sockets.get(id);
389
+ if (!s) return console.error("Unknown socket!!", id);
390
+ s.name = name;
391
+ s.el.firstChild.textContent = name;
392
+ if (activeId === id) socketTitle.textContent = name;
393
+ });
394
+ ws.on("packet", ([id, size, saved], [dir], [tag], [values], [time, processTime]) => {
395
+ console.log("Received packet", { id, size, saved, dir, tag, values, time, processTime });
396
+ addPacket(id, dir, tag, size, saved, values, time, processTime);
397
+ });
398
+ ws.on("stats", (stats) => {
399
+ console.log("Received stats", stats);
400
+ stats.forEach((v, i) => setStat(i, v));
401
+ });
402
+ ws.on("stat", (i, v) => setStat(i, v));
403
+
404
+ const lastKnownPassword = localStorage.getItem("password");
405
+ const empty = !localStorage.getItem("req");
406
+ let usedPass = "";
407
+ ws.on_ready(() => {
408
+ if(empty) ws.send("password", "");
409
+ else ws.send("password", usedPass = (lastKnownPassword ?? prompt("Please enter password")));
410
+ });
411
+
412
+ ws.on_close(() => {
413
+ window.location.reload();
414
+ });
415
+
416
+ ws.on("authenticated", (success) => {
417
+ if(!success) {
418
+ localStorage.setItem("req", true);
419
+ localStorage.removeItem("password");
420
+ window.location.reload();
421
+ } else {
422
+ localStorage.setItem("req", usedPass.length > 0);
423
+ localStorage.setItem("password", usedPass);
424
+ }
425
+ })
426
+ </script>
427
+ </body>
428
+ </html>
429
+ `
430
+ */
431
+ const server = http_1.default.createServer((req, res) => {
432
+ res.writeHead(200, { 'Content-Type': 'text/html' });
433
+ res.end(`<!doctypehtml><meta charset=UTF-8><script src=https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/bundled/SonicWS_bundle.js></script><title>SonicWS Debug Menu</title><style>body{margin:0;font-family:Inter,Arial,sans-serif;background:#0f1115;color:#e6e6e6;height:100vh;display:flex}#sidebar{width:260px;background:#141821;border-right:1px solid #1f2533;display:flex;flex-direction:column}#sidebar-header{padding:16px;font-weight:600;font-size:18px;border-bottom:1px solid #1f2533;cursor:pointer;transition:color .2s}#sidebar-header:hover{color:#ddd}#socket-list{flex:1;overflow-y:auto}.socket-item{padding:10px 14px;cursor:pointer;border-bottom:1px solid #1f2533}.socket-item:hover{background:#1b2030}.socket-item.active{background:#22294a}.socket-id{font-size:12px;opacity:.7}#main{flex:1;display:flex;flex-direction:column}#main-header{padding:17px;border-bottom:1px solid #1f2533;display:flex;justify-content:space-between;align-items:center}#stats{display:flex;gap:20px;font-size:13px}#packets{flex:1;overflow-y:auto;padding:12px}.packet{background:#1a1f2e;border-radius:6px;padding:6px 8px;margin-bottom:4px;font-size:12px;cursor:pointer}.packet.sent{border-left:3px solid #3cff7a}.packet.recv{border-left:3px solid #ff5a5a}.packet-details{display:none;margin-top:4px;opacity:.75;font-size:11px}.packet.expanded .packet-details{display:block}button{background:0 0}</style><div id=sidebar><div id=sidebar-header>Sonic WS Debug Menu</div><div id=socket-list></div></div><div id=main><div id=main-header><button id=close-socket style=display:none>❌</button><div id=socket-title>Server Home</div><div id=stats></div></div><div id=home style=display:block;padding:16px><h2>Server Dashboard</h2><div id=global-stats style=margin-bottom:16px></div><h3>Connection Logs</h3><ul id=connection-logs style=max-height:200px;overflow-y:auto;padding-left:16px></ul><div style=margin-top:16px><table style=width:100%;border-collapse:collapse><thead><tr><th style="border-bottom:1px solid #444;text-align:left">Socket ID<th style="border-bottom:1px solid #444;text-align:left">Name<th style="border-bottom:1px solid #444;text-align:left">Status<tbody id=connection-table></table></div></div><div id=packets></div></div><script>const socketList=document.getElementById("socket-list"),packetsDiv=document.getElementById("packets"),socketTitle=document.getElementById("socket-title"),debugTitle=document.getElementById("sidebar-header"),statsDiv=document.getElementById("stats"),home=document.getElementById("home"),closeSocketBtn=document.getElementById("close-socket");debugTitle.onclick=()=>{null!==activeId&&(activeId=null,packetsDiv.style.display="none",home.style.display="block",closeSocketBtn.style.display="none",renderGlobalStats())};const globalStats={totalSockets:0,totalSent:0,totalRecv:0,totalSentBytes:0,totalRecvBytes:0,totalSaved:0,startTime:0};function formatMilliseconds(e){if(e<1)return"0.0s";const t=[{label:"week",value:6048e5},{label:"day",value:864e5},{label:"hour",value:36e5},{label:"minute",value:6e4}],s=[];for(const{label:o,value:n}of t){const t=Math.floor(e/n);t>0&&(s.push(t+" "+o+(1!==t?"s":"")),e-=t*n)}if(e>0||0===s.length){const t=(e/1e3).toFixed(1);s.push(t+"s")}if(1===s.length)return s[0];const o=s.pop();return s.join(", ")+" and "+o}const globalStatsDiv=document.getElementById("global-stats");function renderGlobalStats(){const e=globalStats,t=formatMilliseconds(Date.now()-e.startTime);globalStatsDiv.innerHTML="<div><strong>Total Sockets:</strong> "+e.totalSockets+"</div><div><strong>Total Sent Packets:</strong> "+e.totalSent+"</div><div><strong>Total Received Packets:</strong> "+e.totalRecv+"</div><div><strong>Total Sent Bytes:</strong> "+e.totalSentBytes+" B</div><div><strong>Total Received Bytes:</strong> "+e.totalRecvBytes+" B</div><div><strong>Total Bandwidth Saved:</strong> "+e.totalSaved+" B</div><div><strong>Uptime:</strong> "+t+"</div>"}function updateConnectionTable(){const e=document.getElementById("connection-table");e.innerHTML="",sockets.forEach((t=>{const s=document.createElement("tr");s.innerHTML="<td>"+t.id+"</td><td>"+t.name+'</td><td style="color:'+(t.el.style.color||"#0f0")+'">'+("#f00"===t.el.style.color?"Disconnected":"Connected")+"</td>",e.appendChild(s)}))}setInterval(renderGlobalStats,50),setInterval(updateConnectionTable,1e3);const sockets=new Map;let activeId=null;function selectSocket(e){activeId=e,[...socketList.children].forEach((t=>t.classList.toggle("active",t.dataset.id==e)));const t=sockets.get(e);socketTitle.textContent=t.name,packetsDiv.innerHTML="",t.packets.forEach((e=>packetsDiv.appendChild(e.el))),renderStats(t),home.style.display="none",packetsDiv.style.display="block",closeSocketBtn.style.display="block"}function renderStats(e){statsDiv.innerHTML="<div>Sent: "+e.sent+"</div><div>Recv: "+e.recv+"</div><div>Sent bytes: "+e.sentBytes+"</div><div>Recv bytes: "+e.recvBytes+"</div><div>Saved: "+e.saved+"</div>"}function addSocket(e,t){const s=document.createElement("div");s.className="socket-item",s.dataset.id=e,s.innerHTML="<div>"+t+'</div><div class="socket-id">#'+e+"</div>",s.onclick=()=>selectSocket(e),socketList.appendChild(s),sockets.set(e,{id:e,name:t,el:s,packets:[],sent:0,recv:0,sentBytes:0,recvBytes:0,saved:0})}function removeSocket(e,t,s,o){const n=sockets.get(e);if(!n)return console.error("Unknown socket!!",e);n.el.dataset.id=e+"-closed",n.el.onclick=()=>selectSocket(e+"-closed"),sockets.set(e+"-closed",n),sockets.delete(e),activeId==e&&(activeId=e+"-closed");const c=n.el.childNodes[0];c.style.color="#f00";let l=document.createElement("span");l.style.display="inline-block",l.style.width="10px",l.style.height="10px",l.style.borderRadius="50%",l.style.background="#ff5a5a",l.style.marginLeft="8px",c.appendChild(l);const a=document.createElement("li");a.textContent="Socket #"+e+" disconnected — Code: "+t+", Reason: "+s+", Closure Cause: "+o,document.getElementById("connection-logs").appendChild(a),requestAnimationFrame((()=>l.style.width="100%")),setTimeout((()=>{l.remove(),n.el.remove(),activeId==e+"-closed"&&(packetsDiv.style.display="none",home.style.display="block",closeSocketBtn.style.display="none")}),3e4)}function addPacket(e,t,s,o,n,c,l,a){const d=sockets.get(e);if(!d)return console.error("Unknown socket!!",e);const i=document.createElement("div");i.className="packet "+("sent"===t?"sent":"recv"),i.innerHTML="<div>"+s+("undefined"!==c?" — "+c:"")+'</div><div class="packet-details">Raw Bytes: '+o+"b (saved: ~"+n+"b)<br>Processed At: "+new Date(l).toISOString()+"<br>Processing Time: "+a.toFixed(2)+"ms</div>",i.onclick=()=>i.classList.toggle("expanded"),d.packets.push({el:i}),"sent"===t?(d.sent++,d.sentBytes+=o):(d.recv++,d.recvBytes+=o),d.saved+=n,activeId===e&&(packetsDiv.appendChild(i),renderStats(d))}function setStat(e,t){globalStats[Object.keys(globalStats)[e]]=t,null===activeId&&renderGlobalStats()}closeSocketBtn.onclick=()=>{null!==activeId&&ws.send("close",Number(activeId))};const ws=new SonicWS("ws://"+location.host);ws.on("connection",(e=>addSocket(e,"Socket "+e))),ws.on("disconnection",(([e,t],[s,o])=>removeSocket(e,t,s,o))),ws.on("nameChange",(([e],[t])=>{const s=sockets.get(e);if(!s)return console.error("Unknown socket!!",e);s.name=t,s.el.firstChild.textContent=t,activeId===e&&(socketTitle.textContent=t)})),ws.on("packet",(([e,t,s],[o],[n],[c],[l,a])=>{console.log("Received packet",{id:e,size:t,saved:s,dir:o,tag:n,values:c,time:l,processTime:a}),addPacket(e,o,n,t,s,c,l,a)})),ws.on("stats",(e=>{console.log("Received stats",e),e.forEach(((e,t)=>setStat(t,e)))})),ws.on("stat",((e,t)=>setStat(e,t)));const lastKnownPassword=localStorage.getItem("password"),empty=!localStorage.getItem("req");let usedPass="";ws.on_ready((()=>{empty?ws.send("password",""):ws.send("password",usedPass=lastKnownPassword??prompt("Please enter password"))})),ws.on_close((()=>{window.location.reload()})),ws.on("authenticated",(e=>{e?(localStorage.setItem("req",usedPass.length>0),localStorage.setItem("password",usedPass)):(localStorage.setItem("req",!0),localStorage.removeItem("password"),window.location.reload())}));</script>`);
434
+ });
435
+ const TYPE_ENUM = (0, EnumHandler_1.DefineEnum)("type", ["sent", "recv"]);
436
+ const wss = new SonicWSServer_1.SonicWSServer({
437
+ clientPackets: [
438
+ (0, PacketUtils_1.CreatePacket)({ tag: "password", type: PacketType_1.PacketType.STRINGS_UTF16 }),
439
+ (0, PacketUtils_1.CreatePacket)({ tag: "close", type: PacketType_1.PacketType.UVARINT }),
440
+ ],
441
+ serverPackets: [
442
+ (0, PacketUtils_1.CreatePacket)({ tag: "authenticated", type: PacketType_1.PacketType.BOOLEANS }),
443
+ (0, PacketUtils_1.CreatePacket)({ tag: "connection", type: PacketType_1.PacketType.UVARINT }),
444
+ (0, PacketUtils_1.CreateObjPacket)({ tag: "disconnection", types: [PacketType_1.PacketType.UVARINT, PacketType_1.PacketType.STRINGS], noDataRange: true }),
445
+ (0, PacketUtils_1.CreateObjPacket)({ tag: "nameChange", types: [PacketType_1.PacketType.UVARINT, PacketType_1.PacketType.STRINGS_UTF16], noDataRange: true }),
446
+ (0, PacketUtils_1.CreateObjPacket)({
447
+ tag: "packet",
448
+ types: [
449
+ PacketType_1.PacketType.VARINT,
450
+ TYPE_ENUM,
451
+ PacketType_1.PacketType.STRINGS_UTF16,
452
+ PacketType_1.PacketType.STRINGS_UTF16,
453
+ PacketType_1.PacketType.FLOATS,
454
+ ],
455
+ noDataRange: true,
456
+ dataBatching: 50,
457
+ maxBatchSize: 0,
458
+ }),
459
+ (0, PacketUtils_1.CreatePacket)({ tag: "stats", type: PacketType_1.PacketType.UVARINT, noDataRange: true, dontSpread: true }),
460
+ (0, PacketUtils_1.CreatePacket)({ tag: "stat", type: PacketType_1.PacketType.UVARINT, dataMax: 2 }),
461
+ ],
462
+ websocketOptions: { server },
463
+ });
464
+ const globalStats = new Proxy({
465
+ totalSockets: 0,
466
+ totalSent: 0,
467
+ totalRecv: 0,
468
+ totalSentBytes: 0,
469
+ totalRecvBytes: 0,
470
+ totalSaved: 0,
471
+ startTime: Date.now(),
472
+ }, {
473
+ set(target, prop, value) {
474
+ const key = String(prop);
475
+ if (target[key] !== value) {
476
+ target[key] = value;
477
+ wss.broadcast("stat", Object.keys(globalStats).indexOf(key), value);
478
+ }
479
+ return true;
480
+ }
481
+ });
482
+ // TODO: i think this is fucked by async
483
+ const storedPacketData = {};
484
+ wss.on_connect(ws => {
485
+ let authenticated = false;
486
+ const ogs = ws.send.bind(ws);
487
+ let queue = [];
488
+ ws.send = async (tag, ...values) => {
489
+ console.log(authenticated, tag, values);
490
+ if (!authenticated)
491
+ queue.push([tag, values]);
492
+ else
493
+ ogs(tag, ...values);
494
+ };
495
+ ws.send("stats", ...Object.values(globalStats));
496
+ host.connections.forEach(conn => {
497
+ ws.send("connection", conn.id);
498
+ ws.send("nameChange", conn.id, conn.getName());
499
+ storedPacketData[conn.id]?.forEach((data) => {
500
+ ws.send("packet", ...data);
501
+ });
502
+ });
503
+ ws.on("password", (pword) => {
504
+ if (data.password != pword) {
505
+ ogs("authenticated", false);
506
+ setTimeout(() => ws.close(1008), 1000);
507
+ }
508
+ else {
509
+ authenticated = true;
510
+ ws.send("authenticated", true);
511
+ queue.forEach(([tag, values]) => ogs(tag, ...values));
512
+ }
513
+ });
514
+ ws.on("close", (id) => {
515
+ if (!authenticated)
516
+ return;
517
+ host.connectionMap[id]?.close(Connection_1.CloseCodes.MANUAL_SHUTDOWN);
518
+ });
519
+ });
520
+ const innerConns = [];
521
+ const broadcastSends = {};
522
+ const textEncoder = new TextEncoder();
523
+ const length = (values) => textEncoder.encode(JSON.stringify(values) ?? "[]").length;
524
+ host.addMiddleware(new (class {
525
+ onClientConnect(connection) {
526
+ globalStats.totalSockets++;
527
+ storedPacketData[connection.id] = [];
528
+ innerConns.push(connection);
529
+ wss.broadcast("connection", connection.id);
530
+ const packetsSend = {};
531
+ const packetsRecv = {};
532
+ connection.addMiddleware(new (class {
533
+ onNameChange(name) {
534
+ wss.broadcast("nameChange", connection.id, name);
535
+ }
536
+ onSend_pre(tag, values, date, perfTime) {
537
+ packetsSend[tag] ??= [];
538
+ packetsSend[tag].push([values, perfTime, date]);
539
+ }
540
+ onSend_post(tag, data, sendSize) {
541
+ globalStats.totalSentBytes += sendSize;
542
+ globalStats.totalSent++;
543
+ const [values, perfTime, date] = packetsSend[tag].shift();
544
+ const jsonLength = length(values);
545
+ const saved = jsonLength - sendSize;
546
+ globalStats.totalSaved += saved;
547
+ const record = [
548
+ [connection.id, sendSize + 1, saved],
549
+ TYPE_ENUM.wrap("sent"),
550
+ tag,
551
+ JSON.stringify(values),
552
+ [date, performance.now() - perfTime],
553
+ ];
554
+ storedPacketData[connection.id].push(record);
555
+ wss.broadcast("packet", ...record);
556
+ }
557
+ onReceive_pre(tag, data, recvSize) {
558
+ globalStats.totalRecvBytes += recvSize;
559
+ globalStats.totalRecv++;
560
+ packetsRecv[tag] ??= [];
561
+ packetsRecv[tag].push([data, performance.now(), Date.now()]);
562
+ }
563
+ onReceive_post(tag, values) {
564
+ const [data, time, date] = packetsRecv[tag].shift();
565
+ const jsonLength = length(values);
566
+ const saved = jsonLength - data.length;
567
+ globalStats.totalSaved += saved;
568
+ const record = [
569
+ [connection.id, data.length + 1, saved],
570
+ TYPE_ENUM.wrap("recv"),
571
+ tag,
572
+ JSON.stringify(values),
573
+ [date, performance.now() - time],
574
+ ];
575
+ storedPacketData[connection.id].push(record);
576
+ wss.broadcast("packet", ...record);
577
+ }
578
+ })());
579
+ }
580
+ onClientDisconnect(connection, code, reason) {
581
+ globalStats.totalSockets--;
582
+ wss.broadcast("disconnection", [connection.id, code], [reason?.toString() ?? "UNKNOWN", (0, Connection_1.getClosureCause)(code)]);
583
+ delete storedPacketData[connection.id];
584
+ innerConns.splice(innerConns.indexOf(connection), 1);
585
+ }
586
+ onPacketBroadcast_pre(tag, info, ...values) {
587
+ broadcastSends[tag] ??= [];
588
+ broadcastSends[tag].push([values, performance.now(), Date.now()]);
589
+ }
590
+ onPacketBroadcast_post(tag, info, data, sendSize) {
591
+ const [values, time, date] = broadcastSends[tag].shift();
592
+ info.recipients.forEach(k => {
593
+ if (innerConns.includes(k)) {
594
+ k.callMiddleware("onSend_pre", tag, values, date, time);
595
+ k.callMiddleware("onSend_post", tag, data, sendSize);
596
+ }
597
+ });
598
+ }
599
+ })());
600
+ server.listen(data.port, () => {
601
+ const address = server.address();
602
+ console.log(`SWS Debug server running at http://localhost:${address.port}`);
603
+ (0, open_1.default)(`http://localhost:${address.port}`);
604
+ });
605
+ }
606
+ }
607
+ exports.DebugServer = DebugServer;