467363d651
Made-with: Cursor
81 lines
3.5 KiB
JavaScript
81 lines
3.5 KiB
JavaScript
const http = require('http');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const { Server } = require('socket.io');
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
const BASE_PATH = '/realtimechat';
|
|
|
|
const server = http.createServer((req, res) => {
|
|
const sockPath = BASE_PATH + '/socket.io/socket.io';
|
|
if (req.url === sockPath + '.js' || req.url === sockPath + '.min.js') {
|
|
const clientPath = path.join(__dirname, 'node_modules', 'socket.io', 'client-dist', 'socket.io.min.js');
|
|
return fs.readFile(clientPath, (err, data) => {
|
|
if (err) { res.writeHead(404); return res.end('Not Found'); }
|
|
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
res.end(data);
|
|
});
|
|
}
|
|
let file = req.url === BASE_PATH || req.url === BASE_PATH + '/' ? BASE_PATH + '/index.html' : req.url;
|
|
if (file.indexOf(BASE_PATH) === 0) file = file.slice(BASE_PATH.length) || '/index.html';
|
|
const filePath = path.join(__dirname, 'public', file);
|
|
const ext = path.extname(filePath);
|
|
const types = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.ico': 'image/x-icon' };
|
|
fs.readFile(filePath, (err, data) => {
|
|
if (err) {
|
|
res.writeHead(404);
|
|
return res.end('Not Found');
|
|
}
|
|
res.writeHead(200, { 'Content-Type': types[ext] || 'application/octet-stream' });
|
|
res.end(data);
|
|
});
|
|
});
|
|
|
|
const io = new Server(server, { path: BASE_PATH + '/socket.io', cors: { origin: '*' } });
|
|
const rooms = new Map();
|
|
|
|
io.on('connection', (socket) => {
|
|
socket.on('create-room', ({ roomId, password }, cb) => {
|
|
roomId = (roomId || '').trim() || 'room-' + Date.now();
|
|
if (!rooms.has(roomId)) rooms.set(roomId, { password: password || '', peers: new Map() });
|
|
if (typeof cb === 'function') cb({ ok: true, roomId });
|
|
});
|
|
|
|
socket.on('join-room', ({ roomId, password, nickname }, cb) => {
|
|
if (!rooms.has(roomId)) return cb && cb({ ok: false, error: 'ไม่พบห้อง' });
|
|
const room = rooms.get(roomId);
|
|
if (room.password && room.password !== (password || '')) return cb && cb({ ok: false, error: 'รหัสผ่านผิด' });
|
|
socket.join(roomId);
|
|
const nick = (nickname || '').trim();
|
|
room.peers.set(socket.id, { id: socket.id, nickname: nick });
|
|
const peerList = [...room.peers.values()].filter((p) => p.id !== socket.id);
|
|
if (typeof cb === 'function') cb({ ok: true, peers: peerList });
|
|
socket.to(roomId).emit('user-joined', { id: socket.id, nickname: nick });
|
|
});
|
|
|
|
socket.on('disconnect', () => {
|
|
for (const [rid, room] of rooms) {
|
|
if (room.peers.has(socket.id)) {
|
|
room.peers.delete(socket.id);
|
|
socket.to(rid).emit('user-left', { id: socket.id });
|
|
if (room.peers.size === 0) rooms.delete(rid);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
socket.on('webrtc-offer', ({ to, offer }) => socket.to(to).emit('webrtc-offer', { from: socket.id, offer }));
|
|
socket.on('webrtc-answer', ({ to, answer }) => socket.to(to).emit('webrtc-answer', { from: socket.id, answer }));
|
|
socket.on('webrtc-ice', ({ to, candidate }) => socket.to(to).emit('webrtc-ice', { from: socket.id, candidate }));
|
|
socket.on('chat', (text) => {
|
|
const roomId = [...socket.rooms].find(r => r !== socket.id && rooms.has(r));
|
|
if (!roomId) return;
|
|
const room = rooms.get(roomId);
|
|
const peer = room?.peers.get(socket.id);
|
|
const nickname = peer?.nickname || '';
|
|
io.to(roomId).emit('chat', { id: socket.id, nickname, text, time: new Date() });
|
|
});
|
|
});
|
|
|
|
server.listen(PORT, () => console.log('RealtimeChat', PORT));
|