@aetherframework/websocket 1.0.0 → 1.0.1

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.
@@ -1,422 +0,0 @@
1
- /**
2
- * @license MIT
3
- * Copyright (c) 2026-present AetherFramework Contributors.
4
- * SPDX-License-Identifier: MIT
5
- * @module @aetherframework/src/drivers/memory-driver
6
- */
7
-
8
- import EventEmitter from 'events';
9
- import crypto from 'crypto';
10
-
11
- class MemoryDriver extends EventEmitter {
12
- constructor(config = {}) {
13
- super();
14
- this.config = {
15
- maxPayload: config.maxPayload || 1024 * 1024,
16
- latency: config.latency || 0, // Simulated network latency in ms
17
- dropRate: config.dropRate || 0, // Simulated packet drop rate (0-1)
18
- ...config
19
- };
20
-
21
- this.connections = new Map();
22
- this.messageQueue = new Map();
23
- this.isServer = false;
24
- this.serverInstance = null;
25
- }
26
-
27
- /**
28
- * Create an in-memory WebSocket server
29
- * @param {Object} options - Server options
30
- * @returns {Promise<Object>} Server instance
31
- */
32
- async createServer(options = {}) {
33
- this.isServer = true;
34
- this.serverInstance = {
35
- type: 'memory',
36
- address: { address: 'memory', port: 0, family: 'memory' },
37
- connections: new Map(),
38
- broadcast: (message) => this._broadcast(message),
39
- close: () => this.closeServer(),
40
- getStats: () => this.getStats()
41
- };
42
-
43
- // Simulate server listening
44
- setTimeout(() => {
45
- this.emit('server:listening', {
46
- host: options.host || 'memory',
47
- port: options.port || 0,
48
- family: 'memory'
49
- });
50
- }, 0);
51
-
52
- return this.serverInstance;
53
- }
54
-
55
- /**
56
- * Create an in-memory WebSocket client
57
- * @param {string} url - WebSocket URL (ignored for memory driver)
58
- * @param {Object} options - Client options
59
- * @returns {Promise<Object>} Client connection
60
- */
61
- async createClient(url, options = {}) {
62
- const connectionId = crypto.randomUUID();
63
-
64
- // Create mock connection
65
- const connection = {
66
- id: connectionId,
67
- readyState: 1, // OPEN
68
- protocol: options.protocol || null,
69
- remoteAddress: 'memory',
70
- remotePort: 0,
71
- url: url,
72
- options: options,
73
- send: (data) => this._sendToServer(connectionId, data),
74
- sendBinary: (data) => this._sendBinaryToServer(connectionId, data),
75
- sendJSON: (obj) => this._sendToServer(connectionId, JSON.stringify(obj)),
76
- close: (code, reason) => this._closeConnection(connectionId, code, reason),
77
- terminate: () => this._terminateConnection(connectionId),
78
- ping: () => this._sendPing(connectionId),
79
- getStats: () => this._getConnectionStats(connectionId)
80
- };
81
-
82
- this.connections.set(connectionId, connection);
83
-
84
- // Simulate connection handshake
85
- setTimeout(() => {
86
- if (Math.random() > this.config.dropRate) {
87
- this.emit('connection', connection);
88
-
89
- // Simulate server accepting connection
90
- if (this.isServer) {
91
- this.serverInstance.connections.set(connectionId, connection);
92
-
93
- // Send welcome message
94
- setTimeout(() => {
95
- this._deliverMessage(connectionId, {
96
- type: 'welcome',
97
- message: 'Connected to memory WebSocket server',
98
- connectionId: connectionId,
99
- timestamp: Date.now()
100
- });
101
- }, this.config.latency);
102
- }
103
- } else {
104
- // Simulate connection failure
105
- this.emit('error', {
106
- type: 'connection_failed',
107
- message: 'Simulated connection failure',
108
- connectionId
109
- });
110
- }
111
- }, this.config.latency);
112
-
113
- return connection;
114
- }
115
-
116
- /**
117
- * Send message to server (from client)
118
- * @param {string} connectionId - Connection ID
119
- * @param {string|Buffer} data - Data to send
120
- * @private
121
- */
122
- _sendToServer(connectionId, data) {
123
- const connection = this.connections.get(connectionId);
124
- if (!connection || connection.readyState !== 1) {
125
- return false;
126
- }
127
-
128
- // Simulate network latency
129
- setTimeout(() => {
130
- if (Math.random() > this.config.dropRate) {
131
- // Deliver to server
132
- this.emit('message', connection, data, false);
133
-
134
- // Update connection stats
135
- connection.stats = connection.stats || {
136
- messagesSent: 0,
137
- messagesReceived: 0,
138
- bytesSent: 0,
139
- bytesReceived: 0
140
- };
141
- connection.stats.messagesSent++;
142
- connection.stats.bytesSent += Buffer.byteLength(data);
143
- } else {
144
- // Simulate packet loss
145
- this.emit('error', {
146
- type: 'packet_loss',
147
- message: 'Simulated packet loss',
148
- connectionId
149
- });
150
- }
151
- }, this.config.latency);
152
-
153
- return true;
154
- }
155
-
156
- /**
157
- * Send binary data to server
158
- * @param {string} connectionId - Connection ID
159
- * @param {Buffer} data - Binary data
160
- * @private
161
- */
162
- _sendBinaryToServer(connectionId, data) {
163
- const connection = this.connections.get(connectionId);
164
- if (!connection || connection.readyState !== 1) {
165
- return false;
166
- }
167
-
168
- setTimeout(() => {
169
- if (Math.random() > this.config.dropRate) {
170
- this.emit('message', connection, data, true);
171
-
172
- connection.stats = connection.stats || {
173
- messagesSent: 0,
174
- messagesReceived: 0,
175
- bytesSent: 0,
176
- bytesReceived: 0
177
- };
178
- connection.stats.messagesSent++;
179
- connection.stats.bytesSent += data.length;
180
- }
181
- }, this.config.latency);
182
-
183
- return true;
184
- }
185
-
186
- /**
187
- * Send ping frame
188
- * @param {string} connectionId - Connection ID
189
- * @private
190
- */
191
- _sendPing(connectionId) {
192
- const connection = this.connections.get(connectionId);
193
- if (!connection || connection.readyState !== 1) {
194
- return false;
195
- }
196
-
197
- setTimeout(() => {
198
- if (Math.random() > this.config.dropRate) {
199
- // Simulate pong response
200
- setTimeout(() => {
201
- this.emit('pong', connection);
202
- }, this.config.latency / 2);
203
- }
204
- }, this.config.latency);
205
-
206
- return true;
207
- }
208
-
209
- /**
210
- * Deliver message to connection (from server to client)
211
- * @param {string} connectionId - Connection ID
212
- * @param {any} message - Message to deliver
213
- * @private
214
- */
215
- _deliverMessage(connectionId, message) {
216
- const connection = this.connections.get(connectionId);
217
- if (!connection || connection.readyState !== 1) {
218
- return;
219
- }
220
-
221
- // Queue message for delivery
222
- if (!this.messageQueue.has(connectionId)) {
223
- this.messageQueue.set(connectionId, []);
224
- }
225
-
226
- this.messageQueue.get(connectionId).push({
227
- message,
228
- timestamp: Date.now()
229
- });
230
-
231
- // Process queue with simulated latency
232
- setTimeout(() => {
233
- const queue = this.messageQueue.get(connectionId);
234
- if (queue && queue.length > 0) {
235
- const item = queue.shift();
236
- if (Math.random() > this.config.dropRate) {
237
- // Emit message event on connection
238
- connection.emit('message', item.message);
239
-
240
- // Update stats
241
- connection.stats = connection.stats || {
242
- messagesSent: 0,
243
- messagesReceived: 0,
244
- bytesSent: 0,
245
- bytesReceived: 0
246
- };
247
- connection.stats.messagesReceived++;
248
- connection.stats.bytesReceived += Buffer.byteLength(
249
- typeof item.message === 'string' ? item.message : JSON.stringify(item.message)
250
- );
251
- }
252
- }
253
- }, this.config.latency);
254
- }
255
-
256
- /**
257
- * Close connection
258
- * @param {string} connectionId - Connection ID
259
- * @param {number} code - Close code
260
- * @param {string} reason - Close reason
261
- * @private
262
- */
263
- _closeConnection(connectionId, code = 1000, reason = '') {
264
- const connection = this.connections.get(connectionId);
265
- if (!connection) return;
266
-
267
- connection.readyState = 3; // CLOSED
268
-
269
- setTimeout(() => {
270
- this.emit('close', connection, code, reason);
271
-
272
- if (this.isServer) {
273
- this.serverInstance.connections.delete(connectionId);
274
- }
275
-
276
- this.connections.delete(connectionId);
277
- this.messageQueue.delete(connectionId);
278
- }, this.config.latency);
279
-
280
- return true;
281
- }
282
-
283
- /**
284
- * Terminate connection (force close)
285
- * @param {string} connectionId - Connection ID
286
- * @private
287
- */
288
- _terminateConnection(connectionId) {
289
- const connection = this.connections.get(connectionId);
290
- if (!connection) return;
291
-
292
- connection.readyState = 3; // CLOSED
293
-
294
- this.emit('close', connection, 1006, 'Connection terminated');
295
-
296
- if (this.isServer) {
297
- this.serverInstance.connections.delete(connectionId);
298
- }
299
-
300
- this.connections.delete(connectionId);
301
- this.messageQueue.delete(connectionId);
302
-
303
- return true;
304
- }
305
-
306
- /**
307
- * Broadcast message to all connections
308
- * @param {any} message - Message to broadcast
309
- * @private
310
- */
311
- _broadcast(message) {
312
- if (!this.isServer) return;
313
-
314
- this.serverInstance.connections.forEach((connection, connectionId) => {
315
- this._deliverMessage(connectionId, message);
316
- });
317
- }
318
-
319
- /**
320
- * Send message to specific connection
321
- * @param {string} connectionId - Connection ID
322
- * @param {any} message - Message to send
323
- */
324
- sendTo(connectionId, message) {
325
- if (!this.isServer) return false;
326
-
327
- const connection = this.serverInstance.connections.get(connectionId);
328
- if (!connection) return false;
329
-
330
- this._deliverMessage(connectionId, message);
331
- return true;
332
- }
333
-
334
- /**
335
- * Get connection statistics
336
- * @param {string} connectionId - Connection ID
337
- * @returns {Object} Connection statistics
338
- * @private
339
- */
340
- _getConnectionStats(connectionId) {
341
- const connection = this.connections.get(connectionId);
342
- if (!connection) return null;
343
-
344
- return {
345
- ...(connection.stats || {}),
346
- readyState: connection.readyState,
347
- protocol: connection.protocol,
348
- remoteAddress: connection.remoteAddress,
349
- remotePort: connection.remotePort,
350
- uptime: Date.now() - (connection.createdAt || Date.now())
351
- };
352
- }
353
-
354
- /**
355
- * Close the memory server
356
- * @returns {Promise<void>}
357
- */
358
- async closeServer() {
359
- return new Promise((resolve) => {
360
- // Close all connections
361
- this.connections.forEach((connection, connectionId) => {
362
- this._closeConnection(connectionId, 1001, 'Server shutting down');
363
- });
364
-
365
- // Clear all data
366
- this.connections.clear();
367
- this.messageQueue.clear();
368
- this.serverInstance = null;
369
- this.isServer = false;
370
-
371
- setTimeout(() => {
372
- this.emit('server:closed');
373
- resolve();
374
- }, this.config.latency);
375
- });
376
- }
377
-
378
- /**
379
- * Get server statistics
380
- * @returns {Object} Statistics object
381
- */
382
- getStats() {
383
- return {
384
- connections: this.connections.size,
385
- isServer: this.isServer,
386
- config: {
387
- latency: this.config.latency,
388
- dropRate: this.config.dropRate,
389
- maxPayload: this.config.maxPayload
390
- },
391
- memoryUsage: process.memoryUsage(),
392
- timestamp: Date.now()
393
- };
394
- }
395
-
396
- /**
397
- * Simulate network conditions
398
- * @param {Object} conditions - Network conditions to simulate
399
- */
400
- simulateNetwork(conditions = {}) {
401
- this.config = {
402
- ...this.config,
403
- ...conditions
404
- };
405
-
406
- this.emit('network:changed', this.config);
407
- }
408
-
409
- /**
410
- * Reset all connections and state
411
- */
412
- reset() {
413
- this.connections.clear();
414
- this.messageQueue.clear();
415
- this.serverInstance = null;
416
- this.isServer = false;
417
-
418
- this.emit('reset');
419
- }
420
- }
421
-
422
- export default MemoryDriver;