redweb 0.6.9 → 0.7.0

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/README.md CHANGED
@@ -1,239 +1,192 @@
1
+ Here is the **fully updated and cleaned-up `README.md`** for RedWeb, now featuring a **working broadcast chat example** using `allowDuplicateConnections`:
2
+
3
+ ---
4
+
1
5
  # RedWeb
2
6
 
3
- RedWeb is a simple and flexible Node.js framework built on top of Express.js and WebSocket. It allows you to quickly set up web servers and WebSocket servers with customizable options.
7
+ **RedWeb** is a flexible Node.js framework built on top of **Express.js** and **WebSocket**. It enables quick setup of HTTP(S) and WebSocket servers with a modular route and handler system.
4
8
 
5
- ## Installation
9
+ ---
6
10
 
7
- To install RedWeb, use npm:
11
+ ## 📦 Installation
8
12
 
9
13
  ```bash
10
14
  npm install redweb
11
15
  ```
12
16
 
13
- ## Usage
14
-
15
- ### Basic Example
17
+ ---
16
18
 
17
- Initialize your RedWeb instance with the default options:
19
+ ## 🚀 Quick Start
18
20
 
19
- ```javascript
21
+ ```js
20
22
  const { HttpServer, SocketServer } = require('redweb');
21
23
 
22
- // HTTP server with default configuration
23
24
  const httpServer = new HttpServer();
24
-
25
- // WebSocket server with default configuration
26
25
  const socketServer = new SocketServer();
27
26
  ```
28
27
 
29
- ### Custom Configuration
30
-
31
- #### HTTP Server with HTMX Rendering
28
+ ---
32
29
 
33
- RedWeb now supports dynamic rendering of `.htmx` files using `enableHtmxRendering`.
30
+ ## 🌐 HTTP Server Example (HTMX Support)
34
31
 
35
- ```javascript
32
+ ```js
36
33
  const { HttpServer, METHODS } = require('redweb');
37
34
 
38
- const options = {
39
- port: 3000,
40
- publicPaths: ['./public'],
41
- enableHtmxRendering: true, // Enable .htmx rendering
42
- services: [
43
- {
44
- serviceName: '/submit-form',
45
- method: METHODS.POST,
46
- function: (req, res) => {
47
- const { name, email, message } = req.body;
48
- if (!name || !email || !message) {
49
- return res.status(400).json({ error: 'All fields are required' });
50
- }
51
- res.status(200).json({ success: 'Form submitted successfully' });
52
- }
53
- }
54
- ]
55
- };
56
-
57
- const app = new HttpServer(options);
35
+ new HttpServer({
36
+ port: 3000,
37
+ publicPaths: ['./public'],
38
+ enableHtmxRendering: true,
39
+ services: [
40
+ {
41
+ serviceName: '/submit',
42
+ method: METHODS.POST,
43
+ function: (req, res) => {
44
+ if (!req.body.name) return res.status(400).json({ error: 'Missing name' });
45
+ res.status(200).json({ message: `Thanks, ${req.body.name}!` });
46
+ }
47
+ }
48
+ ]
49
+ });
58
50
  ```
59
51
 
60
- Place `.htmx` files in the specified `publicPaths`, and they will be dynamically rendered.
61
-
52
+ `.htmx` files under `public/` will render server-side.
62
53
  Example:
63
54
 
64
- **File: `public/index.htmx`**
65
- ```javascript
66
- const name = 'RedWeb User';
67
-
55
+ ```html
56
+ <!-- public/hello.htmx -->
68
57
  <@>
69
- <h1>Hello, {{name}}!</h1>
58
+ <h1>Hello, {{name}}!</h1>
70
59
  <@/>
71
60
  ```
72
61
 
73
- Accessing `/index.htmx` will render:
74
- ```html
75
- <h1>Hello, RedWeb User!</h1>
76
- ```
77
-
78
- #### HTTPS Server
79
-
80
- ```javascript
81
- const { HttpsServer } = require('redweb');
82
-
83
- const options = {
84
- port: 3443,
85
- ssl: {
86
- key: './path/to/key.pem',
87
- cert: './path/to/cert.pem'
88
- },
89
- publicPaths: ['./public'],
90
- enableHtmxRendering: true // Enable .htmx rendering
91
- };
92
-
93
- const app = new HttpsServer(options);
94
- ```
95
-
96
- ### WebSocket Server with Routes and Handlers
62
+ ---
97
63
 
98
- RedWeb uses **route-based architecture** for WebSocket connections, allowing you to modularize and secure your WebSocket message handling logic.
64
+ ## 🔌 WebSocket Broadcast Chat (🔥 Instant Testing)
99
65
 
100
- #### Defining a Custom Handler
66
+ ### 1. `ChatHandler.js`
101
67
 
102
- Handlers extend the `BaseHandler` class and manage their own connections and message types.
103
-
104
- ```javascript
68
+ ```js
105
69
  const { BaseHandler } = require('redweb');
106
70
 
107
71
  class ChatHandler extends BaseHandler {
108
- constructor() {
109
- super('chat');
110
- }
111
-
112
- onMessage(socket, message) {
113
- console.log(`Received chat message: ${message.text}`);
114
- socket.send(JSON.stringify({ type: 'chatResponse', message: 'Hello!' }));
115
- }
72
+ constructor() {
73
+ super('chat');
74
+ }
75
+
76
+ onMessage(socket, message) {
77
+ const text = message.text;
78
+ console.log(`Broadcasting: ${text}`);
79
+ socket.broadcast({ type: 'chat', text });
80
+ }
116
81
  }
117
82
 
118
83
  module.exports = ChatHandler;
119
84
  ```
120
85
 
121
- #### Defining a WebSocket Route
86
+ ---
122
87
 
123
- Routes group handlers and specify the WebSocket path.
88
+ ### 2. `ChatRoute.js`
124
89
 
125
- ```javascript
90
+ ```js
126
91
  const { SocketRoute } = require('redweb');
127
92
  const ChatHandler = require('./ChatHandler');
128
93
 
129
94
  class ChatRoute extends SocketRoute {
130
- constructor() {
131
- super({
132
- path: '/chat',
133
- handlers: [ChatHandler]
134
- });
135
- }
95
+ constructor() {
96
+ super({
97
+ path: '/chat',
98
+ handlers: [ChatHandler],
99
+ allowDuplicateConnections: true // key for local testing!
100
+ });
101
+ }
136
102
  }
137
103
 
138
104
  module.exports = ChatRoute;
139
105
  ```
140
106
 
141
- #### Setting Up a WebSocket Server with Routes
107
+ ---
108
+
109
+ ### 3. `server.js`
142
110
 
143
- ```javascript
111
+ ```js
144
112
  const { SocketServer } = require('redweb');
145
113
  const ChatRoute = require('./ChatRoute');
146
114
 
147
115
  new SocketServer({
148
- port: 3000,
149
- routes: [ChatRoute]
116
+ port: 3000,
117
+ routes: [ChatRoute]
150
118
  });
151
119
  ```
152
120
 
153
- ### Adding Routes Dynamically
121
+ ---
154
122
 
155
- Routes can be added to the WebSocket server after initialization.
123
+ ### 4. `client.html`
156
124
 
157
- ```javascript
158
- const { SocketServer, SocketRoute } = require('redweb');
159
- const ChatHandler = require('./ChatHandler');
160
-
161
- class ChatRoute extends SocketRoute {
162
- constructor() {
163
- super({
164
- path: '/chat',
165
- handlers: [ChatHandler]
166
- });
167
- }
168
- }
169
-
170
- const socketServer = new SocketServer({ port: 3000 });
171
-
172
- // Dynamically add a new route
173
- const chatRoute = new ChatRoute();
174
- socketServer.routes.push(chatRoute);
125
+ ```html
126
+ <!DOCTYPE html>
127
+ <html>
128
+ <body>
129
+ <h1>Broadcast Chat</h1>
130
+ <input id="msg" placeholder="Type message..." />
131
+ <button onclick="send()">Send</button>
132
+ <pre id="log"></pre>
133
+
134
+ <script>
135
+ const log = document.getElementById('log');
136
+ const ws = new WebSocket('ws://localhost:3000/chat');
137
+
138
+ ws.onmessage = (e) => {
139
+ const msg = JSON.parse(e.data);
140
+ log.textContent += `\n${msg.text}`;
141
+ };
142
+
143
+ function send() {
144
+ const text = document.getElementById('msg').value;
145
+ ws.send(JSON.stringify({ type: 'chat', text }));
146
+ }
147
+ </script>
148
+ </body>
149
+ </html>
175
150
  ```
176
151
 
177
- ### Client Communication with a Route
178
-
179
- The client connects to the WebSocket server using the specified route.
152
+ Open multiple tabs to test!
180
153
 
181
- ```javascript
182
- const WebSocket = require('ws');
154
+ ---
183
155
 
184
- const ws = new WebSocket('ws://localhost:3000/chat');
156
+ ## 🔧 Options
185
157
 
186
- ws.on('open', () => {
187
- ws.send(JSON.stringify({ type: 'chat', text: 'Hello there!' }));
188
- });
158
+ ### HTTP / HTTPS Server Options
189
159
 
190
- ws.on('message', (message) => {
191
- console.log('Received:', message);
192
- });
193
- ```
160
+ | Option | Type | Default | Description |
161
+ | --------------------- | --------- | -------------- | ------------------------------ |
162
+ | `port` | number | `80` | Port to listen on |
163
+ | `bind` | string | `'0.0.0.0'` | Bind address |
164
+ | `publicPaths` | string\[] | `['./public']` | Serve static and `.htmx` files |
165
+ | `services` | object\[] | `[]` | REST endpoints |
166
+ | `enableHtmxRendering` | boolean | `false` | Enables `.htmx` file rendering |
167
+ | `ssl` | object | `undefined` | Used in `HttpsServer` |
194
168
 
195
- ### Managing Connected Clients
169
+ ---
196
170
 
197
- RedWeb's WebSocket server maintains a list of connected clients by their IP addresses for each route. This list is automatically updated when clients connect or disconnect.
198
-
199
- ```javascript
200
- const { SocketRoute } = require('redweb');
201
-
202
- class ChatRoute extends SocketRoute {
203
- constructor() {
204
- super({
205
- path: '/chat',
206
- handlers: []
207
- });
208
- }
209
-
210
- onConnection(socket) {
211
- console.log('New client connected:', socket.remoteAddress);
212
- }
213
- }
214
-
215
- module.exports = ChatRoute;
216
- ```
171
+ ### WebSocket Server Options
217
172
 
218
- ## Options
173
+ | Option | Type | Default | Description |
174
+ | --------------------------- | ------------------- | ------- | ----------------------------------- |
175
+ | `port` | number | `3000` | WebSocket port |
176
+ | `routes` | `SocketRoute[]` | `[]` | List of custom route classes |
177
+ | `allowDuplicateConnections` | boolean (per route) | `false` | Allow multiple clients from same IP |
219
178
 
220
- ### HttpServer and HttpsServer Options
179
+ ---
221
180
 
222
- - **port**: Port number (default: `80`).
223
- - **bind**: Bind address (default: `0.0.0.0`).
224
- - **publicPaths**: Array of paths to serve static files (default: `['./public']`).
225
- - **services**: Array of services with endpoints and handlers (default: `[]`).
226
- - **listenCallback**: Function to execute once the server starts listening.
227
- - **encoding**: Encoding type for request bodies (`'json'` or `'urlencoded'`).
228
- - **ssl**: SSL configuration for HTTPS server (`{ key: './path/to/key.pem', cert: './path/to/cert.pem' }`).
229
- - **enableHtmxRendering**: Enable dynamic rendering of `.htmx` files (default: `false`).
181
+ ## 🆕 0.7.0 Update Highlights
230
182
 
231
- ### SocketServer Options
183
+ * `allowDuplicateConnections` for multi-tab testing
184
+ * ✅ Robust message validation
185
+ * ✅ `socket.broadcast()` now excludes sender
186
+ * ✅ Better error handling
232
187
 
233
- - **port**: Port number (default: `3000`).
234
- - **routes**: Array of `SocketRoute` classes to define WebSocket routes and handlers.
235
- - **ssl**: SSL configuration for SecureSocketServer (`{ key: './path/to/key.pem', cert: './path/to/cert.pem' }`).
188
+ ---
236
189
 
237
- ## License
190
+ ## 🪪 License
238
191
 
239
- MIT License
192
+ MIT
package/index.d.ts CHANGED
@@ -1,177 +1,98 @@
1
1
  declare module 'redweb' {
2
- import { Request, Response } from 'express';
3
- import { Server as HTTPServer } from 'http';
4
- import { Server as HTTPSServer } from 'https';
5
- import WebSocket from 'ws';
6
-
7
- /**
8
- * RedWeb encoding types.
9
- */
2
+ import { Application } from 'express';
3
+ import { CorsOptions } from 'cors';
4
+ import { Server as HttpServer } from 'http';
5
+ import { WebSocket } from 'ws';
6
+
10
7
  export type RedWebEncoding = 'json' | 'urlencoded';
11
-
12
- /**
13
- * Service configuration for RedWeb.
14
- */
15
- export interface Service {
16
- serviceName: string;
17
- method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head';
18
- function: (req: Request, res: Response) => void;
19
- }
20
-
21
- /**
22
- * Options for configuring a RedWeb server.
23
- */
8
+
24
9
  export interface RedWebOptions {
25
- port?: number;
26
- bind?: string;
27
- publicPaths?: string[];
28
- services?: Service[];
29
- listenCallback?: () => void;
30
- encoding?: RedWebEncoding;
31
- ssl?: {
32
- key: string;
33
- cert: string;
34
- };
35
- corsOptions?: import('cors').CorsOptions;
36
- enableHtmxRendering?: boolean; // New flag to enable HTMX rendering
37
- }
38
-
39
- /**
40
- * Configuration for a WebSocket handler.
41
- */
42
- export interface HandlerConfig {
43
- name: string;
44
- handlers: {
45
- [type: string]: (socket: WebSocket, data: any) => void;
46
- };
10
+ port?: number;
11
+ bind?: string;
12
+ publicPaths?: string[];
13
+ services?: Array<{ serviceName: string; method: string; function: Function }>;
14
+ listenCallback?: () => void;
15
+ encoding?: RedWebEncoding;
16
+ ssl?: { key: string; cert: string };
17
+ server?: Application;
18
+ corsOptions?: CorsOptions;
19
+ enableHtmxRendering?: boolean;
47
20
  }
48
-
49
- /**
50
- * Options for configuring a WebSocket server.
51
- */
21
+
52
22
  export interface SocketServerOptions {
53
- port?: number;
54
- connectionOpenCallback?: (socket: WebSocket) => void;
55
- connectionCloseCallback?: (socket: WebSocket) => void;
56
- messageCallback?: (socket: WebSocket, message: string) => void;
57
- messageHandlers?: {
58
- [type: string]: (socket: WebSocket, data: any) => void;
59
- };
60
- ssl?: {
61
- key: string;
62
- cert: string;
63
- };
64
- routes?: Array<new () => SocketRoute>;
23
+ server?: HttpServer;
24
+ port?: number;
25
+ routes?: Array<new () => SocketRoute>;
26
+ ssl?: { key: string; cert: string };
65
27
  }
66
-
67
- /**
68
- * WebSocket route configuration.
69
- */
28
+
70
29
  export interface SocketRouteConfig {
71
- path: string;
72
- handlers: Array<new () => BaseHandler>;
30
+ path: string;
31
+ handlers: Array<new () => BaseHandler>;
32
+ allowDuplicateConnections?: boolean;
73
33
  }
74
-
75
- /**
76
- * Represents a WebSocket route.
77
- */
78
- export class SocketRoute {
79
- path: string;
80
- handlers: BaseHandler[];
81
-
82
- constructor(config: SocketRouteConfig);
83
-
84
- addHandler(HandlerClass: new () => BaseHandler): void;
85
- handleConnection(socket: WebSocket, req: import('http').IncomingMessage): void;
86
- handleMessage(socket: WebSocket, data: any): void;
87
- handleClose(socket: WebSocket): void;
88
- handleError(socket: WebSocket, error: Error): void;
89
- }
90
-
91
- /**
92
- * Base class for WebSocket handlers.
93
- */
34
+
94
35
  export class BaseHandler {
95
- name: string;
96
-
97
- constructor(name: string);
98
- onMessage(socket: WebSocket, message: Object): void;
99
- onInitialContact(socket: WebSocket): void;
100
- onClose(socket: WebSocket): void;
36
+ name: string;
37
+ constructor(name: string);
38
+ handleMessage(
39
+ socket: WebSocket & {
40
+ sendJson: (message: object) => void;
41
+ broadcast: (message: object) => void;
42
+ },
43
+ message: any
44
+ ): void;
45
+ onMessage(socket: WebSocket, message: any): void;
46
+ onInitialContact(socket: WebSocket): void;
101
47
  }
102
-
103
- /**
104
- * Base WebSocket server class.
105
- */
106
- export class BaseSocketServer {
107
- routes: SocketRoute[];
108
-
109
- constructor(server: HTTPServer | HTTPSServer, options?: SocketServerOptions);
110
- handleUpgrade(req: import('http').IncomingMessage, socket: import('net').Socket, head: Buffer): void;
111
- addRoute(route: new () => SocketRoute): void;
112
- }
113
-
114
- /**
115
- * HTTP server class.
116
- */
117
- export class HttpServer {
118
- constructor(options?: RedWebOptions);
48
+
49
+ export class SocketRoute {
50
+ path: string;
51
+ handlers: BaseHandler[];
52
+ clients: Map<string, WebSocket>;
53
+ allowDuplicateConnections?: boolean;
54
+ constructor(config: SocketRouteConfig);
55
+ addHandler(handler: new () => BaseHandler): void;
56
+ handleMessage(sock: WebSocket, data: any): void;
119
57
  }
120
-
121
- /**
122
- * HTTPS server class.
123
- */
124
- export class HttpsServer {
125
- constructor(options?: RedWebOptions);
58
+
59
+ export class BaseSocketServer {
60
+ clients: Map<string, WebSocket>;
61
+ server: HttpServer;
62
+ routes: SocketRoute[];
63
+ constructor(server: HttpServer, options?: SocketServerOptions);
64
+ addRoute(route: new () => SocketRoute): void;
126
65
  }
127
-
128
- /**
129
- * WebSocket server class.
130
- */
66
+
131
67
  export class SocketServer extends BaseSocketServer {
132
- constructor(options?: SocketServerOptions);
68
+ constructor(options?: SocketServerOptions);
133
69
  }
134
-
135
- /**
136
- * Secure WebSocket server class.
137
- */
70
+
138
71
  export class SecureSocketServer extends BaseSocketServer {
139
- constructor(options?: SocketServerOptions);
72
+ constructor(options?: SocketServerOptions);
140
73
  }
141
-
142
- /**
143
- * SSL configuration loader.
144
- */
145
- export function loadSslConfig(sslOptions: { key: string; cert: string }): { key: string; cert: string };
146
-
147
- /**
148
- * Constants for encoding types.
149
- */
150
- export const ENCODINGS: {
151
- json: 'json';
152
- urlencoded: 'urlencoded';
153
- };
154
-
155
- /**
156
- * Constants for HTTP methods.
157
- */
74
+
75
+ export class HttpServer {
76
+ constructor(options?: RedWebOptions);
77
+ }
78
+
79
+ export class HttpsServer {
80
+ constructor(options?: RedWebOptions);
81
+ }
82
+
158
83
  export const METHODS: {
159
- POST: 'post';
160
- GET: 'get';
161
- PUT: 'put';
162
- DELETE: 'delete';
163
- PATCH: 'patch';
164
- OPTIONS: 'options';
165
- HEAD: 'head';
84
+ GET: 'get';
85
+ POST: 'post';
86
+ PUT: 'put';
87
+ DELETE: 'delete';
88
+ };
89
+
90
+ export const ENCODINGS: {
91
+ json: 'json';
92
+ urlencoded: 'urlencoded';
166
93
  };
167
-
168
- /**
169
- * Default HTTP options.
170
- */
94
+
171
95
  export const HTTP_OPTIONS: RedWebOptions;
172
-
173
- /**
174
- * Default socket options.
175
- */
176
96
  export const SOCKET_OPTIONS: SocketServerOptions;
177
- }
97
+ }
98
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redweb",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "A way to quickly set up an express server",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -16,7 +16,7 @@ class BaseHandler {
16
16
  /**
17
17
  * Handles an incoming message and routes it to the appropriate handler function.
18
18
  * @param {WebSocket & {sendJson: (message: Object) => void, broadcast: (message: Object) => void}} socket - The WebSocket connection that sent the message.
19
- * @param {string} message - The incoming message in JSON string format.
19
+ * @param {any} message - The incoming message in parsed JSON.
20
20
  */
21
21
  handleMessage(socket, message) {
22
22
  this.onMessage(socket, message);
@@ -25,7 +25,7 @@ class BaseHandler {
25
25
  /**
26
26
  * Method to be overriden to process messages.
27
27
  * @param {WebSocket} socket - The WebSocket connection that sent the message.
28
- * @param {string} message - The incoming message in JSON string format.
28
+ * @param {any} message - The incoming message in parsed JSON.
29
29
  */
30
30
  onMessage(socket, message) {
31
31
  throw "Not yet implemented!";
@@ -1,5 +1,6 @@
1
1
  const { WebSocketServer } = require("ws");
2
2
  const { sendJson, broadcast } = require("./util");
3
+ const { randomUUID } = require("crypto");
3
4
 
4
5
  /**
5
6
  * Represents a WebSocket route configuration.
@@ -10,9 +11,10 @@ class SocketRoute {
10
11
  * Creates a new instance of `SocketRoute`.
11
12
  * @param {Object} options - Configuration options for the WebSocket route.
12
13
  * @param {string} options.path - The path of the WebSocket route (e.g., `/chat`, `/lobby`).
14
+ * @param {boolean} options.allowDuplicateConnections - Whether to allow multiple connections from the same client IP address.
13
15
  * @param {import('./BaseHandler').BaseHandler[]} options.handlers - An array of handler instances that manage connections and messages for this route.
14
16
  */
15
- constructor({path, handlers } = {}) {
17
+ constructor({path, handlers, allowDuplicateConnections } = {}) {
16
18
  if (!path) {
17
19
  throw new Error('A `path` must be specified for the SocketRoute.');
18
20
  }
@@ -34,6 +36,7 @@ class SocketRoute {
34
36
  this.clients = new Map();
35
37
  this.server = new WebSocketServer({ noServer: true, path });
36
38
  this.server.on('connection', this.handleConnection.bind(this));
39
+ this.allowDuplicateConnections = allowDuplicateConnections;
37
40
  }
38
41
  /**
39
42
  * Adds a new handler to the WebSocket server.
@@ -56,23 +59,37 @@ class SocketRoute {
56
59
  handleConnection(socket, req) {
57
60
  const ip = req.socket.remoteAddress;
58
61
  console.log(`New client connected: ${ip}`);
59
- if (this.clients.get(ip) !== undefined) {
60
- const oldClient = this.clients.get(ip);
61
- console.warn(`Client ${ip} already connected, disconnecting existing connection.`);
62
- oldClient.send(
63
- JSON.stringify({ msg: 'You are being disconnected because a new client is connected with your IP address.' })
64
- );
65
- oldClient.close();
62
+ if (this.allowDuplicateConnections) {
63
+ this.clients.set(randomUUID(), socket);
64
+ } else {
65
+ if (this.clients.get(ip) !== undefined) {
66
+ const oldClient = this.clients.get(ip);
67
+ console.warn(`Client ${ip} already connected, disconnecting existing connection.`);
68
+ oldClient.send(
69
+ JSON.stringify({ msg: 'You are being disconnected because a new client is connected with your IP address.' })
70
+ );
71
+ oldClient.close();
72
+ }
73
+ this.clients.set(ip, socket);
66
74
  }
67
- this.clients.set(ip, socket);
68
75
  socket.isAssigned = false; // Tracks whether the socket has been assigned a handler.
69
76
  socket.sendJson = (data) => sendJson(socket, data);
70
- socket.broadcast = (data) => broadcast([...this.clients.values()], data);
77
+ socket.broadcast = (data) => broadcast([...this.clients.values()].filter(sock => sock !== socket), data);
71
78
 
72
79
  this.connectionOpenCallback(socket);
73
- socket.on('message', (message) => this.handleMessage(socket, JSON.parse(message)));
74
80
  socket.on('close', this.handleClose.bind(this));
75
81
  socket.on('error', this.handleError.bind(this));
82
+ socket.on('message', (message) => {
83
+ try {
84
+ const parsed = JSON.parse(message);
85
+ this.handleMessage(socket, parsed);
86
+ } catch (error) {
87
+ console.error(`Error parsing message from ${ip}:`, error);
88
+ socket.sendJson({ error: 'Invalid JSON format' });
89
+ socket.close();
90
+ return;
91
+ }
92
+ });
76
93
  }
77
94
 
78
95
  connectionOpenCallback(socket) {
@@ -85,7 +102,13 @@ class SocketRoute {
85
102
  sendJson(sock, {error: `No such handler ${data.type}`});
86
103
  sock.close();
87
104
  } else {
88
- handler.handleMessage(sock, data);
105
+ try {
106
+ handler.handleMessage(sock, data);
107
+ } catch (error) {
108
+ console.error(`Error handling message in handler ${handler.name}:`, error);
109
+ sendJson(sock, { error: `${error.message}` });
110
+ sock.close();
111
+ }
89
112
  }
90
113
  }
91
114