initial commit

This commit is contained in:
Jose Conde
2024-07-05 01:19:43 +02:00
commit 733ac3891f
43 changed files with 3660 additions and 0 deletions

View File

@ -0,0 +1,5 @@
import { LoggingService } from "../../common/LoggingService";
export class ControllerBase {
protected logger = new LoggingService();
}

View File

@ -0,0 +1,77 @@
import { LoggingService } from "../../common/LoggingService";
import { GameSession } from "../../game/GameSession";
import { NetworkPlayer } from "../../game/entities/player/NetworkPlayer";
import { ControllerBase } from "./ControllerBase";
export class SessionController extends ControllerBase{
private static sessions: any = {};
constructor() {
super();
this.logger.info('SessionController created');
}
createSession(data: any, socketId: string): any {
const { user, sessionName } = data;
const player = new NetworkPlayer(user, socketId);
const session = new GameSession(player, sessionName);
SessionController.sessions[session.id] = session;
return {
status: 'ok',
sessionId: session.id,
playerId: player.id
};
}
joinSession(data: any, socketId: string): any {
this.logger.debug('joinSession data :>> ')
this.logger.object(data);
const { user, sessionId } = data;
const session = SessionController.sessions[sessionId];
const player = new NetworkPlayer(user, socketId);
session.addPlayer(player);
return {
status: 'ok',
sessionId: session.id,
playerId: player.id
};
}
startSession(data: any): any {
const sessionId: string = data.sessionId;
const seed: string | undefined = data.seed;
const session = SessionController.sessions[sessionId];
if (!session) {
return ({
status: 'error',
message: 'Session not found'
});
} else if (session.gameInProgress) {
return {
status: 'error',
message: 'Game already in progress'
};
} else {
const missingHumans = session.maxPlayers - session.numPlayers;
for (let i = 0; i < missingHumans; i++) {
session.addPlayer(session.createPlayerAI(i));
}
session.start(seed);
return {
status: 'ok'
};
}
}
getSession(id: string) {
return SessionController.sessions[id];
}
deleteSession(id: string) {
delete SessionController.sessions[id];
}
}

89
src/server/index.html Normal file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Socket.IO chat</title>
<style>
textarea {
width: 100%;
height: 60px;
resize: none;
}
#response {
height: 200px;
}
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<p>
<select id="event" autocomplete="off">
<option value="">Select event</option>
</select>
</p>
<!-- <p><input id="room" autocomplete="off" /></p> -->
<p><textarea id="message" autocomplete="off" placeholder="Data"></textarea></p>
<p><button>Send</button></p>
<p><textarea id="response" autocomplete="off" placeholder="Response"></textarea></p>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById("form");
const event = document.getElementById("event");
// const room = document.getElementById("room");
const message = document.getElementById("message");
const responseEl = document.getElementById("response");
const messages = document.getElementById("messages");
const options = [
{ value: "createSession", default: '{"user": "arhuako"}' },
{ value: "startSession", default: '{"sessionId": "arhuako"}' },
{ value: "joinSession", default: '{"user": "pepe", "sessionId": "arhuako"}' },
{ value: "leaveSession", default: '{"user": "pepe", "sessionId": "arhuako"}' },
{ value: "chat message", default: "chat message" }
];
//`<option value="${option.value}">${option.value}</option>`
options.forEach((option) => {
const opt = document.createElement("option");
opt.value = option.value;
opt.textContent = option.value;
event.appendChild(opt);
});
event.addEventListener("change", (e) => {
const option = options.find((option) => option.value === e.target.value);
message.value = option.default;
});
const getMessage = (msg) => {
if (msg.startsWith("{") && msg.endsWith("}")) return JSON.parse(msg);
return msg;
};
form.addEventListener("submit", async (e) => {
e.preventDefault();
if (event.value.trim() && message.value.trim()) {
const response = await socket.emitWithAck(event.value.trim(), getMessage(message.value.trim()));
console.log('response :>> ', response);
message.value = "";
const responseStr = JSON.stringify(response, null, 2);
responseEl.value = !responseEl.value ? responseStr : responseEl.value + '\n---\n ' + responseStr;
event.selectedIndex = 0;
}
});
socket.onAny((eventName, msg) => {
const item = document.createElement("li");
item.textContent = `${eventName}: ${msg}`;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
</body>
</html>

25
src/server/index.ts Normal file
View File

@ -0,0 +1,25 @@
import express from 'express';
import http from 'http';
import cors from 'cors';
import { join } from 'path';
import { NetworkClientNotifier } from '../game/NetworkClientNotifier';
import { SocketIoService } from './services/SocketIoService';
const clientNotifier = new NetworkClientNotifier();
const app = express();
const httpServer = http.createServer(app);
const socketIoService = new SocketIoService(httpServer);
clientNotifier.setSocket(socketIoService.getServer());
const PORT = process.env.PORT || 3000;
console.log('__dirname :>> ', __dirname);
app.use(cors());
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'));
});
httpServer.listen(PORT, () => {
console.log(`listening on *:${PORT}`);
});

View File

@ -0,0 +1,5 @@
import { LoggingService } from "../../common/LoggingService";
export class ServiceBase {
protected logger = new LoggingService();
}

View File

@ -0,0 +1,75 @@
import { Server as HttpServer } from "http";
import { ServiceBase } from "./ServiceBase";
import { Server } from "socket.io";
import { SessionController } from "../controllers/SessionController";
export class SocketIoService extends ServiceBase{
io: Server
constructor(private httpServer: HttpServer) {
super()
this.io = this.socketIo(httpServer);
this.initListeners();
}
public getServer(): Server {
return this.io;
}
private initListeners() {
const sessionController = new SessionController();
this.io.on('connection', (socket) => {
console.log(`connect ${socket.id}`);
if (socket.recovered) {
// recovery was successful: socket.id, socket.rooms and socket.data were restored
console.log("recovered!");
console.log("socket.rooms:", socket.rooms);
console.log("socket.data:", socket.data);
} else {
console.log("new connection");
socket.join('room-general')
socket.data.foo = "bar";
}
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.on('createSession', (data, callback) => {
const response = sessionController.createSession(data, socket.id);
callback(response);
});
socket.on('startSession', (data, callback) => {
const response = sessionController.startSession(data);
callback(response);
});
socket.on('joinSession', (data, callback) => {
const response = sessionController.joinSession(data, socket.id);
callback(response);
});
// socket.on('chat message', (msg, callback) => {
// io.emit('chat message', msg);
// callback({
// status: 'ok',
// message: 'Message received',
// })
// });
});
}
private socketIo(httpServer: HttpServer): Server {
return new Server(httpServer, {
cors: {
origin: '*',
},
connectionStateRecovery: {
maxDisconnectionDuration: 15 * 60 * 1000,
skipMiddlewares: true,
},
connectTimeout: 15 * 60 * 1000,
})
}
}