CoolFace
Apppublic

Timsupport/camera

sourceHugging Facemitupdated 4mo agoView on Hugging Face
0likes
server.js229 linesDownload Raw Back to root
1const express = require('express');2const http = require('http');3const { Server } = require('socket.io');4const path = require('path');5 6const app = express();7const server = http.createServer(app);8const io = new Server(server, {9    cors: { origin: "*", methods: ["GET", "POST"] }10});11 12// Serve public files (disable auto index.html for /)13app.use(express.static(path.join(__dirname, 'public'), { index: false }));14 15// Root → landing page16app.get('/', (req, res) => {17    res.sendFile(path.join(__dirname, 'home.html'));18});19 20// Rooms: roomCode → { broadcasterId, viewers: [adminSocketId], deviceInfo, isStreaming }21const rooms = {};22 23io.on('connection', (socket) => {24    console.log(`[Socket] Connected: ${socket.id}`);25 26    // === CLIENT (Camera Device) ===27 28    // Client joins/creates a room29    socket.on('client-join-room', ({ roomCode, deviceName }) => {30        roomCode = roomCode.toUpperCase();31 32        // Check if room already has broadcaster33        if (rooms[roomCode] && rooms[roomCode].broadcasterId) {34            socket.emit('client-error', { message: `Room ${roomCode} sudah ada broadcaster` });35            return;36        }37 38        rooms[roomCode] = {39            broadcasterId: socket.id,40            viewers: [],41            deviceInfo: { name: deviceName || 'Camera', platform: 'browser' },42            isStreaming: false43        };44 45        socket.roomCode = roomCode;46        console.log(`[Room] Client ${socket.id} created room: ${roomCode} (${deviceName})`);47 48        // Broadcast room list to admins49        broadcastRoomList();50 51        socket.emit('client-room-joined', { roomCode });52    });53 54    // Client ready to stream (camera started)55    socket.on('client-ready', ({ roomCode }) => {56        if (rooms[roomCode]) {57            rooms[roomCode].isStreaming = true;58            broadcastRoomList();59 60            // Notify all admins in room that stream is ready61            rooms[roomCode].viewers.forEach(adminId => {62                io.to(adminId).emit('room-stream-ready', { roomCode });63            });64        }65    });66 67    // Client sends WebRTC offer to specific admin68    socket.on('client-offer', ({ roomCode, adminId, offer }) => {69        io.to(adminId).emit('webrtc-offer', { roomCode, fromClientId: socket.id, offer });70    });71 72    // Client sends ICE candidate to admin73    socket.on('client-ice', ({ roomCode, adminId, candidate }) => {74        io.to(adminId).emit('webrtc-ice-candidate', { roomCode, candidate });75    });76 77    // Client sends screenshot78    socket.on('client-screenshot', ({ roomCode, imageData }) => {79        if (rooms[roomCode]) {80            rooms[roomCode].viewers.forEach(adminId => {81                io.to(adminId).emit('new-screenshot', { roomCode, imageData });82            });83        }84    });85 86    // Client status update87    socket.on('client-status', ({ roomCode, isRecording }) => {88        if (rooms[roomCode]) {89            rooms[roomCode].viewers.forEach(adminId => {90                io.to(adminId).emit('stream-status', { roomCode, isRecording });91            });92        }93    });94 95    // === ADMIN (Monitoring Dashboard) ===96 97    // Admin joins room to monitor98    socket.on('admin-join-room', ({ roomCode }) => {99        roomCode = roomCode.toUpperCase();100        const room = rooms[roomCode];101 102        if (!room || !room.broadcasterId) {103            socket.emit('admin-error', { message: `Room ${roomCode} tidak ditemukan` });104            return;105        }106 107        if (room.viewers.includes(socket.id)) {108            socket.emit('admin-error', { message: 'Sudah ada di room ini' });109            return;110        }111 112        room.viewers.push(socket.id);113        socket.adminRoom = roomCode;114 115        console.log(`[Admin] ${socket.id} joined room ${roomCode}`);116 117        // Notify client that admin is watching118        io.to(room.broadcasterId).emit('admin-watching', { adminId: socket.id, roomCode });119 120        // Tell admin about current room state121        socket.emit('room-joined', {122            roomCode,123            deviceInfo: room.deviceInfo,124            isStreaming: room.isStreaming125        });126 127        broadcastRoomList();128    });129 130    // Admin stops monitoring room131    socket.on('admin-leave-room', ({ roomCode }) => {132        const room = rooms[roomCode];133        if (room) {134            room.viewers = room.viewers.filter(id => id !== socket.id);135            io.to(room.broadcasterId).emit('admin-left', { adminId: socket.id, roomCode });136            broadcastRoomList();137        }138        socket.adminRoom = null;139    });140 141    // Admin sends remote command to client142    socket.on('admin-command', ({ roomCode, command }) => {143        const room = rooms[roomCode];144        if (room && room.broadcasterId) {145            io.to(room.broadcasterId).emit('remote-command', { command });146        }147    });148 149    // Admin sends WebRTC answer to client150    socket.on('admin-answer', ({ roomCode, answer }) => {151        const room = rooms[roomCode];152        if (room && room.broadcasterId) {153            io.to(room.broadcasterId).emit('webrtc-answer', { roomCode, answer, adminId: socket.id });154        }155    });156 157    // Admin sends ICE candidate to client158    socket.on('admin-ice', ({ roomCode, candidate }) => {159        const room = rooms[roomCode];160        if (room && room.broadcasterId) {161            io.to(room.broadcasterId).emit('webrtc-ice-candidate', { roomCode, candidate, adminId: socket.id });162        }163    });164 165    // === Chat Messages ===166 167    // Client sends chat message168    socket.on('client-chat', ({ roomCode, message, deviceName }) => {169        const room = rooms[roomCode];170        if (room) {171            room.viewers.forEach(adminId => {172                io.to(adminId).emit('chat-message', { roomCode, from: deviceName, message, type: 'client', timestamp: Date.now() });173            });174        }175    });176 177    // Admin sends chat message178    socket.on('admin-chat', ({ roomCode, message }) => {179        const room = rooms[roomCode];180        if (room && room.broadcasterId) {181            io.to(room.broadcasterId).emit('chat-message', { roomCode, from: socket.id.slice(0, 8), message, type: 'admin', timestamp: Date.now() });182        }183    });184 185    // Disconnect186    socket.on('disconnect', () => {187        console.log(`[Socket] Disconnected: ${socket.id}`);188 189        // Handle client disconnect190        if (socket.roomCode && rooms[socket.roomCode]) {191            const room = rooms[socket.roomCode];192            // Notify all admins in room193            room.viewers.forEach(adminId => {194                io.to(adminId).emit('broadcaster-disconnected', { roomCode: socket.roomCode });195            });196            delete rooms[socket.roomCode];197            broadcastRoomList();198        }199 200        // Handle admin disconnect201        if (socket.adminRoom && rooms[socket.adminRoom]) {202            const room = rooms[socket.adminRoom];203            room.viewers = room.viewers.filter(id => id !== socket.id);204            if (room.broadcasterId) {205                io.to(room.broadcasterId).emit('admin-left', { adminId: socket.id, roomCode: socket.adminRoom });206            }207            broadcastRoomList();208        }209    });210});211 212function broadcastRoomList() {213    const roomList = Object.entries(rooms).map(([code, room]) => ({214        roomCode: code,215        deviceName: room.deviceInfo.name,216        viewerCount: room.viewers.length,217        isStreaming: room.isStreaming218    }));219    io.emit('room-list-updated', roomList);220}221 222const PORT = process.env.PORT || 3000;223server.listen(PORT, '0.0.0.0', () => {224    console.log(`🎬 Camera Monitoring Server on port ${PORT}`);225    console.log(`   🏠 Home: http://localhost:${PORT}/`);226    console.log(`   📷 Camera Device: http://localhost:${PORT}/index.html`);227    console.log(`   🎬 Admin Monitor: http://localhost:${PORT}/viewer.html`);228});229