Spaces:
Running
Running
// server.js (Node.js with Express and ws) | |
const express = require('express'); | |
const { WebSocketServer } = require('ws'); | |
const cors = require('cors'); // Import CORS | |
const { initializeApp, cert } = require('firebase-admin/app'); | |
const { getFirestore } = require('firebase-admin/firestore'); | |
var admin = require("firebase-admin"); | |
const serviceAccount = require("./serviceAcc.json"); | |
initializeApp({ | |
credential: cert(serviceAccount) | |
}); | |
const db = getFirestore(); | |
const app = express(); | |
const port = process.env.PORT || 8080; | |
const wss = new WebSocketServer({ noServer: true }); | |
app.use(cors()); | |
var initialData = {}; | |
let currentDeviceStates = {}; | |
const fetchInitialData = async () => { | |
const devices = []; | |
const rooms = []; | |
const users = []; | |
try { | |
const deviceSnapshot = await db.collection('Devices').get(); | |
deviceSnapshot.forEach(doc => devices.push({ id: doc.id, ...doc.data() })); | |
const roomsSnapshot = await db.collectionGroup('Rooms').get(); // Get all rooms across hostels | |
roomsSnapshot.forEach(doc => rooms.push({ id: doc.id, ...doc.data(), hostelId: doc.ref.parent.parent.id })); // Include hostelId | |
const usersSnapshot = await db.collection('Users').get(); | |
usersSnapshot.forEach(doc => users.push({ id: doc.id, ...doc.data() })); | |
initialData = { devices, rooms, users }; | |
// console.log("Initial data fetched:", initialData); | |
//for each hostel id mantain a list of rooms with devices pertaining to that hostel | |
//setall to off | |
initialData.devices.forEach(device => { | |
device.state = false; | |
} ); | |
initialData.rooms.forEach(room => { | |
if (!currentDeviceStates[room.id]) { | |
currentDeviceStates[room.id] = []; | |
} | |
const roomDevices = initialData.devices.filter(device => device.hostelId === room.hostelId); | |
currentDeviceStates[room.id] = { ...room, devices: roomDevices }; | |
}); | |
} catch (error) { | |
console.error("Error fetching initial data:", error); | |
// return { devices: [], rooms: [], users: [] }; | |
initialData = { devices, rooms, users }; | |
} | |
}; | |
fetchInitialData(); | |
const connectedClients = {}; // Store connected clients per room | |
wss.on('connection', (ws) => { | |
ws.on('message', async (message) => { | |
try { | |
const parsedMessage = JSON.parse(message); | |
const { roomId, userId, apiKey } = parsedMessage; | |
// Helper function to check authorization | |
const isAuthorized = (roomId, userId, apiKey) => { | |
return initialData.users.some(user => user.id === userId && user.roomId === roomId) || apiKey === "masterPassword@tiet@123"; | |
}; | |
switch (parsedMessage.type) { | |
case 'joinRoom': | |
if (!roomId || !userId) { | |
ws.send(JSON.stringify({ error: 'Invalid room or user ID' })); | |
return; | |
} | |
if (!isAuthorized(roomId, userId, apiKey)) { | |
console.log("Unauthorized joinRoom attempt."); | |
ws.send(JSON.stringify({ error: 'Unauthorized' })); | |
return; | |
} | |
// Store the connected client | |
if (!connectedClients[roomId]) { | |
connectedClients[roomId] = []; | |
} | |
connectedClients[roomId].push(ws); | |
ws.send(JSON.stringify({ type: 'roomData', roomData: currentDeviceStates[roomId], roomId: roomId })); | |
break; | |
case 'updateDeviceState': | |
const { deviceId, state } = parsedMessage; | |
if (!deviceId || state === undefined || !roomId || (!userId && !apiKey)) { // Check for undefined state or missing userId/apiKey | |
ws.send(JSON.stringify({ error: 'Invalid device ID, state, room ID, user ID, or API key' })); | |
return; | |
} | |
if (!isAuthorized(roomId, userId, apiKey)) { | |
console.log("Unauthorized updateDeviceState attempt."); | |
ws.send(JSON.stringify({ error: 'Unauthorized' })); | |
return; | |
} | |
const room = currentDeviceStates[roomId]; | |
if (room) { // Check if the room exists | |
const device = room.devices.find(dev => dev.id === deviceId); | |
if (device) { // Check if the device exists | |
device.state = state; | |
// Broadcast to all clients in the room | |
if (connectedClients[roomId]) { | |
connectedClients[roomId].forEach(client => { | |
client.send(JSON.stringify({ type: 'deviceUpdate', deviceId, state, roomId: roomId })); | |
}); | |
} | |
} else { | |
ws.send(JSON.stringify({ error: 'Device not found' })); | |
} | |
} else { | |
ws.send(JSON.stringify({ error: 'Room not found' })); | |
} | |
break; | |
default: | |
console.log('Unknown message type:', parsedMessage.type); | |
} | |
} catch (error) { | |
console.error('Error handling message:', error); | |
ws.send(JSON.stringify({ error: 'Invalid message format' })); // Send error back to client | |
} | |
}); | |
ws.on('close', () => { | |
for (const roomId in connectedClients) { | |
connectedClients[roomId] = connectedClients[roomId].filter(client => client !== ws); | |
} | |
}); | |
ws.on('error', (error) => { | |
console.error('WebSocket error:', error); | |
}); | |
}); | |
console.log('WebSocket server started on port 8080'); | |
const server = app.listen(port, () => console.log(`Listening on port ${port}`)); | |
server.on('upgrade', (request, socket, head) => { | |
wss.handleUpgrade(request, socket, head, ws => { | |
wss.emit('connection', ws, request); | |
}); | |
}); |