import Koa from 'koa'; import Router from 'koa-router'; import bodyParser from 'koa-bodyparser'; import cors from '@koa/cors'; import { createServer } from 'http'; import { Server } from 'socket.io'; import os from 'os'; import signalRouter from './routes/signal.js'; import filesRouter from './routes/files.js'; const app = new Koa(); const router = new Router(); const httpServer = createServer(app); const io = new Server(httpServer, { cors: { origin: '*', methods: ['GET', 'POST'], credentials: true, allowedHeaders: ['Content-Type', 'Authorization'] }, transports: ['websocket', 'polling'] }); app.use(cors({ origin: '*', credentials: true, allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization'] })); app.use(bodyParser()); app.use(async (ctx, next) => { ctx.io = io; await next(); }); router.get('/', async (ctx) => { ctx.body = { message: 'P2P File Transfer Server', version: '1.0.0' }; }); app.use(router.routes()); app.use(router.allowedMethods()); app.use(signalRouter.routes()); app.use(signalRouter.allowedMethods()); app.use(filesRouter.routes()); app.use(filesRouter.allowedMethods()); const rooms = new Map(); const users = new Map(); io.on('connection', (socket) => { console.log('User connected:', socket.id); socket.on('join-room', ({ roomId, userId, nickname }) => { socket.join(roomId); users.set(socket.id, { roomId, userId, nickname }); const room = rooms.get(roomId) || new Set(); room.add(socket.id); rooms.set(roomId, room); socket.to(roomId).emit('user-joined', { userId, socketId: socket.id, nickname }); const roomUsers = Array.from(room).map(id => ({ socketId: id, userId: users.get(id)?.userId, nickname: users.get(id)?.nickname })); socket.emit('room-users', roomUsers); }); socket.on('leave-room', ({ roomId, userId, socketId }) => { const user = users.get(socketId); if (user && user.roomId === roomId) { const room = rooms.get(roomId); if (room) { room.delete(socketId); socket.to(roomId).emit('user-left', { userId: user.userId, socketId: socketId }); if (room.size === 0) { rooms.delete(roomId); } } users.delete(socketId); socket.leave(roomId); } }); socket.on('signal', ({ targetSocketId, signal }) => { const targetUser = users.get(targetSocketId); if (targetUser) { io.to(targetSocketId).emit('signal', { senderSocketId: socket.id, signal }); } }); socket.on('disconnect', () => { console.log('User disconnected:', socket.id); const user = users.get(socket.id); if (user) { const room = rooms.get(user.roomId); if (room) { room.delete(socket.id); socket.to(user.roomId).emit('user-left', { userId: user.userId, socketId: socket.id }); if (room.size === 0) { rooms.delete(user.roomId); } } users.delete(socket.id); } }); }); const PORT = process.env.PORT || 3000; const HOST = process.env.HOST || '127.0.0.1'; httpServer.listen(PORT, HOST, () => { console.log(`P2P Transfer Server running on http://${HOST}:${PORT}`); }); function getLocalIP() { const interfaces = os.networkInterfaces(); for (const name of Object.keys(interfaces)) { for (const iface of interfaces[name]) { if (iface.family === 'IPv4' && !iface.internal) { return iface.address; } } } return 'localhost'; }