const express = require('express') const socketio = require('socket.io') const http = require('http') const cors = require('cors') const { addUser, removeUser, getUser, getUsersInRoom } = require('./users') const path = require('path') const PORT = process.env.PORT || 5000 const app = express() const server = http.createServer(app) const io = socketio(server, { cors: { origin: "*", methods: ["GET", "POST"] } }) app.use(cors()) // Store latest game states by room code for bot API access const gameStates = new Map() // HTTP endpoint for bot to get game state app.get('/api/game/:roomCode/state', (req, res) => { const roomCode = req.params.roomCode const state = gameStates.get(roomCode) if (state) { res.json({ success: true, gameState: state, timestamp: new Date().toISOString() }) } else { res.status(404).json({ success: false, error: 'Game room not found or no state available' }) } }) // HTTP endpoint for bot to submit action app.post('/api/game/:roomCode/action', express.json(), (req, res) => { const roomCode = req.params.roomCode const action = req.body // minimal log for incoming bot action console.log(`[Bot HTTP Action] Room: ${roomCode}`) // Emit action to the game room via socket io.to(roomCode).emit('botActionReceived', action) res.json({ success: true, message: 'Action received and forwarded to game' }) }) io.on('connection', socket => { socket.on('join', (payload, callback) => { let numberOfUsersInRoom = getUsersInRoom(payload.room).length const { error, newUser} = addUser({ id: socket.id, name: numberOfUsersInRoom===0 ? 'Player 1' : 'Player 2', room: payload.room }) if(error) return callback(error) socket.join(newUser.room) io.to(newUser.room).emit('roomData', {room: newUser.room, users: getUsersInRoom(newUser.room)}) socket.emit('currentUserData', {name: newUser.name}) callback() }) socket.on('initGameState', gameState => { const user = getUser(socket.id) if(user) io.to(user.room).emit('initGameState', gameState) }) socket.on('updateGameState', gameState => { const user = getUser(socket.id) if(user) { io.to(user.room).emit('updateGameState', gameState) // Also update stored game state for bot REST API access const currentState = gameStates.get(user.room) || {} gameStates.set(user.room, { ...currentState, ...gameState, room: user.room, lastUpdate: new Date().toISOString() }) } }) socket.on('sendMessage', (payload, callback) => { const user = getUser(socket.id) io.to(user.room).emit('message', {user: user.name, text: payload.message}) callback() }) // Bot integration: receive game state from Player 2 (bot) socket.on('botGameState', gameState => { const user = getUser(socket.id) if(user && user.name === 'Player 2') { // Store latest game state for bot access (do not log full JSON to avoid noise) gameStates.set(user.room, { ...gameState, room: user.room, lastUpdate: new Date().toISOString() }) } }) // Bot integration: receive bot action (play card or draw) socket.on('botAction', (action, callback) => { const user = getUser(socket.id) if(user && user.name === 'Player 2') { // Forward action to game logic. Client will handle via regular game state updates callback && callback({ success: true }) } }) // Bot integration: request current game state socket.on('requestGameState', (callback) => { const user = getUser(socket.id) if(user) { // Request game state from room socket.to(user.room).emit('gameStateRequested') callback && callback({ success: true }) } }) socket.on('disconnect', () => { const user = removeUser(socket.id) if(user) io.to(user.room).emit('roomData', {room: user.room, users: getUsersInRoom(user.room)}) }) }) //serve static assets in production if(process.env.NODE_ENV === 'production') { //set static folder app.use(express.static('client/build')) app.get('*', (req, res) => { res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html')) }) } server.listen(PORT, () => { console.log(`Server running on port ${PORT}`) })