Skip to content

Commit be7ed3a

Browse files
author
Brian Genisio
committed
Adding optional websockets to the server example
1 parent 21ef59c commit be7ed3a

File tree

4 files changed

+196
-16
lines changed

4 files changed

+196
-16
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ modal.updateContent(newHelpContent);
9898
modal.destroy();
9999
```
100100

101+
## Server
102+
103+
This template includes a local development server (`server.js`) that provides:
104+
- Static file serving for your application
105+
- WebSocket support for real-time messaging
106+
- A REST API for triggering client-side alerts
107+
108+
### Starting the Server
109+
110+
```bash
111+
node server.js
112+
```
113+
114+
The server will start on `http://localhost:3000` by default.
115+
116+
### WebSocket Messaging API
117+
118+
The server provides a `POST /message` endpoint that allows you to send real-time messages to connected clients. This can be used to signal changes in the client during events like "Run" or "Submit". When a message is sent, the preview window with the application open will display an alert with the message.
119+
120+
It uses the `ws` package, so if you want to use it, install `ws`.
121+
122+
```
123+
npm install ws
124+
```
125+
126+
#### Endpoint: `POST /message`
127+
128+
**Request Format:**
129+
```json
130+
{
131+
"message": "Your message here"
132+
}
133+
```
134+
135+
**Example using curl:**
136+
```bash
137+
curl -X POST http://localhost:3000/message \
138+
-H "Content-Type: application/json" \
139+
-d '{"message": "Hello from the server!"}'
140+
```
141+
101142
## File Structure
102143

103144
```

app.js

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,59 @@
11
// app.js
22
(function() {
33
const status = document.getElementById('status');
4+
let websocket = null;
45

56
function setStatus(msg) {
67
status.textContent = msg;
78
}
89

10+
// Initialize WebSocket connection
11+
function initializeWebSocket() {
12+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
13+
const host = window.location.host;
14+
const wsUrl = `${protocol}//${host}`;
15+
16+
try {
17+
websocket = new WebSocket(wsUrl);
18+
19+
websocket.onopen = function(event) {
20+
console.log('WebSocket connected');
21+
setStatus('Ready (WebSocket connected)');
22+
};
23+
24+
websocket.onmessage = function(event) {
25+
try {
26+
const data = JSON.parse(event.data);
27+
if (data.type === 'message' && data.message) {
28+
alert(data.message);
29+
}
30+
} catch (error) {
31+
console.error('Error parsing WebSocket message:', error);
32+
}
33+
};
34+
35+
websocket.onclose = function(event) {
36+
console.log('WebSocket disconnected');
37+
setStatus('Ready (WebSocket disconnected)');
38+
39+
// Attempt to reconnect after 3 seconds
40+
setTimeout(() => {
41+
console.log('Attempting to reconnect WebSocket...');
42+
initializeWebSocket();
43+
}, 3000);
44+
};
45+
46+
websocket.onerror = function(error) {
47+
console.error('WebSocket error:', error);
48+
setStatus('Ready (WebSocket error)');
49+
};
50+
51+
} catch (error) {
52+
console.error('Failed to create WebSocket connection:', error);
53+
setStatus('Ready (WebSocket unavailable)');
54+
}
55+
}
56+
957
// Load help content and initialize modal
1058
async function initializeHelpModal() {
1159
try {
@@ -32,10 +80,15 @@
3280
}
3381
}
3482

35-
// Initialize when DOM is ready
83+
// Initialize both help modal and WebSocket when DOM is ready
84+
function initialize() {
85+
initializeHelpModal();
86+
initializeWebSocket();
87+
}
88+
3689
if (document.readyState === 'loading') {
37-
document.addEventListener('DOMContentLoaded', initializeHelpModal);
90+
document.addEventListener('DOMContentLoaded', initialize);
3891
} else {
39-
initializeHelpModal();
92+
initialize();
4093
}
4194
})();

package.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

server.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,23 @@ const fs = require('fs');
33
const path = require('path');
44
const url = require('url');
55

6+
// Try to load WebSocket module, fallback if not available
7+
let WebSocket = null;
8+
let isWebSocketAvailable = false;
9+
try {
10+
WebSocket = require('ws');
11+
isWebSocketAvailable = true;
12+
console.log('WebSocket support enabled');
13+
} catch (error) {
14+
console.log('WebSocket support disabled (ws package not installed)');
15+
console.log('Install with: npm install ws');
16+
}
17+
618
const PORT = 3000;
719

20+
// Track connected WebSocket clients
21+
const wsClients = new Set();
22+
823
// MIME types for different file extensions
924
const mimeTypes = {
1025
'.html': 'text/html',
@@ -39,10 +54,69 @@ function serveFile(filePath, res) {
3954
});
4055
}
4156

57+
// Handle POST requests
58+
function handlePostRequest(req, res) {
59+
const parsedUrl = url.parse(req.url, true);
60+
61+
if (parsedUrl.pathname === '/message') {
62+
let body = '';
63+
64+
req.on('data', chunk => {
65+
body += chunk.toString();
66+
});
67+
68+
req.on('end', () => {
69+
try {
70+
const data = JSON.parse(body);
71+
const message = data.message;
72+
73+
if (!message) {
74+
res.writeHead(400, { 'Content-Type': 'application/json' });
75+
res.end(JSON.stringify({ error: 'Message is required' }));
76+
return;
77+
}
78+
79+
// Check if WebSocket is available
80+
if (!isWebSocketAvailable) {
81+
res.writeHead(503, { 'Content-Type': 'application/json' });
82+
res.end(JSON.stringify({
83+
error: 'WebSocket functionality not available',
84+
details: 'Install the ws package with: npm install ws'
85+
}));
86+
return;
87+
}
88+
89+
// Broadcast message to all connected WebSocket clients
90+
wsClients.forEach(client => {
91+
if (client.readyState === WebSocket.OPEN) {
92+
client.send(JSON.stringify({ type: 'message', message: message }));
93+
}
94+
});
95+
96+
res.writeHead(200, { 'Content-Type': 'application/json' });
97+
res.end(JSON.stringify({ success: true, clientCount: wsClients.size }));
98+
99+
} catch (error) {
100+
res.writeHead(400, { 'Content-Type': 'application/json' });
101+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
102+
}
103+
});
104+
} else {
105+
res.writeHead(404, { 'Content-Type': 'text/plain' });
106+
res.end('Not found');
107+
}
108+
}
109+
42110
// Create HTTP server
43111
const server = http.createServer((req, res) => {
44112
const parsedUrl = url.parse(req.url, true);
45113
let pathname = parsedUrl.pathname;
114+
115+
// Handle POST requests
116+
if (req.method === 'POST') {
117+
handlePostRequest(req, res);
118+
return;
119+
}
46120

47121
// Default to index.html for root path
48122
if (pathname === '/') {
@@ -72,9 +146,34 @@ const server = http.createServer((req, res) => {
72146
});
73147
});
74148

149+
// Create WebSocket server only if WebSocket is available
150+
if (isWebSocketAvailable) {
151+
const wss = new WebSocket.Server({ server });
152+
153+
wss.on('connection', (ws) => {
154+
console.log('New WebSocket client connected');
155+
wsClients.add(ws);
156+
157+
ws.on('close', () => {
158+
console.log('WebSocket client disconnected');
159+
wsClients.delete(ws);
160+
});
161+
162+
ws.on('error', (error) => {
163+
console.error('WebSocket error:', error);
164+
wsClients.delete(ws);
165+
});
166+
});
167+
}
168+
75169
// Start server
76170
server.listen(PORT, () => {
77171
console.log(`Server running at http://localhost:${PORT}`);
172+
if (isWebSocketAvailable) {
173+
console.log(`WebSocket server running on the same port`);
174+
} else {
175+
console.log(`WebSocket functionality disabled - install 'ws' package to enable`);
176+
}
78177
console.log(`Serving files from: ${__dirname}`);
79178
console.log('Press Ctrl+C to stop the server');
80179
});

0 commit comments

Comments
 (0)