From ff17cb99d62fbc467eb012d541ce91b3cd3c4135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 9 Dec 2020 16:07:06 +0100 Subject: [PATCH] Cleaning up pusher --- pusher/src/Model/Group.ts | 138 --------------------- pusher/src/Model/PusherRoom.ts | 10 -- pusher/src/Model/User.ts | 35 ------ pusher/src/Services/SocketManager.ts | 115 ----------------- pusher/tests/GameRoomTest.ts | 97 --------------- pusher/tests/PositionNotifierTest.ts | 176 --------------------------- 6 files changed, 571 deletions(-) delete mode 100644 pusher/src/Model/Group.ts delete mode 100644 pusher/src/Model/User.ts delete mode 100644 pusher/tests/GameRoomTest.ts delete mode 100644 pusher/tests/PositionNotifierTest.ts diff --git a/pusher/src/Model/Group.ts b/pusher/src/Model/Group.ts deleted file mode 100644 index 92d5b0a7..00000000 --- a/pusher/src/Model/Group.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { ConnectCallback, DisconnectCallback } from "./PusherRoom"; -import { User } from "./User"; -import {PositionInterface} from "_Model/PositionInterface"; -import {Movable} from "_Model/Movable"; -import {PositionDispatcher} from "_Model/PositionDispatcher"; -import {gaugeManager} from "../Services/GaugeManager"; - -export class Group implements Movable { - static readonly MAX_PER_GROUP = 4; - - private static nextId: number = 1; - - private id: number; - private users: Set; - private x!: number; - private y!: number; - private hasEditedGauge: boolean = false; - private wasDestroyed: boolean = false; - private roomId: string; - - - constructor(roomId: string, users: User[], private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionDispatcher) { - this.roomId = roomId; - this.users = new Set(); - this.id = Group.nextId; - Group.nextId++; - //we only send a event for prometheus metrics if the group lives more than 5 seconds - setTimeout(() => { - if (!this.wasDestroyed) { - this.hasEditedGauge = true; - gaugeManager.incNbGroupsPerRoomGauge(roomId); - } - }, 5000); - - users.forEach((user: User) => { - this.join(user); - }); - - this.updatePosition(); - } - - getUsers(): User[] { - return Array.from(this.users.values()); - } - - getId() : number { - return this.id; - } - - /** - * Returns the barycenter of all users (i.e. the center of the group) - */ - getPosition(): PositionInterface { - return { - x: this.x, - y: this.y - }; - } - - /** - * Computes the barycenter of all users (i.e. the center of the group) - */ - updatePosition(): void { - const oldX = this.x; - const oldY = this.y; - - let x = 0; - let y = 0; - // Let's compute the barycenter of all users. - this.users.forEach((user: User) => { - const position = user.getPosition(); - x += position.x; - y += position.y; - }); - x /= this.users.size; - y /= this.users.size; - if (this.users.size === 0) { - throw new Error("EMPTY GROUP FOUND!!!"); - } - this.x = x; - this.y = y; - - if (oldX === undefined) { - this.positionNotifier.enter(this); - } else { - this.positionNotifier.updatePosition(this, {x, y}, {x: oldX, y: oldY}); - } - } - - isFull(): boolean { - return this.users.size >= Group.MAX_PER_GROUP; - } - - isEmpty(): boolean { - return this.users.size <= 1; - } - - join(user: User): void - { - // Broadcast on the right event - this.connectCallback(user, this); - this.users.add(user); - user.group = this; - } - - leave(user: User): void - { - const success = this.users.delete(user); - if (success === false) { - throw new Error("Could not find user "+user.id+" in the group "+this.id); - } - user.group = undefined; - - if (this.users.size !== 0) { - this.updatePosition(); - } - - // Broadcast on the right event - this.disconnectCallback(user, this); - } - - /** - * Let's kick everybody out. - * Usually used when there is only one user left. - */ - destroy(): void - { - if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId); - for (const user of this.users) { - this.leave(user); - } - this.wasDestroyed = true; - } - - get getSize(){ - return this.users.size; - } -} diff --git a/pusher/src/Model/PusherRoom.ts b/pusher/src/Model/PusherRoom.ts index d637c00c..92ff87d1 100644 --- a/pusher/src/Model/PusherRoom.ts +++ b/pusher/src/Model/PusherRoom.ts @@ -1,20 +1,10 @@ -import {PointInterface} from "./Websocket/PointInterface"; -import {Group} from "./Group"; -import {User} from "./User"; import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; -import {PositionInterface} from "_Model/PositionInterface"; -import {Identificable} from "_Model/Websocket/Identificable"; import {PositionDispatcher} from "./PositionDispatcher"; import {ViewportInterface} from "_Model/Websocket/ViewportMessage"; -import {Movable} from "_Model/Movable"; import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "./RoomIdentifier"; import {arrayIntersect} from "../Services/ArrayHelper"; -import {MAX_USERS_PER_ROOM} from "../Enum/EnvironmentVariable"; import {ZoneEventListener} from "_Model/Zone"; -export type ConnectCallback = (user: User, group: Group) => void; -export type DisconnectCallback = (user: User, group: Group) => void; - export enum GameRoomPolicyTypes { ANONYMUS_POLICY = 1, MEMBERS_ONLY_POLICY, diff --git a/pusher/src/Model/User.ts b/pusher/src/Model/User.ts deleted file mode 100644 index 3234861f..00000000 --- a/pusher/src/Model/User.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Group } from "./Group"; -import { PointInterface } from "./Websocket/PointInterface"; -import {Zone} from "_Model/Zone"; -import {Movable} from "_Model/Movable"; -import {PositionInterface} from "_Model/PositionInterface"; -import {PositionDispatcher} from "_Model/PositionDispatcher"; -import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; - -export class User implements Movable { - public listenedZones: Set; - public group?: Group; - - public constructor( - public id: number, - public uuid: string, - private position: PointInterface, - public silent: boolean, - private positionNotifier: PositionDispatcher, - public readonly socket: ExSocketInterface - ) { - this.listenedZones = new Set(); - - this.positionNotifier.enter(this); - } - - public getPosition(): PointInterface { - return this.position; - } - - public setPosition(position: PointInterface): void { - const oldPosition = this.position; - this.position = position; - this.positionNotifier.updatePosition(this, position, oldPosition); - } -} diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 2fb6c97c..977756e8 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -26,9 +26,7 @@ import { SendUserMessage, JoinRoomMessage, CharacterLayerMessage, PusherToBackMessage } from "../Messages/generated/messages_pb"; import {PointInterface} from "../Model/Websocket/PointInterface"; -import {User} from "../Model/User"; import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils"; -import {Group} from "../Model/Group"; import {cpuTracker} from "./CpuTracker"; import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable"; import {Movable} from "../Model/Movable"; @@ -477,119 +475,6 @@ export class SocketManager implements ZoneEventListener { } }*/ - private emitCreateUpdateGroupEvent(client: ExSocketInterface, group: Group): void { - const position = group.getPosition(); - const pointMessage = new PointMessage(); - pointMessage.setX(Math.floor(position.x)); - pointMessage.setY(Math.floor(position.y)); - const groupUpdateMessage = new GroupUpdateMessage(); - groupUpdateMessage.setGroupid(group.getId()); - groupUpdateMessage.setPosition(pointMessage); - groupUpdateMessage.setGroupsize(group.getSize); - - const subMessage = new SubMessage(); - subMessage.setGroupupdatemessage(groupUpdateMessage); - - emitInBatch(client, subMessage); - //socket.emit(SocketIoEvent.GROUP_CREATE_UPDATE, groupUpdateMessage.serializeBinary().buffer); - } - - private emitDeleteGroupEvent(client: ExSocketInterface, groupId: number): void { - const groupDeleteMessage = new GroupDeleteMessage(); - groupDeleteMessage.setGroupid(groupId); - - const subMessage = new SubMessage(); - subMessage.setGroupdeletemessage(groupDeleteMessage); - - emitInBatch(client, subMessage); - } - - private emitUserLeftEvent(client: ExSocketInterface, userId: number): void { - const userLeftMessage = new UserLeftMessage(); - userLeftMessage.setUserid(userId); - - const subMessage = new SubMessage(); - subMessage.setUserleftmessage(userLeftMessage); - - emitInBatch(client, subMessage); - } - - private joinWebRtcRoom(user: User, group: Group) { - /*const roomId: string = "webrtcroom"+group.getId(); - if (user.socket.webRtcRoomId === roomId) { - return; - }*/ - - for (const otherUser of group.getUsers()) { - if (user === otherUser) { - continue; - } - - // Let's send 2 messages: one to the user joining the group and one to the other user - const webrtcStartMessage1 = new WebRtcStartMessage(); - webrtcStartMessage1.setUserid(otherUser.id); - webrtcStartMessage1.setName(otherUser.socket.name); - webrtcStartMessage1.setInitiator(true); - - const serverToClientMessage1 = new ServerToClientMessage(); - serverToClientMessage1.setWebrtcstartmessage(webrtcStartMessage1); - - if (!user.socket.disconnecting) { - user.socket.send(serverToClientMessage1.serializeBinary().buffer, true); - //console.log('Sending webrtcstart initiator to '+user.socket.userId) - } - - const webrtcStartMessage2 = new WebRtcStartMessage(); - webrtcStartMessage2.setUserid(user.id); - webrtcStartMessage2.setName(user.socket.name); - webrtcStartMessage2.setInitiator(false); - - const serverToClientMessage2 = new ServerToClientMessage(); - serverToClientMessage2.setWebrtcstartmessage(webrtcStartMessage2); - - if (!otherUser.socket.disconnecting) { - otherUser.socket.send(serverToClientMessage2.serializeBinary().buffer, true); - //console.log('Sending webrtcstart to '+otherUser.socket.userId) - } - - } - } - - //disconnect user - private disConnectedUser(user: User, group: Group) { - // Most of the time, sending a disconnect event to one of the players is enough (the player will close the connection - // which will be shut for the other player). - // However! In the rare case where the WebRTC connection is not yet established, if we close the connection on one of the player, - // the other player will try connecting until a timeout happens (during this time, the connection icon will be displayed for nothing). - // So we also send the disconnect event to the other player. - for (const otherUser of group.getUsers()) { - if (user === otherUser) { - continue; - } - - const webrtcDisconnectMessage1 = new WebRtcDisconnectMessage(); - webrtcDisconnectMessage1.setUserid(user.id); - - const serverToClientMessage1 = new ServerToClientMessage(); - serverToClientMessage1.setWebrtcdisconnectmessage(webrtcDisconnectMessage1); - - if (!otherUser.socket.disconnecting) { - otherUser.socket.send(serverToClientMessage1.serializeBinary().buffer, true); - } - - - const webrtcDisconnectMessage2 = new WebRtcDisconnectMessage(); - webrtcDisconnectMessage2.setUserid(otherUser.id); - - const serverToClientMessage2 = new ServerToClientMessage(); - serverToClientMessage2.setWebrtcdisconnectmessage(webrtcDisconnectMessage2); - - if (!user.socket.disconnecting) { - user.socket.send(serverToClientMessage2.serializeBinary().buffer, true); - } - } - } - emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) { const pusherToBackMessage = new PusherToBackMessage(); pusherToBackMessage.setPlayglobalmessage(playglobalmessage); diff --git a/pusher/tests/GameRoomTest.ts b/pusher/tests/GameRoomTest.ts deleted file mode 100644 index a0e449b2..00000000 --- a/pusher/tests/GameRoomTest.ts +++ /dev/null @@ -1,97 +0,0 @@ -import "jasmine"; -import {PusherRoom, ConnectCallback, DisconnectCallback } from "_Model/PusherRoom"; -import {Point} from "_Model/Websocket/Point"; -import { Group } from "../src/Model/Group"; -import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; -import {User} from "_Model/User"; - -function createMockUser(userId: number): ExSocketInterface { - return { - userId - } as ExSocketInterface; -} - -describe("GameRoom", () => { - it("should connect user1 and user2", () => { - let connectCalledNumber: number = 0; - const connect: ConnectCallback = (user: User, group: Group): void => { - connectCalledNumber++; - } - const disconnect: DisconnectCallback = (user: User, group: Group): void => { - - } - - const world = new PusherRoom('_/global/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}); - - world.join(createMockUser(1), new Point(100, 100)); - - world.join(createMockUser(2), new Point(500, 100)); - - world.updatePosition({ userId: 2 }, new Point(261, 100)); - - expect(connectCalledNumber).toBe(0); - - world.updatePosition({ userId: 2 }, new Point(101, 100)); - - expect(connectCalledNumber).toBe(2); - - world.updatePosition({ userId: 2 }, new Point(102, 100)); - expect(connectCalledNumber).toBe(2); - }); - - it("should connect 3 users", () => { - let connectCalled: boolean = false; - const connect: ConnectCallback = (user: User, group: Group): void => { - connectCalled = true; - } - const disconnect: DisconnectCallback = (user: User, group: Group): void => { - - } - - const world = new PusherRoom('_/global/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}); - - world.join(createMockUser(1), new Point(100, 100)); - - world.join(createMockUser(2), new Point(200, 100)); - - expect(connectCalled).toBe(true); - connectCalled = false; - - // baz joins at the outer limit of the group - world.join(createMockUser(3), new Point(311, 100)); - - expect(connectCalled).toBe(false); - - world.updatePosition({ userId: 3 }, new Point(309, 100)); - - expect(connectCalled).toBe(true); - }); - - it("should disconnect user1 and user2", () => { - let connectCalled: boolean = false; - let disconnectCallNumber: number = 0; - const connect: ConnectCallback = (user: User, group: Group): void => { - connectCalled = true; - } - const disconnect: DisconnectCallback = (user: User, group: Group): void => { - disconnectCallNumber++; - } - - const world = new PusherRoom('_/global/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}); - - world.join(createMockUser(1), new Point(100, 100)); - - world.join(createMockUser(2), new Point(259, 100)); - - expect(connectCalled).toBe(true); - expect(disconnectCallNumber).toBe(0); - - world.updatePosition({ userId: 2 }, new Point(100+160+160+1, 100)); - - expect(disconnectCallNumber).toBe(2); - - world.updatePosition({ userId: 2 }, new Point(262, 100)); - expect(disconnectCallNumber).toBe(2); - }); - -}) diff --git a/pusher/tests/PositionNotifierTest.ts b/pusher/tests/PositionNotifierTest.ts deleted file mode 100644 index 6b70a45e..00000000 --- a/pusher/tests/PositionNotifierTest.ts +++ /dev/null @@ -1,176 +0,0 @@ -import "jasmine"; -import {PusherRoom, ConnectCallback, DisconnectCallback } from "_Model/PusherRoom"; -import {Point} from "_Model/Websocket/Point"; -import { Group } from "../src/Model/Group"; -import {PositionDispatcher} from "_Model/PositionDispatcher"; -import {User} from "../src/Model/User"; -import {PointInterface} from "../src/Model/Websocket/PointInterface"; -import {Zone} from "_Model/Zone"; -import {Movable} from "_Model/Movable"; -import {PositionInterface} from "_Model/PositionInterface"; -import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; - - -describe("PositionNotifier", () => { - it("should receive notifications when player moves", () => { - let enterTriggered = false; - let moveTriggered = false; - let leaveTriggered = false; - - const positionNotifier = new PositionDispatcher(300, 300, (thing: Movable) => { - enterTriggered = true; - }, (thing: Movable, position: PositionInterface) => { - moveTriggered = true; - }, (thing: Movable) => { - leaveTriggered = true; - }); - - const user1 = new User(1, 'test', { - x: 500, - y: 500, - moving: false, - direction: 'down' - }, false, positionNotifier, {} as ExSocketInterface); - - const user2 = new User(2, 'test', { - x: -9999, - y: -9999, - moving: false, - direction: 'down' - }, false, positionNotifier, {} as ExSocketInterface); - - positionNotifier.setViewport(user1, { - left: 200, - right: 600, - top: 100, - bottom: 500 - }); - - user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); - - expect(enterTriggered).toBe(true); - expect(moveTriggered).toBe(false); - enterTriggered = false; - - // Move inside the zone - user2.setPosition({x:501, y:500, direction: 'down', moving: false}); - - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(true); - moveTriggered = false; - - // Move out of the zone in a zone that we don't track - user2.setPosition({x: 901, y: 500, direction: 'down', moving: false}); - - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(true); - leaveTriggered = false; - - // Move back in - user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); - expect(enterTriggered).toBe(true); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(false); - enterTriggered = false; - - // Move out of the zone in a zone that we do track - user2.setPosition({x: 200, y: 500, direction: 'down', moving: false}); - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(true); - expect(leaveTriggered).toBe(false); - moveTriggered = false; - - // Leave the room - positionNotifier.leave(user2); - positionNotifier.removeViewport(user2); - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(true); - leaveTriggered = false; - }); - - it("should receive notifications when camera moves", () => { - let enterTriggered = false; - let moveTriggered = false; - let leaveTriggered = false; - - const positionNotifier = new PositionDispatcher(300, 300, (thing: Movable) => { - enterTriggered = true; - }, (thing: Movable, position: PositionInterface) => { - moveTriggered = true; - }, (thing: Movable) => { - leaveTriggered = true; - }); - - const user1 = new User(1, 'test', { - x: 500, - y: 500, - moving: false, - direction: 'down' - }, false, positionNotifier, {} as ExSocketInterface); - - const user2 = new User(2, 'test', { - x: 0, - y: 0, - moving: false, - direction: 'down' - }, false, positionNotifier, {} as ExSocketInterface); - - let newUsers = positionNotifier.setViewport(user1, { - left: 200, - right: 600, - top: 100, - bottom: 500 - }); - - expect(newUsers.length).toBe(2); - expect(enterTriggered).toBe(true); - enterTriggered = false; - - user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); - - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(true); - moveTriggered = false; - - // Move the viewport but the user stays inside. - positionNotifier.setViewport(user1, { - left: 201, - right: 601, - top: 100, - bottom: 500 - }); - - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(false); - - // Move the viewport out of the user. - positionNotifier.setViewport(user1, { - left: 901, - right: 1001, - top: 100, - bottom: 500 - }); - - expect(enterTriggered).toBe(false); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(true); - leaveTriggered = false; - - // Move the viewport back on the user. - newUsers = positionNotifier.setViewport(user1, { - left: 200, - right: 600, - top: 100, - bottom: 500 - }); - - expect(enterTriggered).toBe(true); - expect(moveTriggered).toBe(false); - expect(leaveTriggered).toBe(false); - enterTriggered = false; - expect(newUsers.length).toBe(2); - }); -})