@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,293 +0,0 @@
1
- /**
2
- * @license MIT
3
- * Copyright (c) 2026-present AetherFramework Contributors.
4
- * SPDX-License-Identifier: MIT
5
- * @module @aetherframework/src/core/WebSocketFactory
6
- */
7
-
8
- import EventEmitter from 'events';
9
- import ConnectionManager from './ConnectionManager.js';
10
- import FrameParser from './FrameParser.js';
11
- import ProtocolHandler from './ProtocolHandler.js';
12
- import ConfigLoader from '../utils/config-loader.js';
13
-
14
- class WebSocketFactory extends EventEmitter {
15
- /**
16
- * Create a new WebSocketFactory instance
17
- * @param {Object} options - Configuration options
18
- */
19
- constructor(options = {}) {
20
- super();
21
-
22
- // Load configuration from environment and options
23
- this.config = ConfigLoader.load({
24
- // Default configuration
25
- driver: 'tcp',
26
- port: 8080,
27
- host: '0.0.0.0',
28
- maxPayload: 1024 * 1024, // 1MB
29
- pingInterval: 30000, // 30 seconds
30
- pingTimeout: 10000, // 10 seconds
31
- compression: false,
32
- tls: false,
33
- tlsOptions: {},
34
- // Merge with user options
35
- ...options
36
- });
37
-
38
- this.connectionManager = new ConnectionManager();
39
- this.frameParser = new FrameParser(this.config);
40
- this.protocolHandler = new ProtocolHandler(this.config);
41
- this.driver = null;
42
- this.server = null;
43
- this.middleware = [];
44
-
45
- // Initialize driver
46
- this._initializeDriver();
47
- }
48
-
49
- /**
50
- * Initialize the selected transport driver
51
- * @private
52
- */
53
- async _initializeDriver() {
54
- try {
55
- const driverName = this.config.driver || 'tcp';
56
- const driverModule = await import(`../drivers/${driverName}-driver.js`);
57
- this.driver = new driverModule.default(this.config);
58
-
59
- // Set up driver event forwarding
60
- this._setupDriverEvents();
61
-
62
- this.emit('driver:initialized', { driver: driverName });
63
- } catch (error) {
64
- this.emit('error', {
65
- type: 'driver_initialization',
66
- message: `Failed to initialize driver: ${error.message}`,
67
- error
68
- });
69
- throw error;
70
- }
71
- }
72
-
73
- /**
74
- * Set up event forwarding from driver to factory
75
- * @private
76
- */
77
- _setupDriverEvents() {
78
- if (!this.driver) return;
79
-
80
- // Forward all driver events to factory
81
- const eventsToForward = [
82
- 'server:listening',
83
- 'server:closed',
84
- 'server:error',
85
- 'connection',
86
- 'message',
87
- 'close',
88
- 'error',
89
- 'ping',
90
- 'pong'
91
- ];
92
-
93
- eventsToForward.forEach(event => {
94
- this.driver.on(event, (...args) => {
95
- this.emit(event, ...args);
96
- });
97
- });
98
- }
99
-
100
- /**
101
- * Create a WebSocket server
102
- * @param {Object} options - Server-specific options
103
- * @returns {Promise<Object>} Server instance
104
- */
105
- async createServer(options = {}) {
106
- if (!this.driver) {
107
- await this._initializeDriver();
108
- }
109
-
110
- const serverOptions = {
111
- ...this.config,
112
- ...options
113
- };
114
-
115
- try {
116
- this.server = await this.driver.createServer(serverOptions);
117
-
118
- // CRITICAL FIX: Ensure server:listening event is emitted
119
- // Get server address information
120
- let addressInfo;
121
- if (this.server.address && typeof this.server.address === 'function') {
122
- addressInfo = this.server.address();
123
- } else if (this.server.address) {
124
- addressInfo = this.server.address;
125
- } else {
126
- addressInfo = {
127
- address: serverOptions.host || '0.0.0.0',
128
- port: serverOptions.port || 8080,
129
- family: 'IPv4'
130
- };
131
- }
132
-
133
- // Emit server:listening event with address information
134
- // Use setTimeout to ensure event listeners are registered
135
- setTimeout(() => {
136
- this.emit('server:listening', {
137
- host: addressInfo.address,
138
- port: addressInfo.port,
139
- family: addressInfo.family || 'IPv4'
140
- });
141
- }, 0);
142
-
143
- this.emit('server:created', this.server);
144
- return this.server;
145
- } catch (error) {
146
- this.emit('error', {
147
- type: 'server_creation',
148
- message: `Failed to create server: ${error.message}`,
149
- error
150
- });
151
- throw error;
152
- }
153
- }
154
-
155
- /**
156
- * Create a WebSocket client connection
157
- * @param {string} url - WebSocket URL (ws:// or wss://)
158
- * @param {Object} options - Client options
159
- * @returns {Promise<Object>} Client connection
160
- */
161
- async createClient(url, options = {}) {
162
- if (!this.driver) {
163
- await this._initializeDriver();
164
- }
165
-
166
- const clientOptions = {
167
- ...this.config,
168
- ...options
169
- };
170
-
171
- try {
172
- const client = await this.driver.createClient(url, clientOptions);
173
- this.emit('client:created', client);
174
- return client;
175
- } catch (error) {
176
- this.emit('error', {
177
- type: 'client_creation',
178
- message: `Failed to create client: ${error.message}`,
179
- error
180
- });
181
- throw error;
182
- }
183
- }
184
-
185
- /**
186
- * Add middleware to the WebSocket pipeline
187
- * @param {Function} middleware - Middleware function
188
- */
189
- use(middleware) {
190
- this.middleware.push(middleware);
191
- }
192
-
193
- /**
194
- * Broadcast message to all connected clients
195
- * @param {string|Buffer} message - Message to broadcast
196
- * @param {Function} filter - Optional filter function
197
- */
198
- broadcast(message, filter = null) {
199
- const connections = this.connectionManager.getAll();
200
-
201
- connections.forEach(connection => {
202
- if (!filter || filter(connection)) {
203
- try {
204
- connection.send(message);
205
- } catch (error) {
206
- this.emit('error', {
207
- type: 'broadcast',
208
- message: `Failed to broadcast to connection ${connection.id}`,
209
- error,
210
- connection
211
- });
212
- }
213
- }
214
- });
215
- }
216
-
217
- /**
218
- * Send message to specific connection
219
- * @param {string} connectionId - Connection ID
220
- * @param {string|Buffer} message - Message to send
221
- * @returns {boolean} Success status
222
- */
223
- sendTo(connectionId, message) {
224
- const connection = this.connectionManager.get(connectionId);
225
- if (connection && connection.readyState === 1) { // OPEN
226
- return connection.send(message);
227
- }
228
- return false;
229
- }
230
-
231
- /**
232
- * Get connection by ID
233
- * @param {string} connectionId - Connection ID
234
- * @returns {Object|null} Connection object or null
235
- */
236
- getConnection(connectionId) {
237
- return this.connectionManager.get(connectionId);
238
- }
239
-
240
- /**
241
- * Get all connections
242
- * @returns {Array} Array of connection objects
243
- */
244
- getConnections() {
245
- return this.connectionManager.getAll();
246
- }
247
-
248
- /**
249
- * Get connection statistics
250
- * @returns {Object} Statistics object
251
- */
252
- getStats() {
253
- const connections = this.connectionManager.getAll();
254
-
255
- return {
256
- totalConnections: connections.length,
257
- activeConnections: connections.filter(c => c.readyState === 1).length,
258
- driver: this.config.driver,
259
- uptime: this.server ? Date.now() - this.server.startTime : 0,
260
- memoryUsage: process.memoryUsage(),
261
- config: {
262
- maxPayload: this.config.maxPayload,
263
- pingInterval: this.config.pingInterval,
264
- pingTimeout: this.config.pingTimeout,
265
- compression: this.config.compression
266
- }
267
- };
268
- }
269
-
270
- /**
271
- * Close the WebSocket server
272
- * @returns {Promise<void>}
273
- */
274
- async close() {
275
- if (this.server) {
276
- await this.driver.closeServer(this.server);
277
- this.emit('server:closed');
278
- }
279
-
280
- // Close all connections
281
- const connections = this.connectionManager.getAll();
282
- connections.forEach(connection => {
283
- if (connection.readyState === 1) {
284
- connection.close(1000, 'Server shutting down');
285
- }
286
- });
287
-
288
- this.connectionManager.clear();
289
- this.emit('closed');
290
- }
291
- }
292
-
293
- export default WebSocketFactory;