111 lines
3.2 KiB
JavaScript
111 lines
3.2 KiB
JavaScript
const jwt = require('jsonwebtoken');
|
|
const logger = require('../utils/logger');
|
|
const redis = require('../config/redis');
|
|
const database = require('../config/database');
|
|
|
|
const socketHandler = (io) => {
|
|
// Authentication middleware for Socket.IO
|
|
io.use(async (socket, next) => {
|
|
try {
|
|
const token = socket.handshake.auth.token || socket.handshake.headers.authorization;
|
|
|
|
if (!token) {
|
|
return next(new Error('Authentication error: No token provided'));
|
|
}
|
|
|
|
const cleanToken = token.replace('Bearer ', '');
|
|
const decoded = jwt.verify(cleanToken, process.env.JWT_SECRET);
|
|
|
|
// Verify user session
|
|
const session = await redis.getUserSession(decoded.id);
|
|
if (!session) {
|
|
return next(new Error('Authentication error: Session expired'));
|
|
}
|
|
|
|
// Get user info
|
|
const [users] = await database.query(
|
|
'SELECT id, username, email, role FROM users WHERE id = ? AND status = "active"',
|
|
[decoded.id]
|
|
);
|
|
|
|
if (users.length === 0) {
|
|
return next(new Error('Authentication error: User not found'));
|
|
}
|
|
|
|
socket.user = users[0];
|
|
next();
|
|
} catch (error) {
|
|
logger.error('Socket authentication failed:', error);
|
|
next(new Error('Authentication error: Invalid token'));
|
|
}
|
|
});
|
|
|
|
io.on('connection', (socket) => {
|
|
logger.info(`User connected: ${socket.user.username} (${socket.id})`);
|
|
|
|
// Join user to their personal room
|
|
socket.join(`user:${socket.user.id}`);
|
|
|
|
// Join admin users to admin room
|
|
if (socket.user.role === 'admin') {
|
|
socket.join('admin');
|
|
}
|
|
|
|
// Handle device data updates
|
|
socket.on('subscribe_device', (deviceId) => {
|
|
socket.join(`device:${deviceId}`);
|
|
logger.info(`User ${socket.user.username} subscribed to device ${deviceId}`);
|
|
});
|
|
|
|
socket.on('unsubscribe_device', (deviceId) => {
|
|
socket.leave(`device:${deviceId}`);
|
|
logger.info(`User ${socket.user.username} unsubscribed from device ${deviceId}`);
|
|
});
|
|
|
|
// Handle alert subscriptions
|
|
socket.on('subscribe_alerts', () => {
|
|
socket.join('alerts');
|
|
logger.info(`User ${socket.user.username} subscribed to alerts`);
|
|
});
|
|
|
|
socket.on('unsubscribe_alerts', () => {
|
|
socket.leave('alerts');
|
|
logger.info(`User ${socket.user.username} unsubscribed from alerts`);
|
|
});
|
|
|
|
// Handle disconnect
|
|
socket.on('disconnect', () => {
|
|
logger.info(`User disconnected: ${socket.user.username} (${socket.id})`);
|
|
});
|
|
});
|
|
|
|
// Export socket functions for use in other modules
|
|
return {
|
|
// Emit device data updates
|
|
emitDeviceData: (deviceId, data) => {
|
|
io.to(`device:${deviceId}`).emit('device_data_update', {
|
|
deviceId,
|
|
data,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
},
|
|
|
|
// Emit alerts
|
|
emitAlert: (alert) => {
|
|
io.to('alerts').emit('new_alert', {
|
|
...alert,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
},
|
|
|
|
// Emit to admin users
|
|
emitToAdmin: (event, data) => {
|
|
io.to('admin').emit(event, {
|
|
...data,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
module.exports = socketHandler;
|