From 75d9ed8dfa1d7bf9c3abb428352d3489869f1039 Mon Sep 17 00:00:00 2001 From: arp Date: Fri, 16 Oct 2020 14:36:43 +0200 Subject: [PATCH] implemented the admin websocket now send data --- back/src/Controller/IoSocketController.ts | 47 ++++++++++++++--- back/src/Controller/MapController.ts | 2 +- back/src/Model/GameRoom.ts | 2 +- back/src/Model/User.ts | 1 + back/src/Services/ClientEventsEmitter.ts | 32 ++++++++++++ back/src/Services/SocketManager.ts | 52 ++++++++++++++++--- back/tests/PositionNotifierTest.ts | 8 +-- .../src/Phaser/Reconnecting/FourOFourScene.ts | 8 --- 8 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 back/src/Services/ClientEventsEmitter.ts diff --git a/back/src/Controller/IoSocketController.ts b/back/src/Controller/IoSocketController.ts index dc8b237f..707df4a6 100644 --- a/back/src/Controller/IoSocketController.ts +++ b/back/src/Controller/IoSocketController.ts @@ -23,6 +23,8 @@ import {adminApi} from "../Services/AdminApi"; import {socketManager} from "../Services/SocketManager"; import {emitInBatch, resetPing} from "../Services/IoSocketHelpers"; import Jwt from "jsonwebtoken"; +import {clientEventsEmitter} from "../Services/ClientEventsEmitter"; +import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable"; export class IoSocketController { private nextUserId: number = 1; @@ -33,18 +35,51 @@ export class IoSocketController { } adminRoomSocket() { - /*this.app.ws('/admin/rooms', { + this.app.ws('/admin/rooms', { + upgrade: (res, req, context) => { + const query = parse(req.getQuery()); + const websocketKey = req.getHeader('sec-websocket-key'); + const websocketProtocol = req.getHeader('sec-websocket-protocol'); + const websocketExtensions = req.getHeader('sec-websocket-extensions'); + const token = query.token; + if (token !== ADMIN_API_TOKEN) { + console.log('Admin access refused for token: '+token) + res.writeStatus("401 Unauthorized").end('Incorrect token'); + } + const roomId = query.roomId as string; + + res.upgrade( + {roomId}, + websocketKey, websocketProtocol, websocketExtensions, context, + ); + }, open: (ws) => { - console.log('o', ws) - ws.send('Hello'); + console.log('Admin socket connect for room: '+ws.roomId); + ws.send('Data:'+JSON.stringify(socketManager.getAdminSocketDataFor(ws.roomId as string))); + ws.clientJoinCallback = (clientUUid: string, roomId: string) => { + const wsroomId = ws.roomId as string; + if(wsroomId === roomId) { + ws.send('MemberJoin:'+clientUUid+';'+roomId); + } + }; + ws.clientLeaveCallback = (clientUUid: string, roomId: string) => { + const wsroomId = ws.roomId as string; + if(wsroomId === roomId) { + ws.send('MemberLeave:'+clientUUid+';'+roomId); + } + }; + clientEventsEmitter.registerToClientJoin(ws.clientJoinCallback); + clientEventsEmitter.registerToClientLeave(ws.clientLeaveCallback); }, message: (ws, arrayBuffer, isBinary): void => { - console.log('m', ws) + console.log('m', ws); //todo: add admin actions such as ban here }, close: (ws, code, message) => { - console.log('close'); + //todo make sure this code unregister the right listeners + clientEventsEmitter.unregisterFromClientJoin(ws.clientJoinCallback); + clientEventsEmitter.unregisterFromClientLeave(ws.clientLeaveCallback); } - })*/ + }) } ioConnection() { diff --git a/back/src/Controller/MapController.ts b/back/src/Controller/MapController.ts index 027fc5b8..abe34886 100644 --- a/back/src/Controller/MapController.ts +++ b/back/src/Controller/MapController.ts @@ -58,7 +58,7 @@ export class MapController extends BaseController{ this.addCorsHeaders(res); res.end(JSON.stringify(mapDetails)); } catch (e) { - console.error(e); + console.error(e.message || e); res.writeStatus("500 Internal Server Error") this.addCorsHeaders(res); res.end("An error occurred"); diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index baa54896..5efde159 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -85,7 +85,7 @@ export class GameRoom { } public join(socket : ExSocketInterface, userPosition: PointInterface): void { - const user = new User(socket.userId, userPosition, false, this.positionNotifier, socket); + const user = new User(socket.userId, socket.userUuid, userPosition, false, this.positionNotifier, socket); this.users.set(socket.userId, user); // Let's call update position to trigger the join / leave room //this.updatePosition(socket, userPosition); diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index 34377dc4..86a227f4 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -12,6 +12,7 @@ export class User implements Movable { public constructor( public id: number, + public uuid: string, private position: PointInterface, public silent: boolean, private positionNotifier: PositionNotifier, diff --git a/back/src/Services/ClientEventsEmitter.ts b/back/src/Services/ClientEventsEmitter.ts new file mode 100644 index 00000000..7b888ef6 --- /dev/null +++ b/back/src/Services/ClientEventsEmitter.ts @@ -0,0 +1,32 @@ +const EventEmitter = require('events'); + +const clientJoinEvent = 'clientJoin'; +const clientLeaveEvent = 'clientLeave'; + +class ClientEventsEmitter extends EventEmitter { + emitClientJoin(clientUUid: string, roomId: string): void { + this.emit(clientJoinEvent, clientUUid, roomId); + } + + emitClientLeave(clientUUid: string, roomId: string): void { + this.emit(clientLeaveEvent, clientUUid, roomId); + } + + registerToClientJoin(callback: (clientUUid: string, roomId: string) => void): void { + this.on(clientJoinEvent, callback); + } + + registerToClientLeave(callback: (clientUUid: string, roomId: string) => void): void { + this.on(clientLeaveEvent, callback); + } + + unregisterFromClientJoin(callback: (clientUUid: string, roomId: string) => void): void { + this.removeListener(clientJoinEvent, callback); + } + + unregisterFromClientLeave(callback: (clientUUid: string, roomId: string) => void): void { + this.removeListener(clientLeaveEvent, callback); + } +} + +export const clientEventsEmitter = new ClientEventsEmitter(); \ No newline at end of file diff --git a/back/src/Services/SocketManager.ts b/back/src/Services/SocketManager.ts index e704ac4f..44579123 100644 --- a/back/src/Services/SocketManager.ts +++ b/back/src/Services/SocketManager.ts @@ -36,6 +36,19 @@ import {Gauge} from "prom-client"; import {emitError, emitInBatch} from "./IoSocketHelpers"; import Jwt from "jsonwebtoken"; import {JITSI_URL} from "../Enum/EnvironmentVariable"; +import {clientEventsEmitter} from "./ClientEventsEmitter"; + +interface AdminSocketRoomsList { + [index: string]: number; +} +interface AdminSocketUsersList { + [index: string]: boolean; +} + +export interface AdminSocketData { + rooms: AdminSocketRoomsList, + users: AdminSocketUsersList, +} class SocketManager { private Worlds: Map = new Map(); @@ -54,6 +67,34 @@ class SocketManager { help: 'Number of clients per room', labelNames: [ 'room' ] }); + + clientEventsEmitter.registerToClientJoin((clientUUid, roomId) => { + this.nbClientsGauge.inc(); + // Let's log server load when a user joins + console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)'); + }); + clientEventsEmitter.registerToClientLeave((clientUUid, roomId) => { + this.nbClientsGauge.dec(); + // Let's log server load when a user leaves + console.log('A user left (', this.sockets.size, ' connected users)'); + }); + } + + getAdminSocketDataFor(roomId:string): AdminSocketData { + const data:AdminSocketData = { + rooms: {}, + users: {}, + } + const room = this.Worlds.get(roomId); + if (room === undefined) { + return data; + } + const users = room.getUsers(); + data.rooms[roomId] = users.size; + users.forEach(user => { + data.users[user.uuid] = true + }) + return data; } handleJoinRoom(client: ExSocketInterface): void { @@ -61,10 +102,7 @@ class SocketManager { const viewport = client.viewport; try { this.sockets.set(client.userId, client); //todo: should this be at the end of the function? - this.nbClientsGauge.inc(); - // Let's log server load when a user joins - console.log(new Date().toISOString() + ' A user joined (', socketManager.sockets.size, ' connected users)'); - + clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId); //join new previous room const gameRoom = this.joinRoom(client, position); @@ -332,12 +370,10 @@ class SocketManager { //user leave previous room //Client.leave(Client.roomId); } finally { - this.nbClientsPerRoomGauge.dec({ room: Client.roomId }); //delete Client.roomId; this.sockets.delete(Client.userId); - // Let's log server load when a user leaves - this.nbClientsGauge.dec(); - console.log('A user left (', this.sockets.size, ' connected users)'); + this.nbClientsPerRoomGauge.dec({ room: Client.roomId }); + clientEventsEmitter.emitClientLeave(Client.userUuid, Client.roomId); } } } diff --git a/back/tests/PositionNotifierTest.ts b/back/tests/PositionNotifierTest.ts index 0f556866..573a3233 100644 --- a/back/tests/PositionNotifierTest.ts +++ b/back/tests/PositionNotifierTest.ts @@ -25,14 +25,14 @@ describe("PositionNotifier", () => { leaveTriggered = true; }); - const user1 = new User(1, { + const user1 = new User(1, 'test', { x: 500, y: 500, moving: false, direction: 'down' }, false, positionNotifier, {} as ExSocketInterface); - const user2 = new User(2, { + const user2 = new User(2, 'test', { x: -9999, y: -9999, moving: false, @@ -103,14 +103,14 @@ describe("PositionNotifier", () => { leaveTriggered = true; }); - const user1 = new User(1, { + const user1 = new User(1, 'test', { x: 500, y: 500, moving: false, direction: 'down' }, false, positionNotifier, {} as ExSocketInterface); - const user2 = new User(2, { + const user2 = new User(2, 'test', { x: 0, y: 0, moving: false, diff --git a/front/src/Phaser/Reconnecting/FourOFourScene.ts b/front/src/Phaser/Reconnecting/FourOFourScene.ts index 4a9b1a6f..36106796 100644 --- a/front/src/Phaser/Reconnecting/FourOFourScene.ts +++ b/front/src/Phaser/Reconnecting/FourOFourScene.ts @@ -64,13 +64,5 @@ export class FourOFourScene extends Phaser.Scene { this.cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, 'cat', 6); this.cat.flipY=true; - /*this.anims.create({ - key: 'right', - frames: this.anims.generateFrameNumbers('cat', { start: 6, end: 8 }), - frameRate: 10, - repeat: -1 - }); - cat.play('right');*/ - } }