temp
This commit is contained in:
parent
1270ae6817
commit
0b78eb6277
@ -3,20 +3,12 @@ import {ADMIN_API_TOKEN, ADMIN_API_URL, SECRET_KEY, URL_ROOM_STARTED} from "../E
|
|||||||
import { uuid } from 'uuidv4';
|
import { uuid } from 'uuidv4';
|
||||||
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
|
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
|
||||||
import {BaseController} from "./BaseController";
|
import {BaseController} from "./BaseController";
|
||||||
import Axios from "axios";
|
import {adminApi, AdminApiData} from "../Services/AdminApi";
|
||||||
|
|
||||||
export interface TokenInterface {
|
export interface TokenInterface {
|
||||||
userUuid: string
|
userUuid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AdminApiData {
|
|
||||||
organizationSlug: string
|
|
||||||
worldSlug: string
|
|
||||||
roomSlug: string
|
|
||||||
mapUrlStart: string
|
|
||||||
userUuid: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AuthenticateController extends BaseController {
|
export class AuthenticateController extends BaseController {
|
||||||
|
|
||||||
constructor(private App : TemplatedApp) {
|
constructor(private App : TemplatedApp) {
|
||||||
@ -51,13 +43,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
let newUrl: string|null = null;
|
let newUrl: string|null = null;
|
||||||
|
|
||||||
if (organizationMemberToken) {
|
if (organizationMemberToken) {
|
||||||
if (!ADMIN_API_URL) {
|
const data = await adminApi.fetchMemberDataByToken(organizationMemberToken);
|
||||||
return res.status(401).send('No admin backoffice set!');
|
|
||||||
}
|
|
||||||
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
|
||||||
const data = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken,
|
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
|
||||||
).then((res): AdminApiData => res.data);
|
|
||||||
|
|
||||||
userUuid = data.userUuid;
|
userUuid = data.userUuid;
|
||||||
mapUrlStart = data.mapUrlStart;
|
mapUrlStart = data.mapUrlStart;
|
||||||
|
@ -1,23 +1,14 @@
|
|||||||
import * as http from "http";
|
|
||||||
import {MessageUserPosition, Point} from "../Model/Websocket/MessageUserPosition"; //TODO fix import by "_Model/.."
|
|
||||||
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
||||||
import Jwt, {JsonWebTokenError} from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import {SECRET_KEY, MINIMUM_DISTANCE, GROUP_RADIUS, ALLOW_ARTILLERY} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
import {SECRET_KEY, MINIMUM_DISTANCE, GROUP_RADIUS, ALLOW_ARTILLERY} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
||||||
import {World} from "../Model/World";
|
import {GameRoom} from "../Model/GameRoom";
|
||||||
import {Group} from "../Model/Group";
|
import {Group} from "../Model/Group";
|
||||||
import {User} from "../Model/User";
|
import {User} from "../Model/User";
|
||||||
import {isSetPlayerDetailsMessage,} from "../Model/Websocket/SetPlayerDetailsMessage";
|
import {isSetPlayerDetailsMessage,} from "../Model/Websocket/SetPlayerDetailsMessage";
|
||||||
import {MessageUserJoined} from "../Model/Websocket/MessageUserJoined";
|
|
||||||
import si from "systeminformation";
|
|
||||||
import {Gauge} from "prom-client";
|
import {Gauge} from "prom-client";
|
||||||
import {TokenInterface} from "../Controller/AuthenticateController";
|
import {TokenInterface} from "../Controller/AuthenticateController";
|
||||||
import {isJoinRoomMessageInterface} from "../Model/Websocket/JoinRoomMessage";
|
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
import {isWebRtcSignalMessageInterface} from "../Model/Websocket/WebRtcSignalMessage";
|
|
||||||
import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface";
|
|
||||||
import {isItemEventMessageInterface} from "../Model/Websocket/ItemEventMessage";
|
|
||||||
import {uuid} from 'uuidv4';
|
import {uuid} from 'uuidv4';
|
||||||
import {GroupUpdateInterface} from "_Model/Websocket/GroupUpdateInterface";
|
|
||||||
import {Movable} from "../Model/Movable";
|
import {Movable} from "../Model/Movable";
|
||||||
import {
|
import {
|
||||||
PositionMessage,
|
PositionMessage,
|
||||||
@ -42,14 +33,17 @@ import {
|
|||||||
SilentMessage,
|
SilentMessage,
|
||||||
WebRtcSignalToClientMessage,
|
WebRtcSignalToClientMessage,
|
||||||
WebRtcSignalToServerMessage,
|
WebRtcSignalToServerMessage,
|
||||||
WebRtcStartMessage, WebRtcDisconnectMessage, PlayGlobalMessage
|
WebRtcStartMessage,
|
||||||
|
WebRtcDisconnectMessage,
|
||||||
|
PlayGlobalMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
import {App, HttpRequest, TemplatedApp, WebSocket} from "uWebSockets.js"
|
import {HttpRequest, TemplatedApp} from "uWebSockets.js"
|
||||||
import {parse} from "query-string";
|
import {parse} from "query-string";
|
||||||
import {cpuTracker} from "../Services/CpuTracker";
|
import {cpuTracker} from "../Services/CpuTracker";
|
||||||
|
import {adminApi} from "../Services/AdminApi";
|
||||||
|
|
||||||
function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
||||||
socket.batchedMessages.addPayload(payload);
|
socket.batchedMessages.addPayload(payload);
|
||||||
@ -71,7 +65,7 @@ function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
private Worlds: Map<string, World> = new Map<string, World>();
|
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
||||||
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
||||||
private nbClientsGauge: Gauge<string>;
|
private nbClientsGauge: Gauge<string>;
|
||||||
private nbClientsPerRoomGauge: Gauge<string>;
|
private nbClientsPerRoomGauge: Gauge<string>;
|
||||||
@ -100,32 +94,11 @@ export class IoSocketController {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private async getUserUuidFromToken(token: unknown): Promise<string> {
|
||||||
*
|
|
||||||
* @param token
|
if (!token) {
|
||||||
*/
|
|
||||||
/* searchClientByToken(token: string): ExSocketInterface | null {
|
|
||||||
const clients: ExSocketInterface[] = Object.values(this.Io.sockets.sockets) as ExSocketInterface[];
|
|
||||||
for (let i = 0; i < clients.length; i++) {
|
|
||||||
const client = clients[i];
|
|
||||||
if (client.token !== token) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private async authenticate(req: HttpRequest): Promise<{ token: string, userUuid: string }> {
|
|
||||||
//console.log(socket.handshake.query.token);
|
|
||||||
|
|
||||||
const query = parse(req.getQuery());
|
|
||||||
|
|
||||||
if (!query.token) {
|
|
||||||
throw new Error('An authentication error happened, a user tried to connect without a token.');
|
throw new Error('An authentication error happened, a user tried to connect without a token.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = query.token;
|
|
||||||
if (typeof(token) !== "string") {
|
if (typeof(token) !== "string") {
|
||||||
throw new Error('Token is expected to be a string');
|
throw new Error('Token is expected to be a string');
|
||||||
}
|
}
|
||||||
@ -133,22 +106,15 @@ export class IoSocketController {
|
|||||||
|
|
||||||
if(token === 'test') {
|
if(token === 'test') {
|
||||||
if (ALLOW_ARTILLERY) {
|
if (ALLOW_ARTILLERY) {
|
||||||
return {
|
return uuid();
|
||||||
token,
|
|
||||||
userUuid: uuid()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
throw new Error("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if(this.searchClientByToken(socket.handshake.query.token)){
|
return new Promise<string>((resolve, reject) => {
|
||||||
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
|
|
||||||
return next(new Error('Authentication error'));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const promise = new Promise<{ token: string, userUuid: string }>((resolve, reject) => {
|
|
||||||
Jwt.verify(token, SECRET_KEY, {},(err, tokenDecoded) => {
|
Jwt.verify(token, SECRET_KEY, {},(err, tokenDecoded) => {
|
||||||
|
const tokenInterface = tokenDecoded as TokenInterface;
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
||||||
reject(new Error('An authentication error happened, invalid JsonWebToken. '+err.message));
|
reject(new Error('An authentication error happened, invalid JsonWebToken. '+err.message));
|
||||||
@ -159,25 +125,19 @@ export class IoSocketController {
|
|||||||
reject(new Error('Empty token found.'));
|
reject(new Error('Empty token found.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tokenInterface = tokenDecoded as TokenInterface;
|
|
||||||
|
|
||||||
if (!this.isValidToken(tokenInterface)) {
|
if (!this.isValidToken(tokenInterface)) {
|
||||||
reject(new Error('Authentication error, invalid token structure.'));
|
reject(new Error('Authentication error, invalid token structure.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({
|
resolve(tokenInterface.userUuid);
|
||||||
token,
|
|
||||||
userUuid: tokenInterface.userUuid
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ioConnection() {
|
ioConnection() {
|
||||||
this.app.ws('/*', {
|
this.app.ws('/room', {
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
//compression: uWS.SHARED_COMPRESSOR,
|
//compression: uWS.SHARED_COMPRESSOR,
|
||||||
@ -197,7 +157,21 @@ export class IoSocketController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await this.authenticate(req);
|
const query = parse(req.getQuery());
|
||||||
|
|
||||||
|
const moderated = query.moderated || false;
|
||||||
|
const roomId = query.roomId || null;
|
||||||
|
const token = query.token;
|
||||||
|
|
||||||
|
|
||||||
|
const userUuid = await this.getUserUuidFromToken(token);
|
||||||
|
|
||||||
|
this.handleJoinRoom(client, message.getJoinroommessage() as JoinRoomMessage);
|
||||||
|
|
||||||
|
const isGranted = await adminApi.memberIsGrantedAccessToRoom(client.userUuid, roomId);
|
||||||
|
if (!isGranted) {
|
||||||
|
throw Error('Client cannot acces this ressource.');
|
||||||
|
}
|
||||||
|
|
||||||
if (upgradeAborted.aborted) {
|
if (upgradeAborted.aborted) {
|
||||||
console.log("Ouch! Client disconnected before we could upgrade it!");
|
console.log("Ouch! Client disconnected before we could upgrade it!");
|
||||||
@ -209,8 +183,8 @@ export class IoSocketController {
|
|||||||
res.upgrade({
|
res.upgrade({
|
||||||
// Data passed here is accessible on the "websocket" socket object.
|
// Data passed here is accessible on the "websocket" socket object.
|
||||||
url: req.getUrl(),
|
url: req.getUrl(),
|
||||||
token: result.token,
|
token,
|
||||||
userUuid: result.userUuid
|
userUuid
|
||||||
},
|
},
|
||||||
/* Spell these correctly */
|
/* Spell these correctly */
|
||||||
req.getHeader('sec-websocket-key'),
|
req.getHeader('sec-websocket-key'),
|
||||||
@ -250,13 +224,11 @@ export class IoSocketController {
|
|||||||
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
||||||
|
|
||||||
},
|
},
|
||||||
message: (ws, arrayBuffer, isBinary) => {
|
message: (ws, arrayBuffer, isBinary): void => {
|
||||||
const client = ws as ExSocketInterface;
|
const client = ws as ExSocketInterface;
|
||||||
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
||||||
|
|
||||||
if (message.hasJoinroommessage()) {
|
if (message.hasViewportmessage()) {
|
||||||
this.handleJoinRoom(client, message.getJoinroommessage() as JoinRoomMessage);
|
|
||||||
} else if (message.hasViewportmessage()) {
|
|
||||||
this.handleViewport(client, message.getViewportmessage() as ViewportMessage);
|
this.handleViewport(client, message.getViewportmessage() as ViewportMessage);
|
||||||
} else if (message.hasUsermovesmessage()) {
|
} else if (message.hasUsermovesmessage()) {
|
||||||
this.handleUserMovesMessage(client, message.getUsermovesmessage() as UserMovesMessage);
|
this.handleUserMovesMessage(client, message.getUsermovesmessage() as UserMovesMessage);
|
||||||
@ -333,26 +305,22 @@ export class IoSocketController {
|
|||||||
console.warn(message);
|
console.warn(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleJoinRoom(Client: ExSocketInterface, message: JoinRoomMessage): void {
|
private async handleJoinRoom(client: ExSocketInterface, message: JoinRoomMessage): Promise<void> {
|
||||||
try {
|
try {
|
||||||
/*if (!isJoinRoomMessageInterface(message.toObject())) {
|
|
||||||
console.log(message.toObject())
|
|
||||||
this.emitError(Client, 'Invalid JOIN_ROOM message received: ' + message.toObject().toString());
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
const roomId = message.getRoomid();
|
const roomId = message.getRoomid();
|
||||||
|
|
||||||
if (Client.roomId === roomId) {
|
if (client.roomId === roomId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//leave previous room
|
//leave previous room
|
||||||
//this.leaveRoom(Client); // Useless now, there is only one room per connection
|
//this.leaveRoom(Client); // Useless now, there is only one room per connection
|
||||||
|
|
||||||
//join new previous room
|
//join new previous room
|
||||||
const world = this.joinRoom(Client, roomId, ProtobufUtils.toPointInterface(message.getPosition() as PositionMessage));
|
const gameRoom = await this.joinRoom(client, roomId, ProtobufUtils.toPointInterface(message.getPosition() as PositionMessage));
|
||||||
|
|
||||||
const things = world.setViewport(Client, (message.getViewport() as ViewportMessage).toObject());
|
const things = gameRoom.setViewport(client, (message.getViewport() as ViewportMessage).toObject());
|
||||||
|
|
||||||
const roomJoinedMessage = new RoomJoinedMessage();
|
const roomJoinedMessage = new RoomJoinedMessage();
|
||||||
|
|
||||||
@ -382,7 +350,7 @@ export class IoSocketController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [itemId, item] of world.getItemsState().entries()) {
|
for (const [itemId, item] of gameRoom.getItemsState().entries()) {
|
||||||
const itemStateMessage = new ItemStateMessage();
|
const itemStateMessage = new ItemStateMessage();
|
||||||
itemStateMessage.setItemid(itemId);
|
itemStateMessage.setItemid(itemId);
|
||||||
itemStateMessage.setStatejson(JSON.stringify(item));
|
itemStateMessage.setStatejson(JSON.stringify(item));
|
||||||
@ -393,8 +361,8 @@ export class IoSocketController {
|
|||||||
const serverToClientMessage = new ServerToClientMessage();
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
||||||
|
|
||||||
if (!Client.disconnecting) {
|
if (!client.disconnecting) {
|
||||||
Client.send(serverToClientMessage.serializeBinary().buffer, true);
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('An error occurred on "join_room" event');
|
console.error('An error occurred on "join_room" event');
|
||||||
@ -600,7 +568,7 @@ export class IoSocketController {
|
|||||||
if(Client.roomId){
|
if(Client.roomId){
|
||||||
try {
|
try {
|
||||||
//user leave previous world
|
//user leave previous world
|
||||||
const world: World | undefined = this.Worlds.get(Client.roomId);
|
const world: GameRoom | undefined = this.Worlds.get(Client.roomId);
|
||||||
if (world) {
|
if (world) {
|
||||||
world.leave(Client);
|
world.leave(Client);
|
||||||
if (world.isEmpty()) {
|
if (world.isEmpty()) {
|
||||||
@ -616,17 +584,17 @@ export class IoSocketController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private joinRoom(Client : ExSocketInterface, roomId: string, position: PointInterface): World {
|
private joinRoom(client : ExSocketInterface, roomId: string, position: PointInterface): GameRoom {
|
||||||
|
|
||||||
//join user in room
|
//join user in room
|
||||||
//Client.join(roomId);
|
|
||||||
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
||||||
Client.roomId = roomId;
|
client.roomId = roomId;
|
||||||
Client.position = position;
|
client.position = position;
|
||||||
|
|
||||||
//check and create new world for a room
|
//check and create new world for a room
|
||||||
let world = this.Worlds.get(roomId)
|
let world = this.Worlds.get(roomId)
|
||||||
if(world === undefined){
|
if(world === undefined){
|
||||||
world = new World((user1: User, group: Group) => {
|
world = new GameRoom((user1: User, group: Group) => {
|
||||||
this.joinWebRtcRoom(user1, group);
|
this.joinWebRtcRoom(user1, group);
|
||||||
}, (user1: User, group: Group) => {
|
}, (user1: User, group: Group) => {
|
||||||
this.disConnectedUser(user1, group);
|
this.disConnectedUser(user1, group);
|
||||||
@ -689,10 +657,10 @@ export class IoSocketController {
|
|||||||
|
|
||||||
// Dispatch groups position to newly connected user
|
// Dispatch groups position to newly connected user
|
||||||
world.getGroups().forEach((group: Group) => {
|
world.getGroups().forEach((group: Group) => {
|
||||||
this.emitCreateUpdateGroupEvent(Client, group);
|
this.emitCreateUpdateGroupEvent(client, group);
|
||||||
});
|
});
|
||||||
//join world
|
//join world
|
||||||
world.join(Client, Client.position);
|
world.join(client, client.position);
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,7 +850,7 @@ export class IoSocketController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWorlds(): Map<string, World> {
|
public getWorlds(): Map<string, GameRoom> {
|
||||||
return this.Worlds;
|
return this.Worlds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import {MessageUserPosition, Point} from "./Websocket/MessageUserPosition";
|
|
||||||
import {PointInterface} from "./Websocket/PointInterface";
|
import {PointInterface} from "./Websocket/PointInterface";
|
||||||
import {Group} from "./Group";
|
import {Group} from "./Group";
|
||||||
import {Distance} from "./Distance";
|
|
||||||
import {User} from "./User";
|
import {User} from "./User";
|
||||||
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
import {PositionInterface} from "_Model/PositionInterface";
|
import {PositionInterface} from "_Model/PositionInterface";
|
||||||
import {Identificable} from "_Model/Websocket/Identificable";
|
import {Identificable} from "_Model/Websocket/Identificable";
|
||||||
import {EntersCallback, LeavesCallback, MovesCallback, Zone} from "_Model/Zone";
|
import {EntersCallback, LeavesCallback, MovesCallback} from "_Model/Zone";
|
||||||
import {PositionNotifier} from "./PositionNotifier";
|
import {PositionNotifier} from "./PositionNotifier";
|
||||||
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||||
import {Movable} from "_Model/Movable";
|
import {Movable} from "_Model/Movable";
|
||||||
@ -14,7 +12,7 @@ import {Movable} from "_Model/Movable";
|
|||||||
export type ConnectCallback = (user: User, group: Group) => void;
|
export type ConnectCallback = (user: User, group: Group) => void;
|
||||||
export type DisconnectCallback = (user: User, group: Group) => void;
|
export type DisconnectCallback = (user: User, group: Group) => void;
|
||||||
|
|
||||||
export class World {
|
export class GameRoom {
|
||||||
private readonly minDistance: number;
|
private readonly minDistance: number;
|
||||||
private readonly groupRadius: number;
|
private readonly groupRadius: number;
|
||||||
|
|
||||||
@ -123,7 +121,7 @@ export class World {
|
|||||||
} else {
|
} else {
|
||||||
// If the user is part of a group:
|
// If the user is part of a group:
|
||||||
// should he leave the group?
|
// should he leave the group?
|
||||||
const distance = World.computeDistanceBetweenPositions(user.getPosition(), user.group.getPosition());
|
const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), user.group.getPosition());
|
||||||
if (distance > this.groupRadius) {
|
if (distance > this.groupRadius) {
|
||||||
this.leaveGroup(user);
|
this.leaveGroup(user);
|
||||||
}
|
}
|
||||||
@ -199,53 +197,19 @@ export class World {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const distance = World.computeDistance(user, currentUser); // compute distance between peers.
|
const distance = GameRoom.computeDistance(user, currentUser); // compute distance between peers.
|
||||||
|
|
||||||
if(distance <= minimumDistanceFound && distance <= this.minDistance) {
|
if(distance <= minimumDistanceFound && distance <= this.minDistance) {
|
||||||
minimumDistanceFound = distance;
|
minimumDistanceFound = distance;
|
||||||
matchingItem = currentUser;
|
matchingItem = currentUser;
|
||||||
}
|
}
|
||||||
/*if (typeof currentUser.group === 'undefined' || !currentUser.group.isFull()) {
|
|
||||||
// We found a user we can bind to.
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
/*
|
|
||||||
if(context.groups.length > 0) {
|
|
||||||
|
|
||||||
context.groups.forEach(group => {
|
|
||||||
if(group.isPartOfGroup(userPosition)) { // Is the user in a group ?
|
|
||||||
if(group.isStillIn(userPosition)) { // Is the user leaving the group ? (is the user at more than max distance of each player)
|
|
||||||
|
|
||||||
// Should we split the group? (is each player reachable from the current player?)
|
|
||||||
// This is needed if
|
|
||||||
// A <==> B <==> C <===> D
|
|
||||||
// becomes A <==> B <=====> C <> D
|
|
||||||
// If C moves right, the distance between B and C is too great and we must form 2 groups
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the user is in no group
|
|
||||||
// Is there someone in a group close enough and with room in the group ?
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Aucun groupe n'existe donc je stock les users assez proches de moi
|
|
||||||
let dist: Distance = {
|
|
||||||
distance: distance,
|
|
||||||
first: userPosition,
|
|
||||||
second: user // TODO: convertir en messageUserPosition
|
|
||||||
}
|
|
||||||
usersToBeGroupedWith.push(dist);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.groups.forEach((group: Group) => {
|
this.groups.forEach((group: Group) => {
|
||||||
if (group.isFull()) {
|
if (group.isFull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const distance = World.computeDistanceBetweenPositions(user.getPosition(), group.getPosition());
|
const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), group.getPosition());
|
||||||
if(distance <= minimumDistanceFound && distance <= this.groupRadius) {
|
if(distance <= minimumDistanceFound && distance <= this.groupRadius) {
|
||||||
minimumDistanceFound = distance;
|
minimumDistanceFound = distance;
|
||||||
matchingItem = group;
|
matchingItem = group;
|
||||||
@ -275,66 +239,7 @@ export class World {
|
|||||||
return this.itemsState;
|
return this.itemsState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*getDistancesBetweenGroupUsers(group: Group): Distance[]
|
|
||||||
{
|
|
||||||
let i = 0;
|
|
||||||
let users = group.getUsers();
|
|
||||||
let distances: Distance[] = [];
|
|
||||||
users.forEach(function(user1, key1) {
|
|
||||||
users.forEach(function(user2, key2) {
|
|
||||||
if(key1 < key2) {
|
|
||||||
distances[i] = {
|
|
||||||
distance: World.computeDistance(user1, user2),
|
|
||||||
first: user1,
|
|
||||||
second: user2
|
|
||||||
};
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
distances.sort(World.compareDistances);
|
|
||||||
|
|
||||||
return distances;
|
|
||||||
}
|
|
||||||
|
|
||||||
filterGroup(distances: Distance[], group: Group): void
|
|
||||||
{
|
|
||||||
let users = group.getUsers();
|
|
||||||
let usersToRemove = false;
|
|
||||||
let groupTmp: MessageUserPosition[] = [];
|
|
||||||
distances.forEach(dist => {
|
|
||||||
if(dist.distance <= World.MIN_DISTANCE) {
|
|
||||||
let users = [dist.first];
|
|
||||||
let usersbis = [dist.second]
|
|
||||||
groupTmp.push(dist.first);
|
|
||||||
groupTmp.push(dist.second);
|
|
||||||
} else {
|
|
||||||
usersToRemove = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(usersToRemove) {
|
|
||||||
// Detecte le ou les users qui se sont fait sortir du groupe
|
|
||||||
let difference = users.filter(x => !groupTmp.includes(x));
|
|
||||||
|
|
||||||
// TODO : Notify users un difference that they have left the group
|
|
||||||
}
|
|
||||||
|
|
||||||
let newgroup = new Group(groupTmp);
|
|
||||||
this.groups.push(newgroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static compareDistances(distA: Distance, distB: Distance): number
|
|
||||||
{
|
|
||||||
if (distA.distance < distB.distance) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (distA.distance > distB.distance) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
setViewport(socket : Identificable, viewport: ViewportInterface): Movable[] {
|
setViewport(socket : Identificable, viewport: ViewportInterface): Movable[] {
|
||||||
const user = this.users.get(socket.userId);
|
const user = this.users.get(socket.userId);
|
||||||
if(typeof user === 'undefined') {
|
if(typeof user === 'undefined') {
|
@ -1,7 +1,6 @@
|
|||||||
import { World, ConnectCallback, DisconnectCallback } from "./World";
|
import { ConnectCallback, DisconnectCallback } from "./GameRoom";
|
||||||
import { User } from "./User";
|
import { User } from "./User";
|
||||||
import {PositionInterface} from "_Model/PositionInterface";
|
import {PositionInterface} from "_Model/PositionInterface";
|
||||||
import {uuid} from "uuidv4";
|
|
||||||
import {Movable} from "_Model/Movable";
|
import {Movable} from "_Model/Movable";
|
||||||
import {PositionNotifier} from "_Model/PositionNotifier";
|
import {PositionNotifier} from "_Model/PositionNotifier";
|
||||||
|
|
||||||
|
36
back/src/Services/AdminApi.ts
Normal file
36
back/src/Services/AdminApi.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
|
import Axios from "axios";
|
||||||
|
|
||||||
|
export interface AdminApiData {
|
||||||
|
organizationSlug: string
|
||||||
|
worldSlug: string
|
||||||
|
roomSlug: string
|
||||||
|
mapUrlStart: string
|
||||||
|
userUuid: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdminApi {
|
||||||
|
|
||||||
|
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
||||||
|
if (!ADMIN_API_URL) {
|
||||||
|
return Promise.reject('No admin backoffice set!');
|
||||||
|
}
|
||||||
|
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
||||||
|
const res = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken,
|
||||||
|
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
||||||
|
)
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async memberIsGrantedAccessToRoom(memberId: string, roomId: string): Promise<boolean> {
|
||||||
|
if (!ADMIN_API_URL) {
|
||||||
|
return Promise.reject('No admin backoffice set!');
|
||||||
|
}
|
||||||
|
const res = await Axios.get(ADMIN_API_URL+'/api/member/'+memberId+'/is-granted-access/'+roomId,
|
||||||
|
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
||||||
|
)
|
||||||
|
return res.data === true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const adminApi = new AdminApi();
|
@ -1,5 +1,5 @@
|
|||||||
import "jasmine";
|
import "jasmine";
|
||||||
import {World, ConnectCallback, DisconnectCallback } from "../src/Model/World";
|
import {GameRoom, ConnectCallback, DisconnectCallback } from "_Model/GameRoom";
|
||||||
import {Point} from "../src/Model/Websocket/MessageUserPosition";
|
import {Point} from "../src/Model/Websocket/MessageUserPosition";
|
||||||
import { Group } from "../src/Model/Group";
|
import { Group } from "../src/Model/Group";
|
||||||
import {PositionNotifier} from "../src/Model/PositionNotifier";
|
import {PositionNotifier} from "../src/Model/PositionNotifier";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "jasmine";
|
import "jasmine";
|
||||||
import {World, ConnectCallback, DisconnectCallback } from "../src/Model/World";
|
import {GameRoom, ConnectCallback, DisconnectCallback } from "_Model/GameRoom";
|
||||||
import {Point} from "../src/Model/Websocket/MessageUserPosition";
|
import {Point} from "../src/Model/Websocket/MessageUserPosition";
|
||||||
import { Group } from "../src/Model/Group";
|
import { Group } from "../src/Model/Group";
|
||||||
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
@ -21,7 +21,7 @@ describe("World", () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
const world = new GameRoom(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
||||||
|
|
||||||
world.join(createMockUser(1), new Point(100, 100));
|
world.join(createMockUser(1), new Point(100, 100));
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ describe("World", () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
const world = new GameRoom(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
||||||
|
|
||||||
world.join(createMockUser(1), new Point(100, 100));
|
world.join(createMockUser(1), new Point(100, 100));
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ describe("World", () => {
|
|||||||
disconnectCallNumber++;
|
disconnectCallNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
const world = new GameRoom(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
|
||||||
|
|
||||||
world.join(createMockUser(1), new Point(100, 100));
|
world.join(createMockUser(1), new Point(100, 100));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user