redweb 0.6.1 → 0.6.4

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,203 +1,203 @@
1
- const WebSocket = require('ws');
2
-
3
- /**
4
- * @typedef {Object} SocketServerOptions
5
- * @property {import('http').Server} [server] - The HTTP server instance to bind the WebSocket server to.
6
- * @property {number} [port=3000] - The port number for the WebSocket server.
7
- * @property {(socket: WebSocket) => void} [connectionOpenCallback] - Callback executed when a client connects.
8
- * @property {(socket: WebSocket) => void} [connectionCloseCallback] - Callback executed when a client disconnects.
9
- * @property {(socket: WebSocket, message: object) => void} [messageCallback] - Callback executed when a message is received.
10
- * @property {Record<string, (socket: WebSocket, data: object) => void>} [messageHandlers] - A dictionary of message types and their corresponding handler functions.
11
- * @property {{ key: string, cert: string } | null} [ssl] - SSL configuration for a secure WebSocket server.
12
- * @property {Array<new () => BaseHandler>} [handlerConfig] - An array of handler classes to use for routing.
13
- */
14
-
15
- const SOCKET_OPTIONS = {
16
- port: 3000,
17
- connectionOpenCallback: undefined,
18
- connectionCloseCallback: undefined,
19
- messageCallback: undefined,
20
- messageHandlers: {
21
- ping: (socket, data) => socket.send(JSON.stringify({ type: 'pong' }))
22
- },
23
- ssl: null
24
- };
25
-
26
- /**
27
- * Broadcasts a message to all connected clients.
28
- * @param {BaseSocketServer} socketServer - The WebSocket server instance.
29
- * @param {object} message - The message to broadcast.
30
- */
31
- function broadcast(socketServer, message) {
32
- socketServer.clients.forEach(client => client.send(JSON.stringify(message)));
33
- }
34
-
35
- /**
36
- * Represents the base WebSocket server.
37
- */
38
- class BaseSocketServer {
39
- /**
40
- * @param {import('http').Server} server - The HTTP server instance to bind the WebSocket server to.
41
- * @param {SocketServerOptions} options - The configuration options for the WebSocket server.
42
- */
43
- constructor(server, options = {}) {
44
- this.wss = new WebSocket.Server({ server });
45
- this.clients = new Map(); // Map of clients by their IP addresses.
46
- Object.assign(this, { ...SOCKET_OPTIONS, ...options });
47
-
48
- this.handlers = this.initHandlers(options.handlerConfig || []);
49
- this.wss.on('connection', this.handleConnection.bind(this));
50
- }
51
-
52
- /**
53
- * Initializes the handler classes.
54
- * @param {Array<new () => BaseHandler>} handlerConfig - Array of handler classes.
55
- * @returns {BaseHandler[]} - Array of handler instances.
56
- */
57
- initHandlers(handlerConfig) {
58
- return handlerConfig.map(HandlerClass => new HandlerClass());
59
- }
60
-
61
- /**
62
- * Adds a new handler to the WebSocket server.
63
- * @param {new () => BaseHandler} HandlerClass - The handler class to add.
64
- */
65
- addHandler(HandlerClass) {
66
- const newHandler = new HandlerClass();
67
- if (this.handlers.find(handler => handler.name === newHandler.name)) {
68
- console.warn(`Handler with name '${newHandler.name}' already exists.`);
69
- return;
70
- }
71
- this.handlers.push(newHandler);
72
- console.log(`Handler '${newHandler.name}' added successfully.`);
73
- }
74
-
75
- /**
76
- * Handles a new WebSocket connection.
77
- * @param {WebSocket} socket - The WebSocket connection instance.
78
- * @param {import('http').IncomingMessage} req - The HTTP request object associated with the connection.
79
- */
80
- handleConnection(socket, req) {
81
- const ip = req.socket.remoteAddress;
82
- console.log(`New client connected: ${ip}`);
83
- if (this.clients.get(ip) !== undefined) {
84
- const oldClient = this.clients.get(ip);
85
- console.warn(`Client ${ip} already connected, disconnecting existing connection.`);
86
- oldClient.send(
87
- JSON.stringify({ msg: 'You are being disconnected because a new client is connected with your IP address.' })
88
- );
89
- oldClient.close();
90
- }
91
- this.clients.set(ip, socket);
92
- socket.isAssigned = false; // Tracks whether the socket has been assigned a handler.
93
-
94
- if (this.connectionOpenCallback) this.connectionOpenCallback(socket);
95
-
96
- socket.on('message', message => this.initialMessageHandler(socket, message, ip));
97
- socket.on('close', () => this.handleClose(socket, ip));
98
- socket.on('error', error => this.handleError(socket, error, ip));
99
- }
100
-
101
- /**
102
- * Processes the initial message to determine if a handler assignment is required.
103
- * @param {WebSocket} socket - The WebSocket connection instance.
104
- * @param {string} message - The received message.
105
- * @param {string} ip - The client's IP address.
106
- */
107
- initialMessageHandler(socket, message, ip) {
108
- try {
109
- const parsedMessage = JSON.parse(message);
110
-
111
- // If the first message is '__handlerConnect', attempt to assign a handler
112
- if (parsedMessage.type === '__handlerConnect') {
113
- this.assignToHandler(socket, parsedMessage);
114
- return;
115
- }
116
-
117
- // If no handler is assigned, use the default messageHandlers or fallback
118
- if (!socket.isAssigned) {
119
- this.handleMessage(socket, parsedMessage, ip);
120
- } else {
121
- throw new Error('Unexpected message after handler assignment');
122
- }
123
- } catch (error) {
124
- console.error(`Error handling initial message from ${ip}:`, error);
125
- socket.close(); // Optionally close the socket for invalid behavior.
126
- }
127
- }
128
-
129
- /**
130
- * Assigns the socket to a specific handler.
131
- * @param {WebSocket} socket - The WebSocket connection instance.
132
- * @param {{ handlerName: string, key?: string }} data - Data containing the handler name and optional authentication key.
133
- */
134
- assignToHandler(socket, connectMessage) {
135
- if (!connectMessage.data) {
136
- console.warn(`No data provided for handlerConnect message.`);
137
- socket.close();
138
- return;
139
- }
140
- const { handlerName, data } = connectMessage.data;
141
- const handler = this.handlers.find(h => h.name === handlerName);
142
- if (!handler) {
143
- console.warn(`Handler not found: ${handlerName}`);
144
- socket.send(JSON.stringify({ error: `Handler '${handlerName}' not found` }));
145
- socket.close();
146
- return;
147
- }
148
-
149
- // Optional: Perform authentication with `key`
150
- socket.removeAllListeners('message');
151
- handler.newConnection(socket, connectMessage.data);
152
- }
153
-
154
- /**
155
- * Handles a message using the default messageHandlers.
156
- * @param {WebSocket} socket - The WebSocket connection instance.
157
- * @param {{ type: string, [key: string]: any }} parsedMessage - The parsed message object.
158
- * @param {string} ip - The client's IP address.
159
- */
160
- handleMessage(socket, parsedMessage, ip) {
161
- const { type, ...data } = parsedMessage;
162
-
163
- if (this.messageCallback) this.messageCallback(socket, parsedMessage);
164
-
165
- if (this.messageHandlers[type]) {
166
- this.messageHandlers[type](socket, data);
167
- } else {
168
- console.warn(`Unhandled message type from ${ip}: ${type}`);
169
- socket.close();
170
- }
171
- }
172
-
173
- /**
174
- * Handles socket disconnection.
175
- * @param {WebSocket} socket - The WebSocket connection instance.
176
- * @param {string} ip - The client's IP address.
177
- */
178
- handleClose(socket, ip) {
179
- console.log(`Client disconnected: ${ip}`);
180
- this.clients.delete(ip);
181
- if (this.connectionCloseCallback) this.connectionCloseCallback(socket);
182
- }
183
-
184
- /**
185
- * Handles socket errors.
186
- * @param {WebSocket} socket - The WebSocket connection instance.
187
- * @param {Error} error - The error object.
188
- * @param {string} ip - The client's IP address.
189
- */
190
- handleError(socket, error, ip) {
191
- console.error(`Socket error from ${ip}:`, error);
192
- }
193
-
194
- /**
195
- * Broadcasts a message to all connected clients.
196
- * @param {object} message - The message to broadcast.
197
- */
198
- broadcast(message) {
199
- broadcast(this, message);
200
- }
201
- }
202
-
203
- module.exports = { BaseSocketServer, SOCKET_OPTIONS };
1
+ const WebSocket = require('ws');
2
+
3
+ /**
4
+ * @typedef {Object} SocketServerOptions
5
+ * @property {import('http').Server} [server] - The HTTP server instance to bind the WebSocket server to.
6
+ * @property {number} [port=3000] - The port number for the WebSocket server.
7
+ * @property {(socket: WebSocket) => void} [connectionOpenCallback] - Callback executed when a client connects.
8
+ * @property {(socket: WebSocket) => void} [connectionCloseCallback] - Callback executed when a client disconnects.
9
+ * @property {(socket: WebSocket, message: object) => void} [messageCallback] - Callback executed when a message is received.
10
+ * @property {Record<string, (socket: WebSocket, data: object) => void>} [messageHandlers] - A dictionary of message types and their corresponding handler functions.
11
+ * @property {{ key: string, cert: string } | null} [ssl] - SSL configuration for a secure WebSocket server.
12
+ * @property {Array<new () => BaseHandler>} [handlerConfig] - An array of handler classes to use for routing.
13
+ */
14
+
15
+ const SOCKET_OPTIONS = {
16
+ port: 3000,
17
+ connectionOpenCallback: undefined,
18
+ connectionCloseCallback: undefined,
19
+ messageCallback: undefined,
20
+ messageHandlers: {
21
+ ping: (socket, data) => socket.send(JSON.stringify({ type: 'pong' }))
22
+ },
23
+ ssl: null
24
+ };
25
+
26
+ /**
27
+ * Broadcasts a message to all connected clients.
28
+ * @param {BaseSocketServer} socketServer - The WebSocket server instance.
29
+ * @param {object} message - The message to broadcast.
30
+ */
31
+ function broadcast(socketServer, message) {
32
+ socketServer.clients.forEach(client => client.send(JSON.stringify(message)));
33
+ }
34
+
35
+ /**
36
+ * Represents the base WebSocket server.
37
+ */
38
+ class BaseSocketServer {
39
+ /**
40
+ * @param {import('http').Server} server - The HTTP server instance to bind the WebSocket server to.
41
+ * @param {SocketServerOptions} options - The configuration options for the WebSocket server.
42
+ */
43
+ constructor(server, options = {}) {
44
+ this.wss = new WebSocket.Server({ server });
45
+ this.clients = new Map(); // Map of clients by their IP addresses.
46
+ Object.assign(this, { ...SOCKET_OPTIONS, ...options });
47
+
48
+ this.handlers = this.initHandlers(options.handlerConfig || []);
49
+ this.wss.on('connection', this.handleConnection.bind(this));
50
+ }
51
+
52
+ /**
53
+ * Initializes the handler classes.
54
+ * @param {Array<new () => BaseHandler>} handlerConfig - Array of handler classes.
55
+ * @returns {BaseHandler[]} - Array of handler instances.
56
+ */
57
+ initHandlers(handlerConfig) {
58
+ return handlerConfig.map(HandlerClass => new HandlerClass());
59
+ }
60
+
61
+ /**
62
+ * Adds a new handler to the WebSocket server.
63
+ * @param {new () => BaseHandler} HandlerClass - The handler class to add.
64
+ */
65
+ addHandler(HandlerClass) {
66
+ const newHandler = new HandlerClass();
67
+ if (this.handlers.find(handler => handler.name === newHandler.name)) {
68
+ console.warn(`Handler with name '${newHandler.name}' already exists.`);
69
+ return;
70
+ }
71
+ this.handlers.push(newHandler);
72
+ console.log(`Handler '${newHandler.name}' added successfully.`);
73
+ }
74
+
75
+ /**
76
+ * Handles a new WebSocket connection.
77
+ * @param {WebSocket} socket - The WebSocket connection instance.
78
+ * @param {import('http').IncomingMessage} req - The HTTP request object associated with the connection.
79
+ */
80
+ handleConnection(socket, req) {
81
+ const ip = req.socket.remoteAddress;
82
+ console.log(`New client connected: ${ip}`);
83
+ if (this.clients.get(ip) !== undefined) {
84
+ const oldClient = this.clients.get(ip);
85
+ console.warn(`Client ${ip} already connected, disconnecting existing connection.`);
86
+ oldClient.send(
87
+ JSON.stringify({ msg: 'You are being disconnected because a new client is connected with your IP address.' })
88
+ );
89
+ oldClient.close();
90
+ }
91
+ this.clients.set(ip, socket);
92
+ socket.isAssigned = false; // Tracks whether the socket has been assigned a handler.
93
+
94
+ if (this.connectionOpenCallback) this.connectionOpenCallback(socket);
95
+
96
+ socket.on('message', message => this.initialMessageHandler(socket, message, ip));
97
+ socket.on('close', () => this.handleClose(socket, ip));
98
+ socket.on('error', error => this.handleError(socket, error, ip));
99
+ }
100
+
101
+ /**
102
+ * Processes the initial message to determine if a handler assignment is required.
103
+ * @param {WebSocket} socket - The WebSocket connection instance.
104
+ * @param {string} message - The received message.
105
+ * @param {string} ip - The client's IP address.
106
+ */
107
+ initialMessageHandler(socket, message, ip) {
108
+ try {
109
+ const parsedMessage = JSON.parse(message);
110
+
111
+ // If the first message is '__handlerConnect', attempt to assign a handler
112
+ if (parsedMessage.type === '__handlerConnect') {
113
+ this.assignToHandler(socket, parsedMessage);
114
+ return;
115
+ }
116
+
117
+ // If no handler is assigned, use the default messageHandlers or fallback
118
+ if (!socket.isAssigned) {
119
+ this.handleMessage(socket, parsedMessage, ip);
120
+ } else {
121
+ throw new Error('Unexpected message after handler assignment');
122
+ }
123
+ } catch (error) {
124
+ console.error(`Error handling initial message from ${ip}:`, error);
125
+ socket.close(); // Optionally close the socket for invalid behavior.
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Assigns the socket to a specific handler.
131
+ * @param {WebSocket} socket - The WebSocket connection instance.
132
+ * @param {{ handlerName: string, key?: string }} data - Data containing the handler name and optional authentication key.
133
+ */
134
+ assignToHandler(socket, connectMessage) {
135
+ if (!connectMessage.data) {
136
+ console.warn(`No data provided for handlerConnect message.`);
137
+ socket.close();
138
+ return;
139
+ }
140
+ const { handlerName, data } = connectMessage.data;
141
+ const handler = this.handlers.find(h => h.name === handlerName);
142
+ if (!handler) {
143
+ console.warn(`Handler not found: ${handlerName}`);
144
+ socket.send(JSON.stringify({ error: `Handler '${handlerName}' not found` }));
145
+ socket.close();
146
+ return;
147
+ }
148
+
149
+ // Optional: Perform authentication with `key`
150
+ socket.removeAllListeners('message');
151
+ handler.newConnection(socket, connectMessage.data);
152
+ }
153
+
154
+ /**
155
+ * Handles a message using the default messageHandlers.
156
+ * @param {WebSocket} socket - The WebSocket connection instance.
157
+ * @param {{ type: string, [key: string]: any }} parsedMessage - The parsed message object.
158
+ * @param {string} ip - The client's IP address.
159
+ */
160
+ handleMessage(socket, parsedMessage, ip) {
161
+ const { type, ...data } = parsedMessage;
162
+
163
+ if (this.messageCallback) this.messageCallback(socket, parsedMessage);
164
+
165
+ if (this.messageHandlers[type]) {
166
+ this.messageHandlers[type](socket, data);
167
+ } else {
168
+ console.warn(`Unhandled message type from ${ip}: ${type}`);
169
+ socket.close();
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Handles socket disconnection.
175
+ * @param {WebSocket} socket - The WebSocket connection instance.
176
+ * @param {string} ip - The client's IP address.
177
+ */
178
+ handleClose(socket, ip) {
179
+ console.log(`Client disconnected: ${ip}`);
180
+ this.clients.delete(ip);
181
+ if (this.connectionCloseCallback) this.connectionCloseCallback(socket);
182
+ }
183
+
184
+ /**
185
+ * Handles socket errors.
186
+ * @param {WebSocket} socket - The WebSocket connection instance.
187
+ * @param {Error} error - The error object.
188
+ * @param {string} ip - The client's IP address.
189
+ */
190
+ handleError(socket, error, ip) {
191
+ console.error(`Socket error from ${ip}:`, error);
192
+ }
193
+
194
+ /**
195
+ * Broadcasts a message to all connected clients.
196
+ * @param {object} message - The message to broadcast.
197
+ */
198
+ broadcast(message) {
199
+ broadcast(this, message);
200
+ }
201
+ }
202
+
203
+ module.exports = { BaseSocketServer, SOCKET_OPTIONS };
@@ -1,20 +1,20 @@
1
- const https = require('https');
2
- const loadSslConfig = require('../sslConfig');
3
- const { BaseSocketServer } = require('./BaseSocketServer');
4
-
5
- /**
6
- * Secure WebSocket Server
7
- * @param {SocketServerOptions} options - Configuration options for SecureSocketServer.
8
- * @return {Object} WebSocket server instance.
9
- */
10
- class SecureSocketServer extends BaseSocketServer {
11
- constructor(options = {}) {
12
- const sslOptions = loadSslConfig(options.ssl);
13
- const server = https.createServer(sslOptions);
14
- super(server, options);
15
- server.listen(this.port, () => console.log(`RedWeb SecureSocketServer listening on port ${this.port}`));
16
- return this;
17
- }
18
- }
19
-
20
- module.exports = SecureSocketServer;
1
+ const https = require('https');
2
+ const loadSslConfig = require('../sslConfig');
3
+ const { BaseSocketServer } = require('./BaseSocketServer');
4
+
5
+ /**
6
+ * Secure WebSocket Server
7
+ * @param {SocketServerOptions} options - Configuration options for SecureSocketServer.
8
+ * @return {Object} WebSocket server instance.
9
+ */
10
+ class SecureSocketServer extends BaseSocketServer {
11
+ constructor(options = {}) {
12
+ const sslOptions = loadSslConfig(options.ssl);
13
+ const server = https.createServer(sslOptions);
14
+ super(server, options);
15
+ server.listen(this.port, () => console.log(`RedWeb SecureSocketServer listening on port ${this.port}`));
16
+ return this;
17
+ }
18
+ }
19
+
20
+ module.exports = SecureSocketServer;
@@ -1,18 +1,18 @@
1
- const http = require('http');
2
- const { BaseSocketServer } = require('./BaseSocketServer');
3
-
4
- /**
5
- * WebSocket Server
6
- * @param {SocketServerOptions} options - Configuration options for SocketServer.
7
- * @return {Object} WebSocket server instance.
8
- */
9
- class SocketServer extends BaseSocketServer {
10
- constructor(options = {}) {
11
- const server = options?.server || http.createServer();
12
- super(server, options);
13
- server.listen(this.port, () => console.log(`RedWeb SocketServer listening on port ${this.port}`));
14
- return this;
15
- }
16
- }
17
-
18
- module.exports = SocketServer;
1
+ const http = require('http');
2
+ const { BaseSocketServer } = require('./BaseSocketServer');
3
+
4
+ /**
5
+ * WebSocket Server
6
+ * @param {SocketServerOptions} options - Configuration options for SocketServer.
7
+ * @return {Object} WebSocket server instance.
8
+ */
9
+ class SocketServer extends BaseSocketServer {
10
+ constructor(options = {}) {
11
+ const server = options?.server || http.createServer();
12
+ super(server, options);
13
+ server.listen(this.port, () => console.log(`RedWeb SocketServer listening on port ${this.port}`));
14
+ return this;
15
+ }
16
+ }
17
+
18
+ module.exports = SocketServer;
package/src/ws/index.js CHANGED
@@ -1,6 +1,6 @@
1
- const { SOCKET_OPTIONS } = require('./BaseSocketServer');
2
- module.exports = {
3
- SecureSocketServer: require('./SecureSocketServer'),
4
- SocketServer: require('./SocketServer'),
5
- SOCKET_OPTIONS
1
+ const { SOCKET_OPTIONS } = require('./BaseSocketServer');
2
+ module.exports = {
3
+ SecureSocketServer: require('./SecureSocketServer'),
4
+ SocketServer: require('./SocketServer'),
5
+ SOCKET_OPTIONS
6
6
  }