Skip to content

Commit 89f3dbb

Browse files
committed
add web socket support
1 parent 1d0968e commit 89f3dbb

File tree

11 files changed

+1200
-2
lines changed

11 files changed

+1200
-2
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"qrcode": "^1.5.4",
3939
"turndown": "^7.2.0",
4040
"uuid": "^11.1.0",
41+
"ws": "^8.18.1",
4142
"xlsx": "^0.18.5"
4243
},
4344
"devDependencies": {

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/components-loader.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ import './components/slides-editor.js';
2323
import './components/table-editor.js';
2424
import './components/state-example.js';
2525
import './components/about-section.js';
26+
import './components/websocket-example.js';
2627

2728
console.log('All components loaded and registered');
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
import { BaseComponent } from './base-component.js';
2+
import WebSocketClient from '../utils/websocket-client.js';
3+
4+
/**
5+
* WebSocket Example Component
6+
*
7+
* This component demonstrates how to use the WebSocketClient utility
8+
* to establish a WebSocket connection and exchange messages with the server.
9+
*/
10+
class WebSocketExample extends BaseComponent {
11+
constructor() {
12+
super();
13+
14+
// Initialize WebSocketClient
15+
this.wsClient = new WebSocketClient({
16+
port: 8100,
17+
endpoint: '',
18+
reconnectInterval: 3000,
19+
maxReconnectAttempts: 3
20+
});
21+
22+
// Bind methods
23+
this.handleConnect = this.handleConnect.bind(this);
24+
this.handleDisconnect = this.handleDisconnect.bind(this);
25+
this.handleSendMessage = this.handleSendMessage.bind(this);
26+
this.handleMessageInput = this.handleMessageInput.bind(this);
27+
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this);
28+
this.handleWebSocketOpen = this.handleWebSocketOpen.bind(this);
29+
this.handleWebSocketClose = this.handleWebSocketClose.bind(this);
30+
this.handleWebSocketError = this.handleWebSocketError.bind(this);
31+
this.handleWebSocketReconnect = this.handleWebSocketReconnect.bind(this);
32+
this.handleWebSocketReconnectFailed = this.handleWebSocketReconnectFailed.bind(this);
33+
34+
// Register WebSocket event listeners
35+
this.wsClient.on('message', this.handleWebSocketMessage);
36+
this.wsClient.on('open', this.handleWebSocketOpen);
37+
this.wsClient.on('close', this.handleWebSocketClose);
38+
this.wsClient.on('error', this.handleWebSocketError);
39+
this.wsClient.on('reconnect', this.handleWebSocketReconnect);
40+
this.wsClient.on('reconnectFailed', this.handleWebSocketReconnectFailed);
41+
}
42+
43+
/**
44+
* Component template
45+
*/
46+
template() {
47+
return `
48+
<div class="websocket-example">
49+
<h2>WebSocket Example</h2>
50+
51+
<div class="connection-status">
52+
Status: <span id="status" class="status-disconnected">Disconnected</span>
53+
</div>
54+
55+
<div class="connection-controls">
56+
<button id="connectBtn" class="btn">Connect</button>
57+
<button id="disconnectBtn" class="btn" disabled>Disconnect</button>
58+
</div>
59+
60+
<div class="message-container">
61+
<h3>Messages</h3>
62+
<div id="messages" class="messages"></div>
63+
</div>
64+
65+
<div class="message-input">
66+
<input type="text" id="messageInput" placeholder="Type a message..." disabled>
67+
<button id="sendBtn" class="btn" disabled>Send</button>
68+
</div>
69+
</div>
70+
`;
71+
}
72+
73+
/**
74+
* Component styles
75+
*/
76+
styles() {
77+
return `
78+
.websocket-example {
79+
font-family: Arial, sans-serif;
80+
max-width: 600px;
81+
margin: 0 auto;
82+
padding: 20px;
83+
border: 1px solid #ddd;
84+
border-radius: 5px;
85+
}
86+
87+
.connection-status {
88+
margin-bottom: 10px;
89+
}
90+
91+
.status-connected {
92+
color: green;
93+
font-weight: bold;
94+
}
95+
96+
.status-disconnected {
97+
color: red;
98+
}
99+
100+
.status-connecting {
101+
color: orange;
102+
}
103+
104+
.connection-controls {
105+
margin-bottom: 20px;
106+
}
107+
108+
.btn {
109+
padding: 8px 16px;
110+
margin-right: 10px;
111+
background-color: #4caf50;
112+
color: white;
113+
border: none;
114+
border-radius: 4px;
115+
cursor: pointer;
116+
}
117+
118+
.btn:hover {
119+
background-color: #45a049;
120+
}
121+
122+
.btn:disabled {
123+
background-color: #cccccc;
124+
cursor: not-allowed;
125+
}
126+
127+
.messages {
128+
border: 1px solid #ddd;
129+
padding: 10px;
130+
height: 200px;
131+
overflow-y: auto;
132+
margin-bottom: 10px;
133+
background-color: #f9f9f9;
134+
}
135+
136+
.message {
137+
margin-bottom: 5px;
138+
padding: 5px;
139+
border-radius: 4px;
140+
}
141+
142+
.message-received {
143+
background-color: #e3f2fd;
144+
}
145+
146+
.message-sent {
147+
background-color: #e8f5e9;
148+
text-align: right;
149+
}
150+
151+
.message-system {
152+
background-color: #fff3e0;
153+
font-style: italic;
154+
}
155+
156+
.message-input {
157+
display: flex;
158+
}
159+
160+
#messageInput {
161+
flex-grow: 1;
162+
padding: 8px;
163+
margin-right: 10px;
164+
border: 1px solid #ddd;
165+
border-radius: 4px;
166+
}
167+
`;
168+
}
169+
170+
/**
171+
* Called when the component is connected to the DOM
172+
*/
173+
connectedCallback() {
174+
super.connectedCallback();
175+
176+
// Get DOM elements
177+
this.statusElement = this.shadowRoot.getElementById('status');
178+
this.connectButton = this.shadowRoot.getElementById('connectBtn');
179+
this.disconnectButton = this.shadowRoot.getElementById('disconnectBtn');
180+
this.messageInput = this.shadowRoot.getElementById('messageInput');
181+
this.sendButton = this.shadowRoot.getElementById('sendBtn');
182+
this.messagesContainer = this.shadowRoot.getElementById('messages');
183+
184+
// Add event listeners
185+
this.connectButton.addEventListener('click', this.handleConnect);
186+
this.disconnectButton.addEventListener('click', this.handleDisconnect);
187+
this.sendButton.addEventListener('click', this.handleSendMessage);
188+
this.messageInput.addEventListener('keypress', this.handleMessageInput);
189+
}
190+
191+
/**
192+
* Called when the component is disconnected from the DOM
193+
*/
194+
disconnectedCallback() {
195+
// Remove event listeners
196+
this.connectButton.removeEventListener('click', this.handleConnect);
197+
this.disconnectButton.removeEventListener('click', this.handleDisconnect);
198+
this.sendButton.removeEventListener('click', this.handleSendMessage);
199+
this.messageInput.removeEventListener('keypress', this.handleMessageInput);
200+
201+
// Disconnect WebSocket
202+
this.wsClient.disconnect();
203+
204+
// Remove WebSocket event listeners
205+
this.wsClient.off('message', this.handleWebSocketMessage);
206+
this.wsClient.off('open', this.handleWebSocketOpen);
207+
this.wsClient.off('close', this.handleWebSocketClose);
208+
this.wsClient.off('error', this.handleWebSocketError);
209+
this.wsClient.off('reconnect', this.handleWebSocketReconnect);
210+
this.wsClient.off('reconnectFailed', this.handleWebSocketReconnectFailed);
211+
212+
super.disconnectedCallback();
213+
}
214+
215+
/**
216+
* Handle connect button click
217+
*/
218+
handleConnect() {
219+
this.updateStatus('Connecting...', 'status-connecting');
220+
this.addMessage('Connecting to WebSocket server...', 'system');
221+
222+
this.wsClient.connect()
223+
.catch(error => {
224+
console.error('Failed to connect:', error);
225+
this.updateStatus('Connection failed', 'status-disconnected');
226+
this.addMessage(`Connection failed: ${error.message}`, 'system');
227+
});
228+
}
229+
230+
/**
231+
* Handle disconnect button click
232+
*/
233+
handleDisconnect() {
234+
this.wsClient.disconnect();
235+
}
236+
237+
/**
238+
* Handle send button click
239+
*/
240+
handleSendMessage() {
241+
const message = this.messageInput.value.trim();
242+
243+
if (message && this.wsClient.isConnected()) {
244+
this.wsClient.send(message);
245+
this.addMessage(message, 'sent');
246+
this.messageInput.value = '';
247+
}
248+
}
249+
250+
/**
251+
* Handle message input keypress
252+
*/
253+
handleMessageInput(event) {
254+
if (event.key === 'Enter') {
255+
this.handleSendMessage();
256+
}
257+
}
258+
259+
/**
260+
* Handle WebSocket message event
261+
*/
262+
handleWebSocketMessage(data) {
263+
this.addMessage(data, 'received');
264+
}
265+
266+
/**
267+
* Handle WebSocket open event
268+
*/
269+
handleWebSocketOpen() {
270+
this.updateStatus('Connected', 'status-connected');
271+
this.addMessage('Connected to WebSocket server', 'system');
272+
273+
// Update UI
274+
this.connectButton.disabled = true;
275+
this.disconnectButton.disabled = false;
276+
this.messageInput.disabled = false;
277+
this.sendButton.disabled = false;
278+
}
279+
280+
/**
281+
* Handle WebSocket close event
282+
*/
283+
handleWebSocketClose(event) {
284+
this.updateStatus('Disconnected', 'status-disconnected');
285+
this.addMessage(`Disconnected from server: ${event.reason || 'Connection closed'}`, 'system');
286+
287+
// Update UI
288+
this.connectButton.disabled = false;
289+
this.disconnectButton.disabled = true;
290+
this.messageInput.disabled = true;
291+
this.sendButton.disabled = true;
292+
}
293+
294+
/**
295+
* Handle WebSocket error event
296+
*/
297+
handleWebSocketError() {
298+
this.addMessage('WebSocket error occurred', 'system');
299+
}
300+
301+
/**
302+
* Handle WebSocket reconnect event
303+
*/
304+
handleWebSocketReconnect(attempt) {
305+
this.updateStatus(`Reconnecting (${attempt})...`, 'status-connecting');
306+
this.addMessage(`Attempting to reconnect (${attempt})...`, 'system');
307+
}
308+
309+
/**
310+
* Handle WebSocket reconnect failed event
311+
*/
312+
handleWebSocketReconnectFailed() {
313+
this.updateStatus('Reconnection failed', 'status-disconnected');
314+
this.addMessage('Failed to reconnect after multiple attempts', 'system');
315+
}
316+
317+
/**
318+
* Update the connection status
319+
*/
320+
updateStatus(text, className) {
321+
this.statusElement.textContent = text;
322+
this.statusElement.className = className;
323+
}
324+
325+
/**
326+
* Add a message to the messages container
327+
*/
328+
addMessage(text, type) {
329+
const messageElement = document.createElement('div');
330+
messageElement.classList.add('message', `message-${type}`);
331+
messageElement.textContent = text;
332+
this.messagesContainer.appendChild(messageElement);
333+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
334+
}
335+
}
336+
337+
// Define the custom element
338+
customElements.define('websocket-example', WebSocketExample);
339+
340+
export default WebSocketExample;

0 commit comments

Comments
 (0)