Merge branch 'develop' into usersLimit
# Conflicts: # back/src/Controller/IoSocketController.ts # front/src/Connexion/RoomConnection.ts # front/src/Phaser/Game/GameScene.ts
This commit is contained in:
commit
3c0bd9da6c
37 changed files with 1022 additions and 366 deletions
|
@ -20,9 +20,9 @@ import {parse} from "query-string";
|
|||
import {jwtTokenManager} from "../Services/JWTTokenManager";
|
||||
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
||||
import {SocketManager, socketManager} from "../Services/SocketManager";
|
||||
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
||||
import {emitInBatch} from "../Services/IoSocketHelpers";
|
||||
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
||||
import {ADMIN_API_TOKEN, MAX_USERS_PER_ROOM} from "../Enum/EnvironmentVariable";
|
||||
import {ADMIN_API_TOKEN, MAX_USERS_PER_ROOM, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
|
||||
|
||||
export class IoSocketController {
|
||||
private nextUserId: number = 1;
|
||||
|
@ -43,6 +43,7 @@ export class IoSocketController {
|
|||
if (token !== ADMIN_API_TOKEN) {
|
||||
console.log('Admin access refused for token: '+token)
|
||||
res.writeStatus("401 Unauthorized").end('Incorrect token');
|
||||
return;
|
||||
}
|
||||
const roomId = query.roomId as string;
|
||||
|
||||
|
@ -110,6 +111,7 @@ export class IoSocketController {
|
|||
this.app.ws('/room', {
|
||||
/* Options */
|
||||
//compression: uWS.SHARED_COMPRESSOR,
|
||||
idleTimeout: SOCKET_IDLE_TIMER,
|
||||
maxPayloadLength: 16 * 1024 * 1024,
|
||||
maxBackpressure: 65536, // Maximum 64kB of data in the buffer.
|
||||
//idleTimeout: 10,
|
||||
|
@ -164,23 +166,24 @@ export class IoSocketController {
|
|||
let memberTextures: CharacterTexture[] = [];
|
||||
|
||||
const room = await socketManager.getOrCreateRoom(roomId);
|
||||
//TODO http return status
|
||||
/*if (room.isFull) {
|
||||
if(room.isFull){
|
||||
throw new Error('Room is full');
|
||||
}*/
|
||||
|
||||
try {
|
||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||
//console.log('USERDATA', userData)
|
||||
memberTags = userData.tags;
|
||||
memberTextures = userData.textures;
|
||||
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
||||
throw new Error('No correct tags')
|
||||
}
|
||||
if (ADMIN_API_URL) {
|
||||
try {
|
||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||
//console.log('USERDATA', userData)
|
||||
memberTags = userData.tags;
|
||||
memberTextures = userData.textures;
|
||||
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
||||
throw new Error('No correct tags')
|
||||
}
|
||||
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
||||
} catch (e) {
|
||||
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
||||
console.error(e);
|
||||
throw new Error('Client cannot acces this ressource.')
|
||||
}
|
||||
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
||||
} catch (e) {
|
||||
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
||||
throw new Error('Client cannot acces this ressource.')
|
||||
}
|
||||
|
||||
// Generate characterLayers objects from characterLayers string[]
|
||||
|
@ -236,21 +239,19 @@ export class IoSocketController {
|
|||
},
|
||||
/* Handlers */
|
||||
open: (ws) => {
|
||||
(async () => {
|
||||
// Let's join the room
|
||||
const client = this.initClient(ws); //todo: into the upgrade instead?
|
||||
// Let's join the room
|
||||
const client = this.initClient(ws); //todo: into the upgrade instead?
|
||||
const room = socketManager.getRoomById(client.roomId);
|
||||
|
||||
const room = socketManager.getRoomById(client.roomId);
|
||||
if (room && room.isFull) {
|
||||
socketManager.emitCloseMessage(client, 302);
|
||||
}else {
|
||||
socketManager.handleJoinRoom(client);
|
||||
resetPing(client);
|
||||
}
|
||||
if (room && room.isFull) {
|
||||
socketManager.emitCloseMessage(client, 302);
|
||||
}else {
|
||||
socketManager.handleJoinRoom(client);
|
||||
}
|
||||
|
||||
//get data information and shwo messages
|
||||
try {
|
||||
const res: FetchMemberDataByUuidResponse = await adminApi.fetchMemberDataByUuid(client.userUuid);
|
||||
//get data information and show messages
|
||||
if (ADMIN_API_URL) {
|
||||
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
||||
if (!res.messages) {
|
||||
return;
|
||||
}
|
||||
|
@ -262,10 +263,10 @@ export class IoSocketController {
|
|||
message: messageToSend.message
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
}).catch((err) => {
|
||||
console.error('fetchMemberDataByUuid => err', err);
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
},
|
||||
message: (ws, arrayBuffer, isBinary): void => {
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import {BaseController} from "./BaseController";
|
|||
import {parse} from "query-string";
|
||||
import {adminApi} from "../Services/AdminApi";
|
||||
|
||||
//todo: delete this
|
||||
|
||||
export class MapController extends BaseController{
|
||||
|
||||
constructor(private App : TemplatedApp) {
|
||||
|
@ -34,18 +34,21 @@ export class MapController extends BaseController{
|
|||
res.writeStatus("400 Bad request");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected organizationSlug parameter");
|
||||
return;
|
||||
}
|
||||
if (typeof query.worldSlug !== 'string') {
|
||||
console.error('Expected worldSlug parameter');
|
||||
res.writeStatus("400 Bad request");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected worldSlug parameter");
|
||||
return;
|
||||
}
|
||||
if (typeof query.roomSlug !== 'string' && query.roomSlug !== undefined) {
|
||||
console.error('Expected only one roomSlug parameter');
|
||||
res.writeStatus("400 Bad request");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected only one roomSlug parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
|
|
|
@ -3,13 +3,14 @@ const URL_ROOM_STARTED = "/Floor0/floor0.json";
|
|||
const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64;
|
||||
const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48;
|
||||
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == 'true' : false;
|
||||
const ADMIN_API_URL = process.env.ADMIN_API_URL || 'http://admin';
|
||||
const ADMIN_API_URL = process.env.ADMIN_API_URL || '';
|
||||
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || 'myapitoken';
|
||||
const MAX_USERS_PER_ROOM = parseInt(process.env.MAX_USERS_PER_ROOM || '') || 600;
|
||||
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
||||
const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined : process.env.JITSI_URL;
|
||||
const JITSI_ISS = process.env.JITSI_ISS || '';
|
||||
const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || '';
|
||||
export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 30; // maximum time (in second) without activity before a socket is closed
|
||||
|
||||
export {
|
||||
SECRET_KEY,
|
||||
|
|
|
@ -25,7 +25,6 @@ export interface ExSocketInterface extends WebSocket, Identificable {
|
|||
emitInBatch: (payload: SubMessage) => void;
|
||||
batchedMessages: BatchMessage;
|
||||
batchTimeout: NodeJS.Timeout|null;
|
||||
pingTimeout: NodeJS.Timeout|null;
|
||||
disconnecting: boolean,
|
||||
tags: string[],
|
||||
textures: CharacterTexture[],
|
||||
|
|
|
@ -6,8 +6,13 @@ class GaugeManager {
|
|||
private nbClientsPerRoomGauge: Gauge<string>;
|
||||
private nbGroupsPerRoomGauge: Gauge<string>;
|
||||
private nbGroupsPerRoomCounter: Counter<string>;
|
||||
private nbRoomsGauge: Gauge<string>;
|
||||
|
||||
constructor() {
|
||||
this.nbRoomsGauge = new Gauge({
|
||||
name: 'workadventure_nb_rooms',
|
||||
help: 'Number of active rooms'
|
||||
});
|
||||
this.nbClientsGauge = new Gauge({
|
||||
name: 'workadventure_nb_sockets',
|
||||
help: 'Number of connected sockets',
|
||||
|
@ -31,6 +36,13 @@ class GaugeManager {
|
|||
});
|
||||
}
|
||||
|
||||
incNbRoomGauge(): void {
|
||||
this.nbRoomsGauge.inc();
|
||||
}
|
||||
decNbRoomGauge(): void {
|
||||
this.nbRoomsGauge.dec();
|
||||
}
|
||||
|
||||
incNbClientPerRoomGauge(roomId: string): void {
|
||||
this.nbClientsGauge.inc();
|
||||
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
||||
|
|
|
@ -18,22 +18,6 @@ export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): voi
|
|||
socket.batchTimeout = null;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// If we send a message, we don't need to keep the connection alive
|
||||
resetPing(socket);
|
||||
}
|
||||
|
||||
export function resetPing(ws: ExSocketInterface): void {
|
||||
if (ws.pingTimeout) {
|
||||
clearTimeout(ws.pingTimeout);
|
||||
}
|
||||
ws.pingTimeout = setTimeout(() => {
|
||||
if (ws.disconnecting) {
|
||||
return;
|
||||
}
|
||||
ws.ping();
|
||||
resetPing(ws);
|
||||
}, 29000);
|
||||
}
|
||||
|
||||
export function emitError(Client: ExSocketInterface, message: string): void {
|
||||
|
@ -47,4 +31,5 @@ export function emitError(Client: ExSocketInterface, message: string): void {
|
|||
Client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||
}
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {ALLOW_ARTILLERY, SECRET_KEY} from "../Enum/EnvironmentVariable";
|
||||
import {ADMIN_API_URL, ALLOW_ARTILLERY, SECRET_KEY} from "../Enum/EnvironmentVariable";
|
||||
import {uuid} from "uuidv4";
|
||||
import Jwt from "jsonwebtoken";
|
||||
import {TokenInterface} from "../Controller/AuthenticateController";
|
||||
import {adminApi, AdminApiData} from "../Services/AdminApi";
|
||||
|
||||
class JWTTokenManager {
|
||||
|
||||
|
||||
public createJWTToken(userUuid: string) {
|
||||
return Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '200d'}); //todo: add a mechanic to refresh or recreate token
|
||||
}
|
||||
|
@ -48,17 +48,21 @@ class JWTTokenManager {
|
|||
return;
|
||||
}
|
||||
|
||||
//verify user in admin
|
||||
adminApi.fetchCheckUserByToken(tokenInterface.userUuid).then(() => {
|
||||
resolve(tokenInterface.userUuid);
|
||||
}).catch((err) => {
|
||||
//anonymous user
|
||||
if(err.response && err.response.status && err.response.status === 404){
|
||||
if (ADMIN_API_URL) {
|
||||
//verify user in admin
|
||||
adminApi.fetchCheckUserByToken(tokenInterface.userUuid).then(() => {
|
||||
resolve(tokenInterface.userUuid);
|
||||
return;
|
||||
}
|
||||
reject(new Error('Authentication error, invalid token structure. ' + err));
|
||||
});
|
||||
}).catch((err) => {
|
||||
//anonymous user
|
||||
if(err.response && err.response.status && err.response.status === 404){
|
||||
resolve(tokenInterface.userUuid);
|
||||
return;
|
||||
}
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
resolve(tokenInterface.userUuid);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -66,7 +70,7 @@ class JWTTokenManager {
|
|||
private isValidToken(token: object): token is TokenInterface {
|
||||
return !(typeof((token as TokenInterface).userUuid) !== 'string');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const jwtTokenManager = new JWTTokenManager();
|
||||
export const jwtTokenManager = new JWTTokenManager();
|
||||
|
|
|
@ -353,6 +353,7 @@ export class SocketManager {
|
|||
world.leave(Client);
|
||||
if (world.isEmpty()) {
|
||||
this.Worlds.delete(Client.roomId);
|
||||
gaugeManager.decNbRoomGauge();
|
||||
}
|
||||
}
|
||||
//user leave previous room
|
||||
|
@ -385,6 +386,7 @@ export class SocketManager {
|
|||
world.tags = data.tags
|
||||
world.policyType = Number(data.policy_type)
|
||||
}
|
||||
gaugeManager.incNbRoomGauge();
|
||||
this.Worlds.set(roomId, world);
|
||||
}
|
||||
return Promise.resolve(world)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue