improvments

This commit is contained in:
arp 2020-09-28 15:02:37 +02:00
parent af4611ed29
commit 3f9659ef3c
10 changed files with 72 additions and 71 deletions

View file

@ -7,7 +7,6 @@ import bodyParser = require('body-parser');
import * as http from "http"; import * as http from "http";
import {MapController} from "./Controller/MapController"; import {MapController} from "./Controller/MapController";
import {PrometheusController} from "./Controller/PrometheusController"; import {PrometheusController} from "./Controller/PrometheusController";
import {AdminController} from "./Controller/AdminController";
import {DebugController} from "./Controller/DebugController"; import {DebugController} from "./Controller/DebugController";
class App { class App {
@ -17,7 +16,6 @@ class App {
public authenticateController: AuthenticateController; public authenticateController: AuthenticateController;
public mapController: MapController; public mapController: MapController;
public prometheusController: PrometheusController; public prometheusController: PrometheusController;
private adminController: AdminController;
private debugController: DebugController; private debugController: DebugController;
constructor() { constructor() {
@ -36,7 +34,6 @@ class App {
this.authenticateController = new AuthenticateController(this.app); this.authenticateController = new AuthenticateController(this.app);
this.mapController = new MapController(this.app); this.mapController = new MapController(this.app);
this.prometheusController = new PrometheusController(this.app, this.ioSocketController); this.prometheusController = new PrometheusController(this.app, this.ioSocketController);
this.adminController = new AdminController(this.app);
this.debugController = new DebugController(this.app, this.ioSocketController); this.debugController = new DebugController(this.app, this.ioSocketController);
} }

View file

@ -6,7 +6,14 @@ import { uuid } from 'uuidv4';
import Axios from "axios"; import Axios from "axios";
export interface TokenInterface { export interface TokenInterface {
name: string, userUuid: string
}
interface AdminApiData {
organizationSlug: string
worldSlug: string
roomSlug: string
mapUrlStart: string
userUuid: string userUuid: string
} }
@ -35,20 +42,20 @@ export class AuthenticateController {
return res.status(401).send('No admin backoffice set!'); 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. //todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
const response = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken, const data = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken,
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} } { headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
); ).then((res): AdminApiData => res.data);
userUuid = response.data.userUuid; userUuid = data.userUuid;
mapUrlStart = response.data.mapUrlStart; mapUrlStart = data.mapUrlStart;
newUrl = this.getNewUrlOnAdminAuth(response.data) newUrl = this.getNewUrlOnAdminAuth(data)
} else { } else {
userUuid = uuid(); userUuid = uuid();
mapUrlStart= URL_ROOM_STARTED; mapUrlStart = req.headers.host?.replace('api.', 'maps.') + URL_ROOM_STARTED;
newUrl = null; newUrl = null;
} }
const authToken = Jwt.sign({userUuid: userUuid} as TokenInterface, SECRET_KEY, {expiresIn: '24h'}); const authToken = Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '24h'});
return res.status(OK).send({ return res.status(OK).send({
authToken, authToken,
userUuid, userUuid,
@ -64,7 +71,7 @@ export class AuthenticateController {
}); });
} }
getNewUrlOnAdminAuth(data:any): string { private getNewUrlOnAdminAuth(data:AdminApiData): string {
const organizationSlug = data.organizationSlug; const organizationSlug = data.organizationSlug;
const worldSlug = data.worldSlug; const worldSlug = data.worldSlug;
const roomSlug = data.roomSlug; const roomSlug = data.roomSlug;

View file

@ -121,18 +121,19 @@ export class IoSocketController {
return next(new Error('Authentication error')); return next(new Error('Authentication error'));
} }
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => { Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
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);
return next(new Error('Authentication error')); return next(new Error('Authentication error'));
} }
if (!this.isValidToken(tokenDecoded)) { if (!this.isValidToken(tokenInterface)) {
return next(new Error('Authentication error, invalid token structure')); return next(new Error('Authentication error, invalid token structure'));
} }
(socket as ExSocketInterface).token = socket.handshake.query.token; (socket as ExSocketInterface).token = socket.handshake.query.token;
(socket as ExSocketInterface).userId = this.nextUserId; (socket as ExSocketInterface).userId = this.nextUserId;
(socket as ExSocketInterface).userUuid = tokenDecoded.userUuid; (socket as ExSocketInterface).userUuid = tokenInterface.userUuid;
this.nextUserId++; this.nextUserId++;
next(); next();
}); });
@ -141,11 +142,8 @@ export class IoSocketController {
this.ioConnection(); this.ioConnection();
} }
private isValidToken(token: object): token is TokenInterface { private isValidToken(token: TokenInterface): boolean {
if (typeof((token as TokenInterface).userUuid) !== 'string') { if (typeof(token.userUuid) !== 'string') {
return false;
}
if (typeof((token as TokenInterface).name) !== 'string') {
return false; return false;
} }
return true; return true;

View file

@ -3,6 +3,7 @@ import {Application, Request, Response} from "express";
import {OK} from "http-status-codes"; import {OK} from "http-status-codes";
import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable";
//todo: delete this
export class MapController { export class MapController {
App: Application; App: Application;

View file

@ -1,7 +1,6 @@
import {Socket} from "socket.io"; import {Socket} from "socket.io";
import {PointInterface} from "./PointInterface"; import {PointInterface} from "./PointInterface";
import {Identificable} from "./Identificable"; import {Identificable} from "./Identificable";
import {TokenInterface} from "../../Controller/AuthenticateController";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage"; import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb"; import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";

View file

@ -2,51 +2,61 @@ import Axios from "axios";
import {API_URL} from "../Enum/EnvironmentVariable"; import {API_URL} from "../Enum/EnvironmentVariable";
import {RoomConnection} from "./RoomConnection"; import {RoomConnection} from "./RoomConnection";
interface LoginApiData {
authToken: string
userUuid: string
mapUrlStart: string
newUrl: string
}
class ConnectionManager { class ConnectionManager {
private initPromise: Promise<LoginApiData> = Promise.reject();
private mapUrlStart: string|null = null; private mapUrlStart: string|null = null;
private authToken:string|null = null; private authToken:string|null = null;
private userUuid: string|null = null; private userUuid: string|null = null;
private userName:string|null = null;
public async init(): Promise<void> { public async init(): Promise<void> {
const match = /\/register\/(.+)/.exec(window.location.toString()); const match = /\/register\/(.+)/.exec(window.location.toString());
const organizationMemberToken = match ? match[1] : null; const organizationMemberToken = match ? match[1] : null;
const res = await Axios.post(`${API_URL}/login`, {organizationMemberToken}); this.initPromise = Axios.post(`${API_URL}/login`, {organizationMemberToken}).then(res => res.data);
this.authToken = res.data.authToken; const data = await this.initPromise
this.userUuid = res.data.userUuid; this.authToken = data.authToken;
this.mapUrlStart = res.data.mapUrlStart; this.userUuid = data.userUuid;
const newUrl = res.data.newUrl; this.mapUrlStart = data.mapUrlStart;
const newUrl = data.newUrl;
if (newUrl) { if (newUrl) {
history.pushState({}, '', newUrl); history.pushState({}, '', newUrl);
} }
} }
public async setUserName(name:string): Promise<void> { public connectToRoomSocket(): Promise<RoomConnection> {
//todo return new Promise<RoomConnection>((resolve, reject) => {
const connection = new RoomConnection(this.authToken as string);
connection.onConnectError((error: object) => {
console.log('An error occurred while connecting to socket server. Retrying');
reject(error);
});
resolve(connection);
}).catch((err) => {
// Let's retry in 4-6 seconds
return new Promise<RoomConnection>((resolve, reject) => {
setTimeout(() => {
//todo: allow a way to break recurrsion?
this.connectToRoomSocket().then((connection) => resolve(connection));
}, 4000 + Math.floor(Math.random() * 2000) );
});
});
} }
public connectToRoomSocket(): Promise<RoomConnection> { public getMapUrlStart(): Promise<string> {
return Axios.post(`${API_URL}/connectToSocket`, {authToken: this.authToken}).then((res) => { return this.initPromise.then(() => {
return new Promise<RoomConnection>((resolve, reject) => { if (!this.mapUrlStart) {
const connection = new RoomConnection(res.data.roomToken); throw new Error('No map url set!');
connection.onConnectError((error: object) => { }
console.log('An error occurred while connecting to socket server. Retrying'); return this.mapUrlStart;
reject(error); })
});
resolve(connection);
});
})
.catch((err) => {
// Let's retry in 4-6 seconds
return new Promise<RoomConnection>((resolve, reject) => {
setTimeout(() => {
//todo: allow a way to break recurrsion?
this.connectToRoomSocket().then((connection) => resolve(connection));
}, 4000 + Math.floor(Math.random() * 2000) );
});
});
} }
} }

View file

@ -83,9 +83,9 @@ export class RoomConnection implements RoomConnection {
}) })
} }
public emitPlayerDetailsMessage(characterLayersSelected: string[]) { public emitPlayerDetailsMessage(userName: string, characterLayersSelected: string[]) {
const message = new SetPlayerDetailsMessage(); const message = new SetPlayerDetailsMessage();
message.setName(name); message.setName(userName);
message.setCharacterlayersList(characterLayersSelected); message.setCharacterlayersList(characterLayersSelected);
this.socket.emit(EventMessage.SET_PLAYER_DETAILS, message.serializeBinary().buffer, (id: number) => { this.socket.emit(EventMessage.SET_PLAYER_DETAILS, message.serializeBinary().buffer, (id: number) => {
this.userId = id; this.userId = id;

View file

@ -1,4 +1,4 @@
import {PointInterface} from "../../Connexion/Connection"; import {PointInterface} from "../../Connexion/ConnexionModels";
export interface AddPlayerInterface { export interface AddPlayerInterface {
userId: number; userId: number;

View file

@ -4,7 +4,7 @@ import {
} from "../../Connexion/ConnexionModels"; } from "../../Connexion/ConnexionModels";
import Axios from "axios"; import Axios from "axios";
import {API_URL} from "../../Enum/EnvironmentVariable"; import {API_URL} from "../../Enum/EnvironmentVariable";
import {adminDataFetchPromise} from "../../register"; import {connectionManager} from "../../Connexion/ConnectionManager";
export interface HasMovedEvent { export interface HasMovedEvent {
direction: string; direction: string;
@ -30,23 +30,12 @@ export class GameManager {
} }
loadStartMap() : Promise<StartMapInterface> { loadStartMap() : Promise<StartMapInterface> {
if (adminDataFetchPromise) { return connectionManager.getMapUrlStart().then(mapUrlStart => {
return adminDataFetchPromise.then(data => { return {
return { mapUrlStart: mapUrlStart,
mapUrlStart: data.mapUrlStart, startInstance: "global", //todo: is this property still usefull?
startInstance: data.startInstance, }
} });
})
} else {
//todo: remove this call, merge with the admin workflow?
return Axios.get(`${API_URL}/start-map`)
.then((res) => {
return res.data;
}).catch((err) => {
console.error(err);
throw err;
});
}
} }
getPlayerName(): string { getPlayerName(): string {

View file

@ -205,8 +205,8 @@ export class GameScene extends Phaser.Scene implements CenterListener {
this.connectionPromise = connectionManager.connectToRoomSocket().then((connection : RoomConnection) => { this.connectionPromise = connectionManager.connectToRoomSocket().then((connection : RoomConnection) => {
this.connection = connection; this.connection = connection;
this.connection.emitPlayerDetailsMessage(gameManager.getCharacterSelected()) this.connection.emitPlayerDetailsMessage(gameManager.getPlayerName(), gameManager.getCharacterSelected())
connection.onUserJoins((message: MessageUserJoined) => { connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = { const userMessage: AddPlayerInterface = {