246 lines
7.3 KiB
JavaScript
246 lines
7.3 KiB
JavaScript
// LEDLab Main Application
|
|
|
|
class LEDLabApp {
|
|
constructor() {
|
|
this.viewModel = new ViewModel();
|
|
this.eventBus = new EventBus();
|
|
this.ws = null;
|
|
this.reconnectAttempts = 0;
|
|
this.maxReconnectAttempts = 5;
|
|
this.reconnectDelay = 1000;
|
|
|
|
this.matrixDisplay = null;
|
|
this.presetControls = null;
|
|
this.nodeDiscovery = null;
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
// Set up event bus on view model
|
|
this.viewModel.setEventBus(this.eventBus);
|
|
|
|
// Initialize components
|
|
this.initComponents();
|
|
|
|
// Set up WebSocket connection
|
|
this.connectWebSocket();
|
|
|
|
// Set up global event listeners
|
|
this.setupGlobalEventListeners();
|
|
|
|
console.log('LEDLab app initialized');
|
|
}
|
|
|
|
initComponents() {
|
|
// Initialize Matrix Display component
|
|
const matrixContainer = document.querySelector('.matrix-section');
|
|
if (matrixContainer) {
|
|
this.matrixDisplay = new MatrixDisplay(matrixContainer, this.viewModel, this.eventBus);
|
|
this.matrixDisplay.mount();
|
|
}
|
|
|
|
// Initialize Preset Controls component
|
|
const controlsContainer = document.querySelector('.control-section');
|
|
if (controlsContainer) {
|
|
this.presetControls = new PresetControls(controlsContainer, this.viewModel, this.eventBus);
|
|
this.presetControls.mount();
|
|
}
|
|
|
|
// Initialize Node Discovery component
|
|
const nodeContainer = document.querySelector('#node-list').parentElement;
|
|
if (nodeContainer) {
|
|
this.nodeDiscovery = new NodeDiscovery(nodeContainer, this.viewModel, this.eventBus);
|
|
this.nodeDiscovery.mount();
|
|
}
|
|
}
|
|
|
|
connectWebSocket() {
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsUrl = `${protocol}//${window.location.host}`;
|
|
|
|
try {
|
|
this.ws = new WebSocket(wsUrl);
|
|
this.setupWebSocketEventHandlers();
|
|
} catch (error) {
|
|
console.error('Failed to create WebSocket connection:', error);
|
|
this.scheduleReconnect();
|
|
}
|
|
}
|
|
|
|
setupWebSocketEventHandlers() {
|
|
if (!this.ws) return;
|
|
|
|
this.ws.onopen = () => {
|
|
console.log('WebSocket connected');
|
|
this.reconnectAttempts = 0;
|
|
|
|
// Send any queued messages
|
|
this.flushMessageQueue();
|
|
};
|
|
|
|
this.ws.onmessage = (event) => {
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
this.handleWebSocketMessage(data);
|
|
} catch (error) {
|
|
console.error('Error parsing WebSocket message:', error);
|
|
}
|
|
};
|
|
|
|
this.ws.onclose = (event) => {
|
|
console.log('WebSocket disconnected:', event.code, event.reason);
|
|
|
|
if (event.code !== 1000) { // Not a normal closure
|
|
this.scheduleReconnect();
|
|
}
|
|
};
|
|
|
|
this.ws.onerror = (error) => {
|
|
console.error('WebSocket error:', error);
|
|
};
|
|
}
|
|
|
|
handleWebSocketMessage(data) {
|
|
// Publish event to the event bus for components to handle
|
|
this.eventBus.publish(data.type, data);
|
|
}
|
|
|
|
scheduleReconnect() {
|
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
console.error('Max reconnection attempts reached');
|
|
return;
|
|
}
|
|
|
|
this.reconnectAttempts++;
|
|
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1); // Exponential backoff
|
|
|
|
console.log(`Attempting to reconnect in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
|
|
setTimeout(() => {
|
|
this.connectWebSocket();
|
|
}, delay);
|
|
}
|
|
|
|
sendWebSocketMessage(data) {
|
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
this.ws.send(JSON.stringify(data));
|
|
} else {
|
|
console.warn('WebSocket not connected, queuing message');
|
|
// Queue message for when connection is restored
|
|
if (!this.messageQueue) {
|
|
this.messageQueue = [];
|
|
}
|
|
this.messageQueue.push(data);
|
|
}
|
|
}
|
|
|
|
flushMessageQueue() {
|
|
if (this.messageQueue && this.messageQueue.length > 0) {
|
|
console.log(`Flushing ${this.messageQueue.length} queued messages`);
|
|
this.messageQueue.forEach(data => this.sendWebSocketMessage(data));
|
|
this.messageQueue = [];
|
|
}
|
|
}
|
|
|
|
setupGlobalEventListeners() {
|
|
// Listen for messages from components that need to be sent to server
|
|
this.eventBus.subscribe('startPreset', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'startPreset',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('stopStreaming', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'stopStreaming',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('updatePresetParameter', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'updatePresetParameter',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('setMatrixSize', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'setMatrixSize',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('sendToNode', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'sendToNode',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('broadcastToAll', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'broadcastToAll',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('selectNode', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'selectNode',
|
|
...data
|
|
});
|
|
});
|
|
|
|
this.eventBus.subscribe('selectBroadcast', (data) => {
|
|
this.sendWebSocketMessage({
|
|
type: 'selectBroadcast',
|
|
...data
|
|
});
|
|
});
|
|
|
|
// Handle theme changes
|
|
window.addEventListener('themeChanged', (event) => {
|
|
console.log('Theme changed to:', event.detail.theme);
|
|
// Update any theme-specific UI elements if needed
|
|
});
|
|
}
|
|
|
|
// Public API methods for external use
|
|
startPreset(presetName, width, height) {
|
|
this.viewModel.publish('startPreset', { presetName, width, height });
|
|
}
|
|
|
|
stopStreaming() {
|
|
this.viewModel.publish('stopStreaming', {});
|
|
}
|
|
|
|
updatePresetParameter(parameter, value) {
|
|
this.viewModel.publish('updatePresetParameter', { parameter, value });
|
|
}
|
|
|
|
setMatrixSize(width, height) {
|
|
this.viewModel.publish('setMatrixSize', { width, height });
|
|
}
|
|
|
|
sendToNode(nodeIp, message) {
|
|
this.viewModel.publish('sendToNode', { nodeIp, message });
|
|
}
|
|
|
|
broadcastToAll(message) {
|
|
this.viewModel.publish('broadcastToAll', { message });
|
|
}
|
|
}
|
|
|
|
// Initialize the app when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
window.ledlabApp = new LEDLabApp();
|
|
});
|
|
|
|
// Export for use in other modules
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = LEDLabApp;
|
|
}
|