Merge pull request #284 from thecodingmachine/uws

Migrating to uWS
This commit is contained in:
David Négrier 2020-09-30 14:51:36 +02:00 committed by GitHub
commit e42f1a6a21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1441 additions and 1355 deletions

View file

@ -38,27 +38,27 @@
"dependencies": {
"axios": "^0.20.0",
"body-parser": "^1.19.0",
"busboy": "^0.3.1",
"circular-json": "^0.5.9",
"express": "^4.17.1",
"generic-type-guard": "^3.2.0",
"google-protobuf": "^3.13.0",
"http-status-codes": "^1.4.0",
"iterall": "^1.3.0",
"jsonwebtoken": "^8.5.1",
"prom-client": "^12.0.0",
"socket.io": "^2.3.0",
"query-string": "^6.13.3",
"systeminformation": "^4.26.5",
"ts-node-dev": "^1.0.0-pre.44",
"typescript": "^3.8.3",
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
"uuidv4": "^6.0.7"
},
"devDependencies": {
"@types/circular-json": "^0.4.0",
"@types/express": "^4.17.4",
"@types/google-protobuf": "^3.7.3",
"@types/http-status-codes": "^1.2.0",
"@types/jasmine": "^3.5.10",
"@types/jsonwebtoken": "^8.3.8",
"@types/socket.io": "^2.1.4",
"@types/uuidv4": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^2.26.0",
"@typescript-eslint/parser": "^2.26.0",

View file

@ -1,3 +1,3 @@
// lib/server.ts
import App from "./src/App";
App.listen(8080, () => console.log(`Example app listening on port 8080!`))
App.listen(8080, () => console.log(`WorkAdventure starting on port 8080!`))

View file

@ -1,17 +1,13 @@
// lib/app.ts
import {IoSocketController} from "./Controller/IoSocketController"; //TODO fix import by "_Controller/..."
import {AuthenticateController} from "./Controller/AuthenticateController"; //TODO fix import by "_Controller/..."
import express from "express";
import {Application, Request, Response} from 'express';
import bodyParser = require('body-parser');
import * as http from "http";
import {MapController} from "./Controller/MapController";
import {PrometheusController} from "./Controller/PrometheusController";
import {DebugController} from "./Controller/DebugController";
import {App as uwsApp} from "./Server/sifrr.server";
class App {
public app: Application;
public server: http.Server;
public app: uwsApp;
public ioSocketController: IoSocketController;
public authenticateController: AuthenticateController;
public mapController: MapController;
@ -19,40 +15,15 @@ class App {
private debugController: DebugController;
constructor() {
this.app = express();
//config server http
this.server = http.createServer(this.app);
this.config();
this.crossOrigin();
//TODO add middleware with access token to secure api
this.app = new uwsApp();
//create socket controllers
this.ioSocketController = new IoSocketController(this.server);
this.ioSocketController = new IoSocketController(this.app);
this.authenticateController = new AuthenticateController(this.app);
this.mapController = new MapController(this.app);
this.prometheusController = new PrometheusController(this.app, this.ioSocketController);
this.debugController = new DebugController(this.app, this.ioSocketController);
}
// TODO add session user
private config(): void {
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({extended: false}));
}
private crossOrigin(){
this.app.use((req: Request, res: Response, next) => {
res.setHeader("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
}
}
export default new App().server;
export default new App().app;

View file

@ -1,8 +1,8 @@
import {Application, Request, Response} from "express";
import Jwt from "jsonwebtoken";
import {OK} from "http-status-codes";
import {ADMIN_API_TOKEN, ADMIN_API_URL, SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
import { uuid } from 'uuidv4';
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {BaseController} from "./BaseController";
import Axios from "axios";
export interface TokenInterface {
@ -17,60 +17,75 @@ interface AdminApiData {
userUuid: string
}
export class AuthenticateController {
App : Application;
export class AuthenticateController extends BaseController {
constructor(App : Application) {
this.App = App;
constructor(private App : TemplatedApp) {
super();
this.login();
}
//permit to login on application. Return token to connect on Websocket IO.
login(){
// For now, let's completely forget the /login route.
this.App.post("/login", async (req: Request, res: Response) => {
//todo: what to do if the organizationMemberToken is already used?
const organizationMemberToken:string|null = req.body.organizationMemberToken;
try {
let userUuid;
let mapUrlStart;
let newUrl = null;
if (organizationMemberToken) {
if (!ADMIN_API_URL) {
return res.status(401).send('No admin backoffice set!');
this.App.options("/login", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.end();
});
this.App.post("/login", (res: HttpResponse, req: HttpRequest) => {
(async () => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('Login request was aborted');
})
const host = req.getHeader('host');
const param = await res.json();
//todo: what to do if the organizationMemberToken is already used?
const organizationMemberToken:string|null = param.organizationMemberToken;
try {
let userUuid;
let mapUrlStart;
let newUrl = null;
if (organizationMemberToken) {
if (!ADMIN_API_URL) {
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;
mapUrlStart = data.mapUrlStart;
newUrl = this.getNewUrlOnAdminAuth(data)
} else {
userUuid = uuid();
mapUrlStart = host.replace('api.', 'maps.') + URL_ROOM_STARTED;
newUrl = null;
}
//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;
mapUrlStart = data.mapUrlStart;
newUrl = this.getNewUrlOnAdminAuth(data)
} else {
userUuid = uuid();
mapUrlStart = req.headers.host?.replace('api.', 'maps.') + URL_ROOM_STARTED;
newUrl = null;
const authToken = Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '24h'});
res.writeStatus("200 OK").end(JSON.stringify({
authToken,
userUuid,
mapUrlStart,
newUrl,
}));
} catch (e) {
console.log("An error happened", e)
res.writeStatus(e.status || "500 Internal Server Error").end('An error happened');
}
const authToken = Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '24h'});
return res.status(OK).send({
authToken,
userUuid,
mapUrlStart,
newUrl,
});
} catch (e) {
console.log(e.message)
return res.status(e.status || 500).send('An error happened');
}
})();
});
}
private getNewUrlOnAdminAuth(data:AdminApiData): string {
const organizationSlug = data.organizationSlug;
const worldSlug = data.worldSlug;

View file

@ -0,0 +1,10 @@
import {HttpResponse} from "uWebSockets.js";
export class BaseController {
protected addCorsHeaders(res: HttpResponse): void {
res.writeHeader('access-control-allow-headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.writeHeader('access-control-allow-methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.writeHeader('access-control-allow-origin', '*');
}
}

View file

@ -1,22 +1,25 @@
import {Application, Request, Response} from "express";
import {OK} from "http-status-codes";
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
import {IoSocketController} from "_Controller/IoSocketController";
import {stringify} from "circular-json";
import {HttpRequest, HttpResponse} from "uWebSockets.js";
import { parse } from 'query-string';
import {App} from "../Server/sifrr.server";
export class DebugController {
constructor(private App : Application, private ioSocketController: IoSocketController) {
constructor(private App : App, private ioSocketController: IoSocketController) {
this.getDump();
}
getDump(){
this.App.get("/dump", (req: Request, res: Response) => {
if (req.query.token !== ADMIN_API_TOKEN) {
this.App.get("/dump", (res: HttpResponse, req: HttpRequest) => {
const query = parse(req.getQuery());
if (query.token !== ADMIN_API_TOKEN) {
return res.status(401).send('Invalid token sent!');
}
return res.status(OK).contentType('application/json').send(stringify(
return res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(stringify(
this.ioSocketController.getWorlds(),
(key: unknown, value: unknown) => {
if(value instanceof Map) {

File diff suppressed because it is too large Load diff

View file

@ -1,30 +1,34 @@
import express from "express";
import {Application, Request, Response} from "express";
import {OK} from "http-status-codes";
import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable";
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {BaseController} from "./BaseController";
//todo: delete this
export class MapController {
App: Application;
export class MapController extends BaseController{
constructor(App: Application) {
constructor(private App : TemplatedApp) {
super();
this.App = App;
this.getStartMap();
this.assetMaps();
}
assetMaps() {
this.App.use('/map/files', express.static('src/Assets/Maps'));
}
// Returns a map mapping map name to file name of the map
getStartMap() {
this.App.get("/start-map", (req: Request, res: Response) => {
const url = req.headers.host?.replace('api.', 'maps.') + URL_ROOM_STARTED;
res.status(OK).send({
this.App.options("/start-map", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.end();
});
this.App.get("/start-map", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
const url = req.getHeader('host').replace('api.', 'maps.') + URL_ROOM_STARTED;
res.writeStatus("200 OK").end(JSON.stringify({
mapUrlStart: url,
startInstance: "global"
});
}));
});
}
}

View file

@ -1,10 +1,11 @@
import {Application, Request, Response} from "express";
import {App} from "../Server/sifrr.server";
import {IoSocketController} from "_Controller/IoSocketController";
import {HttpRequest, HttpResponse} from "uWebSockets.js";
const register = require('prom-client').register;
const collectDefaultMetrics = require('prom-client').collectDefaultMetrics;
export class PrometheusController {
constructor(private App: Application, private ioSocketController: IoSocketController) {
constructor(private App: App, private ioSocketController: IoSocketController) {
collectDefaultMetrics({
timeout: 10000,
gcDurationBuckets: [0.001, 0.01, 0.1, 1, 2, 5], // These are the default buckets.
@ -13,8 +14,8 @@ export class PrometheusController {
this.App.get("/metrics", this.metrics.bind(this));
}
private metrics(req: Request, res: Response): void {
res.set('Content-Type', register.contentType);
private metrics(res: HttpResponse, req: HttpRequest): void {
res.writeHeader('Content-Type', register.contentType);
res.end(register.metrics());
}
}

View file

@ -5,6 +5,7 @@ const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS)
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == 'true' : false;
const ADMIN_API_URL = process.env.ADMIN_API_URL || null;
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || null;
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
export {
SECRET_KEY,
@ -14,4 +15,5 @@ export {
ADMIN_API_TOKEN,
GROUP_RADIUS,
ALLOW_ARTILLERY,
}
CPU_OVERHEAT_THRESHOLD,
}

View file

@ -87,7 +87,7 @@ export class Group implements Movable {
join(user: User): void
{
// Broadcast on the right event
this.connectCallback(user.id, this);
this.connectCallback(user, this);
this.users.add(user);
user.group = this;
}
@ -105,7 +105,7 @@ export class Group implements Movable {
}
// Broadcast on the right event
this.disconnectCallback(user.id, this);
this.disconnectCallback(user, this);
}
/**

View file

@ -4,6 +4,7 @@ import {Zone} from "_Model/Zone";
import {Movable} from "_Model/Movable";
import {PositionInterface} from "_Model/PositionInterface";
import {PositionNotifier} from "_Model/PositionNotifier";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
export class User implements Movable {
public listenedZones: Set<Zone>;
@ -13,7 +14,8 @@ export class User implements Movable {
public id: number,
private position: PointInterface,
public silent: boolean,
private positionNotifier: PositionNotifier
private positionNotifier: PositionNotifier,
public readonly socket: ExSocketInterface
) {
this.listenedZones = new Set<Zone>();

View file

@ -1,24 +1,23 @@
import {Socket} from "socket.io";
import {PointInterface} from "./PointInterface";
import {Identificable} from "./Identificable";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
import {WebSocket} from "uWebSockets.js"
export interface ExSocketInterface extends Socket, Identificable {
export interface ExSocketInterface extends WebSocket, Identificable {
token: string;
roomId: string;
webRtcRoomId: string|undefined;
userId: number; // A temporary (autoincremented) identifier for this user
userUuid: string; // A unique identifier for this user
name: string;
characterLayers: string[];
position: PointInterface;
viewport: ViewportInterface;
isArtillery: boolean; // Whether this socket is opened by Artillery for load testing (hack)
/**
* Pushes an event that will be sent in the next batch of events
*/
emitInBatch: (event: string, payload: SubMessage) => void;
emitInBatch: (payload: SubMessage) => void;
batchedMessages: BatchMessage;
batchTimeout: NodeJS.Timeout|null;
disconnecting: boolean
}

View file

@ -1,8 +1,9 @@
import {PointInterface} from "./PointInterface";
import {ItemEventMessage, PositionMessage} from "../../Messages/generated/messages_pb";
import {ItemEventMessage, PointMessage, PositionMessage} from "../../Messages/generated/messages_pb";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
import Direction = PositionMessage.Direction;
import {ItemEventMessageInterface} from "_Model/Websocket/ItemEventMessage";
import {PositionInterface} from "_Model/PositionInterface";
export class ProtobufUtils {
@ -34,6 +35,42 @@ export class ProtobufUtils {
return position;
}
public static toPointInterface(position: PositionMessage): PointInterface {
let direction: string;
switch (position.getDirection()) {
case Direction.UP:
direction = 'up';
break;
case Direction.DOWN:
direction = 'down';
break;
case Direction.LEFT:
direction = 'left';
break;
case Direction.RIGHT:
direction = 'right';
break;
default:
throw new Error("Unexpected direction");
}
// sending to all clients in room except sender
return {
x: position.getX(),
y: position.getY(),
direction,
moving: position.getMoving(),
};
}
public static toPointMessage(point: PositionInterface): PointMessage {
const position = new PointMessage();
position.setX(Math.floor(point.x));
position.setY(Math.floor(point.y));
return position;
}
public static toItemEvent(itemEventMessage: ItemEventMessage): ItemEventMessageInterface {
return {
itemId: itemEventMessage.getItemid(),

View file

@ -11,8 +11,8 @@ import {PositionNotifier} from "./PositionNotifier";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {Movable} from "_Model/Movable";
export type ConnectCallback = (user: number, group: Group) => void;
export type DisconnectCallback = (user: number, group: Group) => void;
export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: User, group: Group) => void;
export class World {
private readonly minDistance: number;
@ -55,8 +55,8 @@ export class World {
return this.users;
}
public join(socket : Identificable, userPosition: PointInterface): void {
const user = new User(socket.userId, userPosition, false, this.positionNotifier);
public join(socket : ExSocketInterface, userPosition: PointInterface): void {
const user = new User(socket.userId, 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);
@ -74,8 +74,8 @@ export class World {
this.users.delete(user.userId);
if (userObj !== undefined) {
this.positionNotifier.leave(userObj);
this.positionNotifier.removeViewport(userObj);
this.positionNotifier.leave(userObj);
}
}

View file

@ -0,0 +1,13 @@
import { App as _App, AppOptions } from 'uWebSockets.js';
import BaseApp from './baseapp';
import { extend } from './utils';
import { UwsApp } from './types';
class App extends (<UwsApp>_App) {
constructor(options: AppOptions = {}) {
super(options); // eslint-disable-line constructor-super
extend(this, new BaseApp());
}
}
export default App;

View file

@ -0,0 +1,111 @@
import { Readable } from 'stream';
import { us_listen_socket_close, TemplatedApp, HttpResponse, HttpRequest } from 'uWebSockets.js';
import { stob } from './utils';
import { Handler } from './types';
const noOp = () => true;
const handleBody = (res: HttpResponse, req: HttpRequest) => {
const contType = req.getHeader('content-type');
res.bodyStream = function() {
const stream = new Readable();
stream._read = noOp; // eslint-disable-line @typescript-eslint/unbound-method
this.onData((ab, isLast) => {
// uint and then slicing is bit faster than slice and then uint
stream.push(new Uint8Array(ab.slice((ab as any).byteOffset, ab.byteLength))); // eslint-disable-line @typescript-eslint/no-explicit-any
if (isLast) {
stream.push(null);
}
});
return stream;
};
res.body = () => stob(res.bodyStream());
if (contType.includes('application/json'))
res.json = async () => JSON.parse(await res.body());
};
class BaseApp {
_sockets = new Map();
ws!: TemplatedApp['ws'];
get!: TemplatedApp['get'];
_post!: TemplatedApp['post'];
_put!: TemplatedApp['put'];
_patch!: TemplatedApp['patch'];
_listen!: TemplatedApp['listen'];
post(pattern: string, handler: Handler) {
if (typeof handler !== 'function')
throw Error(`handler should be a function, given ${typeof handler}.`);
this._post(pattern, (res, req) => {
handleBody(res, req);
handler(res, req);
});
return this;
}
put(pattern: string, handler: Handler) {
if (typeof handler !== 'function')
throw Error(`handler should be a function, given ${typeof handler}.`);
this._put(pattern, (res, req) => {
handleBody(res, req);
handler(res, req);
});
return this;
}
patch(pattern: string, handler: Handler) {
if (typeof handler !== 'function')
throw Error(`handler should be a function, given ${typeof handler}.`);
this._patch(pattern, (res, req) => {
handleBody(res, req);
handler(res, req);
});
return this;
}
listen(h: string | number, p: Function | number = noOp, cb?: Function) {
if (typeof p === 'number' && typeof h === 'string') {
this._listen(h, p, socket => {
this._sockets.set(p, socket);
if (cb === undefined) {
throw new Error('cb undefined');
}
cb(socket);
});
} else if (typeof h === 'number' && typeof p === 'function') {
this._listen(h, socket => {
this._sockets.set(h, socket);
p(socket);
});
} else {
throw Error(
'Argument types: (host: string, port: number, cb?: Function) | (port: number, cb?: Function)'
);
}
return this;
}
close(port: null | number = null) {
if (port) {
this._sockets.has(port) && us_listen_socket_close(this._sockets.get(port));
this._sockets.delete(port);
} else {
this._sockets.forEach(app => {
us_listen_socket_close(app);
});
this._sockets.clear();
}
return this;
}
}
export default BaseApp;

View file

@ -0,0 +1,13 @@
import { SSLApp as _SSLApp, AppOptions } from 'uWebSockets.js';
import BaseApp from './baseapp';
import { extend } from './utils';
import { UwsApp } from './types';
class SSLApp extends (<UwsApp>_SSLApp) {
constructor(options: AppOptions) {
super(options); // eslint-disable-line constructor-super
extend(this, new BaseApp());
}
}
export default SSLApp;

View file

@ -0,0 +1,11 @@
import { AppOptions, TemplatedApp, HttpResponse, HttpRequest } from 'uWebSockets.js';
export type UwsApp = {
(options: AppOptions): TemplatedApp;
new (options: AppOptions): TemplatedApp;
prototype: TemplatedApp;
};
export type Handler = (res: HttpResponse, req: HttpRequest) => void;
export {};

View file

@ -0,0 +1,37 @@
import { ReadStream } from 'fs';
function extend(who: any, from: any, overwrite = true) { // eslint-disable-line @typescript-eslint/no-explicit-any
const ownProps = Object.getOwnPropertyNames(Object.getPrototypeOf(from)).concat(
Object.keys(from)
);
ownProps.forEach(prop => {
if (prop === 'constructor' || from[prop] === undefined) return;
if (who[prop] && overwrite) {
who[`_${prop}`] = who[prop];
}
if (typeof from[prop] === 'function') who[prop] = from[prop].bind(who);
else who[prop] = from[prop];
});
}
function stob(stream: ReadStream): Promise<Buffer> {
return new Promise(resolve => {
const buffers: Buffer[] = [];
stream.on('data', buffers.push.bind(buffers));
stream.on('end', () => {
switch (buffers.length) {
case 0:
resolve(Buffer.allocUnsafe(0));
break;
case 1:
resolve(buffers[0]);
break;
default:
resolve(Buffer.concat(buffers));
}
});
});
}
export { extend, stob };

View file

@ -0,0 +1,19 @@
import { parse } from 'query-string';
import { HttpRequest } from 'uWebSockets.js';
import App from './server/app';
import SSLApp from './server/sslapp';
import * as types from './server/types';
const getQuery = (req: HttpRequest) => {
return parse(req.getQuery());
};
export { App, SSLApp, getQuery };
export * from './server/types';
export default {
App,
SSLApp,
getQuery,
...types
};

View file

@ -0,0 +1,55 @@
import {CPU_OVERHEAT_THRESHOLD} from "../Enum/EnvironmentVariable";
function secNSec2ms(secNSec: Array<number>|number) {
if (Array.isArray(secNSec)) {
return secNSec[0] * 1000 + secNSec[1] / 1000000;
}
return secNSec / 1000;
}
class CpuTracker {
private cpuPercent: number = 0;
private overHeating: boolean = false;
constructor() {
let time = process.hrtime.bigint()
let usage = process.cpuUsage()
setInterval(() => {
const elapTime = process.hrtime.bigint();
const elapUsage = process.cpuUsage(usage)
usage = process.cpuUsage()
const elapTimeMS = elapTime - time;
const elapUserMS = secNSec2ms(elapUsage.user)
const elapSystMS = secNSec2ms(elapUsage.system)
this.cpuPercent = Math.round(100 * (elapUserMS + elapSystMS) / Number(elapTimeMS) * 1000000)
time = elapTime;
if (!this.overHeating && this.cpuPercent > CPU_OVERHEAT_THRESHOLD) {
this.overHeating = true;
console.warn('CPU high threshold alert. Going in "overheat" mode');
} else if (this.overHeating && this.cpuPercent <= CPU_OVERHEAT_THRESHOLD) {
this.overHeating = false;
console.log('CPU is back to normal. Canceling "overheat" mode');
}
/*console.log('elapsed time ms: ', elapTimeMS)
console.log('elapsed user ms: ', elapUserMS)
console.log('elapsed system ms:', elapSystMS)
console.log('cpu percent: ', this.cpuPercent)*/
}, 100);
}
public getCpuPercent(): number {
return this.cpuPercent;
}
public isOverHeating(): boolean {
return this.overHeating;
}
}
const cpuTracker = new CpuTracker();
export { cpuTracker };

View file

@ -8,6 +8,7 @@ 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", () => {
@ -29,14 +30,14 @@ describe("PositionNotifier", () => {
y: 500,
moving: false,
direction: 'down'
}, false, positionNotifier);
}, false, positionNotifier, {} as ExSocketInterface);
const user2 = new User(2, {
x: -9999,
y: -9999,
moving: false,
direction: 'down'
}, false, positionNotifier);
}, false, positionNotifier, {} as ExSocketInterface);
positionNotifier.setViewport(user1, {
left: 200,
@ -107,14 +108,14 @@ describe("PositionNotifier", () => {
y: 500,
moving: false,
direction: 'down'
}, false, positionNotifier);
}, false, positionNotifier, {} as ExSocketInterface);
const user2 = new User(2, {
x: 0,
y: 0,
moving: false,
direction: 'down'
}, false, positionNotifier);
}, false, positionNotifier, {} as ExSocketInterface);
let newUsers = positionNotifier.setViewport(user1, {
left: 200,

View file

@ -2,22 +2,30 @@ import "jasmine";
import {World, ConnectCallback, DisconnectCallback } from "../src/Model/World";
import {Point} from "../src/Model/Websocket/MessageUserPosition";
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("World", () => {
it("should connect user1 and user2", () => {
let connectCalledNumber: number = 0;
const connect: ConnectCallback = (user: number, group: Group): void => {
const connect: ConnectCallback = (user: User, group: Group): void => {
connectCalledNumber++;
}
const disconnect: DisconnectCallback = (user: number, group: Group): void => {
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
}
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
world.join({ userId: 1 }, new Point(100, 100));
world.join(createMockUser(1), new Point(100, 100));
world.join({ userId: 2 }, new Point(500, 100));
world.join(createMockUser(2), new Point(500, 100));
world.updatePosition({ userId: 2 }, new Point(261, 100));
@ -33,24 +41,24 @@ describe("World", () => {
it("should connect 3 users", () => {
let connectCalled: boolean = false;
const connect: ConnectCallback = (user: number, group: Group): void => {
const connect: ConnectCallback = (user: User, group: Group): void => {
connectCalled = true;
}
const disconnect: DisconnectCallback = (user: number, group: Group): void => {
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
}
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
world.join({ userId: 1 }, new Point(100, 100));
world.join(createMockUser(1), new Point(100, 100));
world.join({ userId: 2 }, new Point(200, 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({ userId: 3 }, new Point(311, 100));
world.join(createMockUser(3), new Point(311, 100));
expect(connectCalled).toBe(false);
@ -62,18 +70,18 @@ describe("World", () => {
it("should disconnect user1 and user2", () => {
let connectCalled: boolean = false;
let disconnectCallNumber: number = 0;
const connect: ConnectCallback = (user: number, group: Group): void => {
const connect: ConnectCallback = (user: User, group: Group): void => {
connectCalled = true;
}
const disconnect: DisconnectCallback = (user: number, group: Group): void => {
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
disconnectCallNumber++;
}
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {});
world.join({ userId: 1 }, new Point(100, 100));
world.join(createMockUser(1), new Point(100, 100));
world.join({ userId: 2 }, new Point(259, 100));
world.join(createMockUser(2), new Point(259, 100));
expect(connectCalled).toBe(true);
expect(disconnectCallNumber).toBe(0);

View file

@ -20,13 +20,6 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@types/body-parser@*":
version "1.19.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
dependencies:
"@types/connect" "*"
"@types/node" "*"
"@types/circular-json@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be"
@ -36,32 +29,10 @@
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
"@types/connect@*":
version "3.4.33"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
dependencies:
"@types/node" "*"
"@types/eslint-visitor-keys@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
"@types/express-serve-static-core@*":
version "4.17.3"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.3.tgz#dc8068ee3e354d7fba69feb86b3dfeee49b10f09"
dependencies:
"@types/node" "*"
"@types/range-parser" "*"
"@types/express@^4.17.4":
version "4.17.4"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.4.tgz#e78bf09f3f530889575f4da8a94cd45384520aac"
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "*"
"@types/qs" "*"
"@types/serve-static" "*"
"@types/google-protobuf@^3.7.3":
version "3.7.3"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.7.3.tgz#429512e541bbd777f2c867692e6335ee08d1f6d4"
@ -87,35 +58,10 @@
dependencies:
"@types/node" "*"
"@types/mime@*":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
"@types/node@*":
version "13.11.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
"@types/qs@*":
version "6.9.1"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.1.tgz#937fab3194766256ee09fcd40b781740758617e7"
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
"@types/serve-static@*":
version "1.13.3"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
dependencies:
"@types/express-serve-static-core" "*"
"@types/mime" "*"
"@types/socket.io@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.4.tgz#674e7bc193c5ccdadd4433f79f3660d31759e9ac"
dependencies:
"@types/node" "*"
"@types/strip-bom@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
@ -169,13 +115,6 @@
semver "^6.3.0"
tsutils "^3.17.1"
accepts@~1.3.4, accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
dependencies:
mime-types "~2.1.24"
negotiator "0.6.2"
acorn-jsx@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
@ -184,10 +123,6 @@ acorn@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
ajv@^6.10.0, ajv@^6.10.2:
version "6.12.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
@ -238,22 +173,10 @@ array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
astral-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
@ -261,38 +184,16 @@ axios@^0.20.0:
dependencies:
follow-redirects "^1.10.0"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
base64id@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
better-assert@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
dependencies:
callsite "1.0.0"
bintrees@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
blob@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
body-parser@1.19.0, body-parser@^1.19.0:
body-parser@^1.19.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
dependencies:
@ -322,14 +223,17 @@ buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
busboy@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b"
integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==
dependencies:
dicer "0.3.0"
bytes@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -399,44 +303,14 @@ color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
component-emitter@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
dependencies:
safe-buffer "5.1.2"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -470,22 +344,21 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
debug@^4.0.1, debug@^4.1.1, debug@~4.1.0:
debug@^4.0.1, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
dependencies:
ms "^2.1.1"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@ -494,9 +367,12 @@ depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
dicer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==
dependencies:
streamsearch "0.1.2"
diff@^4.0.1:
version "4.0.2"
@ -532,57 +408,12 @@ emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
engine.io-client@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
debug "~4.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
parseqs "0.0.5"
parseuri "0.0.5"
ws "~6.1.0"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
engine.io-parser@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
base64-arraybuffer "0.1.5"
blob "0.0.5"
has-binary2 "~1.0.2"
engine.io@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
dependencies:
accepts "~1.3.4"
base64id "2.0.0"
cookie "0.3.1"
debug "~4.1.0"
engine.io-parser "~2.2.0"
ws "^7.1.2"
error-ex@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
dependencies:
is-arrayish "^0.2.1"
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@ -688,45 +519,6 @@ esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
dependencies:
accepts "~1.3.7"
array-flatten "1.1.1"
body-parser "1.19.0"
content-disposition "0.5.3"
content-type "~1.0.4"
cookie "0.4.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.1.2"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.5"
qs "6.7.0"
range-parser "~1.2.1"
safe-buffer "5.1.2"
send "0.17.1"
serve-static "1.14.1"
setprototypeof "1.1.1"
statuses "~1.5.0"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@ -765,18 +557,6 @@ filewatcher@~3.0.0:
dependencies:
debounce "^1.0.0"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.3"
statuses "~1.5.0"
unpipe "~1.0.0"
find-up@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@ -801,14 +581,6 @@ follow-redirects@^1.10.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -862,16 +634,6 @@ growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
dependencies:
isarray "2.0.1"
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@ -894,16 +656,6 @@ http-errors@1.7.2:
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-errors@~1.7.2:
version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-status-codes@*, http-status-codes@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477"
@ -935,10 +687,6 @@ indent-string@^2.1.0:
dependencies:
repeating "^2.0.0"
indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -946,7 +694,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4:
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
@ -972,10 +720,6 @@ inquirer@^7.0.0:
strip-ansi "^6.0.0"
through "^2.3.6"
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@ -1014,14 +758,15 @@ is-wsl@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
iterall@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
jasmine-core@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.5.0.tgz#132c23e645af96d85c8bca13c8758b18429fc1e4"
@ -1165,14 +910,6 @@ meow@^3.3.0:
redent "^1.0.0"
trim-newlines "^1.0.0"
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
mime-db@1.43.0:
version "1.43.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
@ -1183,10 +920,6 @@ mime-types@~2.1.24:
dependencies:
mime-db "1.43.0"
mime@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@ -1211,10 +944,6 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
ms@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@ -1227,10 +956,6 @@ natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@ -1258,10 +983,6 @@ object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object-component@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@ -1307,22 +1028,6 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
dependencies:
better-assert "~1.0.0"
parseuri@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
dependencies:
better-assert "~1.0.0"
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
path-exists@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
@ -1341,10 +1046,6 @@ path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@ -1382,13 +1083,6 @@ prom-client@^12.0.0:
dependencies:
tdigest "^0.1.1"
proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
dependencies:
forwarded "~0.1.2"
ipaddr.js "1.9.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@ -1397,9 +1091,14 @@ qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
query-string@^6.13.3:
version "6.13.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.3.tgz#57d1c20e828b0e562d66b7f71a4998bd57f84112"
integrity sha512-dldo2oHe3sg03iPshlHw/64nkaRUJKdS0FW85kmWQkmCkqUbNdNdgkgtAufJcEpjzrx6Q9EW9Y3xqx/rM9pGhw==
dependencies:
decode-uri-component "^0.2.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
raw-body@2.4.0:
version "2.4.0"
@ -1487,10 +1186,6 @@ rxjs@^6.5.3:
dependencies:
tslib "^1.9.0"
safe-buffer@5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
safe-buffer@^5.0.1:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
@ -1507,33 +1202,6 @@ semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "~1.7.2"
mime "1.6.0"
ms "2.1.1"
on-finished "~2.3.0"
range-parser "~1.2.1"
statuses "~1.5.0"
serve-static@1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.1"
setprototypeof@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
@ -1564,56 +1232,6 @@ slice-ansi@^2.1.0:
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"
socket.io-adapter@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
socket.io-client@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
dependencies:
backo2 "1.0.2"
base64-arraybuffer "0.1.5"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "~4.1.0"
engine.io-client "~3.4.0"
has-binary2 "~1.0.2"
has-cors "1.1.0"
indexof "0.0.1"
object-component "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
dependencies:
component-emitter "1.2.1"
debug "~3.1.0"
isarray "2.0.1"
socket.io-parser@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
dependencies:
component-emitter "1.2.1"
debug "~4.1.0"
isarray "2.0.1"
socket.io@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
dependencies:
debug "~4.1.0"
engine.io "~3.4.0"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
socket.io-client "2.3.0"
socket.io-parser "~3.4.0"
source-map-support@^0.5.12, source-map-support@^0.5.6:
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
@ -1647,14 +1265,29 @@ spdx-license-ids@^3.0.0:
version "3.0.5"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
"statuses@>= 1.5.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
streamsearch@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
string-width@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
@ -1753,10 +1386,6 @@ tmp@^0.0.33:
dependencies:
os-tmpdir "~1.0.2"
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
@ -1829,7 +1458,7 @@ type-fest@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
type-is@~1.6.17, type-is@~1.6.18:
type-is@~1.6.17:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
dependencies:
@ -1840,7 +1469,11 @@ typescript@^3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
unpipe@1.0.0, unpipe@~1.0.0:
uWebSockets.js@uNetworking/uWebSockets.js#v18.5.0:
version "18.5.0"
resolved "https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/9b1605d2db82981cafe69dbe356e10ce412f5805"
unpipe@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@ -1850,10 +1483,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
uuid@7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
@ -1875,10 +1504,6 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
which@^1.2.9, which@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
@ -1899,28 +1524,10 @@ write@1.0.3:
dependencies:
mkdirp "^0.5.1"
ws@^7.1.2:
version "7.2.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
dependencies:
async-limiter "~1.0.0"
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"

View file

@ -1,13 +1,20 @@
import {RoomConnection} from "../front/src/Connexion/Connection";
import {RoomConnection} from "../front/src/Connexion/RoomConnection";
import {connectionManager} from "../front/src/Connexion/ConnectionManager";
import * as WebSocket from "ws"
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function startOneUser(): Promise<void> {
const connection = await RoomConnection.createConnection('foo', ['male3']);
RoomConnection.setWebsocketFactory((url: string) => {
return new WebSocket(url);
});
await connection.joinARoom('global__maps.workadventure.localhost/Floor0/floor0', 783, 170, 'down', false, {
async function startOneUser(): Promise<void> {
const connection = await connectionManager.connectToRoomSocket();
connection.emitPlayerDetailsMessage('foo', ['male3']);
await connection.joinARoom('global__maps.workadventure.localhost/Floor0/floor0', 783, 170, 'down', true, {
top: 0,
bottom: 200,
left: 500,
@ -38,6 +45,9 @@ async function startOneUser(): Promise<void> {
}
(async () => {
connectionManager.initBenchmark();
for (let userNo = 0; userNo < 40; userNo++) {
startOneUser();
// Wait 0.5s between adding users

View file

@ -21,11 +21,10 @@
],
"license": "SEE LICENSE IN LICENSE.txt",
"dependencies": {
"socket.io-client": "^2.3.0",
"@types/ws": "^7.2.6",
"ts-node-dev": "^1.0.0-pre.62",
"typescript": "^4.0.2"
"typescript": "^4.0.2",
"ws": "^7.3.1"
},
"devDependencies": {
"@types/socket.io-client": "^1.4.33"
}
"devDependencies": {}
}

View file

@ -2,9 +2,9 @@
# yarn lockfile v1
"@types/socket.io-client@^1.4.33":
version "1.4.33"
resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.33.tgz#8e705b9b3f7fba6cb329d27cd2eda222812adbf1"
"@types/node@*":
version "14.11.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.2.tgz#2de1ed6670439387da1c9f549a2ade2b0a799256"
"@types/strip-bom@^3.0.0":
version "3.0.0"
@ -14,9 +14,11 @@
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
"@types/ws@^7.2.6":
version "7.2.6"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.6.tgz#516cbfb818310f87b43940460e065eb912a4178d"
dependencies:
"@types/node" "*"
anymatch@~3.1.1:
version "3.1.1"
@ -33,40 +35,14 @@ array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
better-assert@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
dependencies:
callsite "1.0.0"
binary-extensions@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
blob@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -84,10 +60,6 @@ buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@ -113,22 +85,6 @@ chokidar@^3.4.0:
optionalDependencies:
fsevents "~2.1.2"
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
component-emitter@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
component-emitter@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -146,18 +102,6 @@ dateformat@~1.0.4-1.2.3:
get-stdin "^4.0.1"
meow "^3.3.0"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
debug@~4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
dependencies:
ms "^2.1.1"
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@ -172,32 +116,6 @@ dynamic-dedupe@^0.3.0:
dependencies:
xtend "^4.0.0"
engine.io-client@~3.4.0:
version "3.4.3"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.3.tgz#192d09865403e3097e3575ebfeb3861c4d01a66c"
dependencies:
component-emitter "~1.3.0"
component-inherit "0.0.3"
debug "~4.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
parseqs "0.0.5"
parseuri "0.0.5"
ws "~6.1.0"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
engine.io-parser@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
base64-arraybuffer "0.1.5"
blob "0.0.5"
has-binary2 "~1.0.2"
error-ex@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@ -250,16 +168,6 @@ graceful-fs@^4.1.2:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
dependencies:
isarray "2.0.1"
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
hosted-git-info@^2.1.4:
version "2.8.8"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
@ -270,10 +178,6 @@ indent-string@^2.1.0:
dependencies:
repeating "^2.0.0"
indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -317,10 +221,6 @@ is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -375,14 +275,6 @@ mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -400,10 +292,6 @@ object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object-component@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@ -416,18 +304,6 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
dependencies:
better-assert "~1.0.0"
parseuri@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
dependencies:
better-assert "~1.0.0"
path-exists@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
@ -522,33 +398,6 @@ signal-exit@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
socket.io-client@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
dependencies:
backo2 "1.0.2"
base64-arraybuffer "0.1.5"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "~4.1.0"
engine.io-client "~3.4.0"
has-binary2 "~1.0.2"
has-cors "1.1.0"
indexof "0.0.1"
object-component "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
dependencies:
component-emitter "1.2.1"
debug "~3.1.0"
isarray "2.0.1"
source-map-support@^0.5.12, source-map-support@^0.5.17:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
@ -602,10 +451,6 @@ strip-json-comments@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@ -670,24 +515,14 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
dependencies:
async-limiter "~1.0.0"
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
ws@^7.3.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"

View file

@ -12,10 +12,10 @@ interface LoginApiData {
class ConnectionManager {
private initPromise: Promise<LoginApiData> = Promise.reject();
private mapUrlStart: string|null = null;
private authToken:string|null = null;
private userUuid: string|null = null;
public async init(): Promise<void> {
const match = /\/register\/(.+)/.exec(window.location.toString());
const organizationMemberToken = match ? match[1] : null;
@ -30,7 +30,11 @@ class ConnectionManager {
history.pushState({}, '', newUrl);
}
}
public initBenchmark(): void {
this.authToken = 'test';
}
public connectToRoomSocket(): Promise<RoomConnection> {
return new Promise<RoomConnection>((resolve, reject) => {
const connection = new RoomConnection(this.authToken as string);
@ -38,7 +42,9 @@ class ConnectionManager {
console.log('An error occurred while connecting to socket server. Retrying');
reject(error);
});
resolve(connection);
connection.onConnect(() => {
resolve(connection);
})
}).catch((err) => {
// Let's retry in 4-6 seconds
return new Promise<RoomConnection>((resolve, reject) => {
@ -49,7 +55,7 @@ class ConnectionManager {
});
});
}
public getMapUrlStart(): Promise<string> {
return this.initPromise.then(() => {
if (!this.mapUrlStart) {
@ -60,4 +66,4 @@ class ConnectionManager {
}
}
export const connectionManager = new ConnectionManager();
export const connectionManager = new ConnectionManager();

View file

@ -1,14 +1,29 @@
import {API_URL} from "../Enum/EnvironmentVariable";
import {
BatchMessage, GroupDeleteMessage, GroupUpdateMessage, ItemEventMessage,
BatchMessage,
ClientToServerMessage,
GroupDeleteMessage,
GroupUpdateMessage,
ItemEventMessage,
JoinRoomMessage,
PositionMessage,
SetPlayerDetailsMessage, UserJoinedMessage, UserLeftMessage, UserMovedMessage,
RoomJoinedMessage,
ServerToClientMessage,
SetPlayerDetailsMessage,
SetUserIdMessage,
SilentMessage,
UserJoinedMessage,
UserLeftMessage,
UserMovedMessage,
UserMovesMessage,
ViewportMessage
ViewportMessage,
WebRtcDisconnectMessage,
WebRtcSignalToClientMessage,
WebRtcSignalToServerMessage,
WebRtcStartMessage
} from "../Messages/generated/messages_pb"
const SocketIo = require('socket.io-client');
import Socket = SocketIOClient.Socket;
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
import Direction = PositionMessage.Direction;
import {ProtobufClientUtils} from "../Network/ProtobufClientUtils";
import {
@ -24,96 +39,146 @@ import {
export class RoomConnection implements RoomConnection {
private readonly socket: Socket;
private readonly socket: WebSocket;
private userId: number|null = null;
private batchCallbacks: Map<string, Function[]> = new Map<string, Function[]>();
private listeners: Map<string, Function[]> = new Map<string, Function[]>();
private static websocketFactory: null|((url: string)=>any) = null; // eslint-disable-line @typescript-eslint/no-explicit-any
public static setWebsocketFactory(websocketFactory: (url: string)=>any): void { // eslint-disable-line @typescript-eslint/no-explicit-any
RoomConnection.websocketFactory = websocketFactory;
}
public constructor(token: string) {
let url = API_URL.replace('http://', 'ws://').replace('https://', 'wss://');
url += '?token='+token;
this.socket = SocketIo(`${API_URL}`, {
query: {
token: token
},
reconnection: false // Reconnection is handled by the application itself
});
if (RoomConnection.websocketFactory) {
this.socket = RoomConnection.websocketFactory(url);
} else {
this.socket = new WebSocket(url);
}
this.socket.on(EventMessage.MESSAGE_ERROR, (message: string) => {
console.error(EventMessage.MESSAGE_ERROR, message);
})
this.socket.binaryType = 'arraybuffer';
/**
* Messages inside batched messages are extracted and sent to listeners directly.
*/
this.socket.on(EventMessage.BATCH, (batchedMessagesBinary: ArrayBuffer) => {
const batchMessage = BatchMessage.deserializeBinary(new Uint8Array(batchedMessagesBinary));
this.socket.onopen = (ev) => {
//console.log('WS connected');
};
for (const message of batchMessage.getPayloadList()) {
let event: string;
let payload;
if (message.hasUsermovedmessage()) {
event = EventMessage.USER_MOVED;
payload = message.getUsermovedmessage();
} else if (message.hasGroupupdatemessage()) {
event = EventMessage.GROUP_CREATE_UPDATE;
payload = message.getGroupupdatemessage();
} else if (message.hasGroupdeletemessage()) {
event = EventMessage.GROUP_DELETE;
payload = message.getGroupdeletemessage();
} else if (message.hasUserjoinedmessage()) {
event = EventMessage.JOIN_ROOM;
payload = message.getUserjoinedmessage();
} else if (message.hasUserleftmessage()) {
event = EventMessage.USER_LEFT;
payload = message.getUserleftmessage();
} else if (message.hasItemeventmessage()) {
event = EventMessage.ITEM_EVENT;
payload = message.getItemeventmessage();
} else {
throw new Error('Unexpected batch message type');
this.socket.onmessage = (messageEvent) => {
const arrayBuffer: ArrayBuffer = messageEvent.data;
const message = ServerToClientMessage.deserializeBinary(new Uint8Array(arrayBuffer));
if (message.hasBatchmessage()) {
for (const subMessage of (message.getBatchmessage() as BatchMessage).getPayloadList()) {
let event: string;
let payload;
if (subMessage.hasUsermovedmessage()) {
event = EventMessage.USER_MOVED;
payload = subMessage.getUsermovedmessage();
} else if (subMessage.hasGroupupdatemessage()) {
event = EventMessage.GROUP_CREATE_UPDATE;
payload = subMessage.getGroupupdatemessage();
} else if (subMessage.hasGroupdeletemessage()) {
event = EventMessage.GROUP_DELETE;
payload = subMessage.getGroupdeletemessage();
} else if (subMessage.hasUserjoinedmessage()) {
event = EventMessage.JOIN_ROOM;
payload = subMessage.getUserjoinedmessage();
} else if (subMessage.hasUserleftmessage()) {
event = EventMessage.USER_LEFT;
payload = subMessage.getUserleftmessage();
} else if (subMessage.hasItemeventmessage()) {
event = EventMessage.ITEM_EVENT;
payload = subMessage.getItemeventmessage();
} else {
throw new Error('Unexpected batch message type');
}
this.dispatch(event, payload);
}
} else if (message.hasRoomjoinedmessage()) {
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
const users: Array<MessageUserJoined> = roomJoinedMessage.getUserList().map(this.toMessageUserJoined.bind(this));
const groups: Array<GroupCreatedUpdatedMessageInterface> = roomJoinedMessage.getGroupList().map(this.toGroupCreatedUpdatedMessage.bind(this));
const items: { [itemId: number] : unknown } = {};
for (const item of roomJoinedMessage.getItemList()) {
items[item.getItemid()] = JSON.parse(item.getStatejson());
}
const listeners = this.batchCallbacks.get(event);
if (listeners === undefined) {
continue;
}
for (const listener of listeners) {
listener(payload);
}
this.resolveJoinRoom({
users,
groups,
items
})
} else if (message.hasSetuseridmessage()) {
this.userId = (message.getSetuseridmessage() as SetUserIdMessage).getUserid();
} else if (message.hasErrormessage()) {
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
} else if (message.hasWebrtcsignaltoclientmessage()) {
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
this.dispatch(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, message.getWebrtcscreensharingsignaltoclientmessage());
} else if (message.hasWebrtcstartmessage()) {
this.dispatch(EventMessage.WEBRTC_START, message.getWebrtcstartmessage());
} else if (message.hasWebrtcdisconnectmessage()) {
this.dispatch(EventMessage.WEBRTC_DISCONNECT, message.getWebrtcdisconnectmessage());
} else {
throw new Error('Unknown message received');
}
})
}
}
private dispatch(event: string, payload: unknown): void {
const listeners = this.listeners.get(event);
if (listeners === undefined) {
return;
}
for (const listener of listeners) {
listener(payload);
}
}
public emitPlayerDetailsMessage(userName: string, characterLayersSelected: string[]) {
const message = new SetPlayerDetailsMessage();
message.setName(userName);
message.setCharacterlayersList(characterLayersSelected);
this.socket.emit(EventMessage.SET_PLAYER_DETAILS, message.serializeBinary().buffer, (id: number) => {
this.userId = id;
});
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setSetplayerdetailsmessage(message);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public closeConnection(): void {
this.socket?.close();
}
private resolveJoinRoom!: (value?: (RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface> | undefined)) => void;
public joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean, viewport: ViewportInterface): Promise<RoomJoinedMessageInterface> {
const promise = new Promise<RoomJoinedMessageInterface>((resolve, reject) => {
this.socket.emit(EventMessage.JOIN_ROOM, {
roomId,
position: {x: startX, y: startY, direction, moving },
viewport,
}, (roomJoinedMessage: RoomJoinedMessageInterface) => {
resolve(roomJoinedMessage);
});
this.resolveJoinRoom = resolve;
const positionMessage = this.toPositionMessage(startX, startY, direction, moving);
const viewportMessage = this.toViewportMessage(viewport);
const joinRoomMessage = new JoinRoomMessage();
joinRoomMessage.setRoomid(roomId);
joinRoomMessage.setPosition(positionMessage);
joinRoomMessage.setViewport(viewportMessage);
//console.log('Sending position ', positionMessage.getX(), positionMessage.getY());
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setJoinroommessage(joinRoomMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
})
return promise;
}
public sharePosition(x : number, y : number, direction : string, moving: boolean, viewport: ViewportInterface) : void{
if(!this.socket){
return;
}
private toPositionMessage(x : number, y : number, direction : string, moving: boolean): PositionMessage {
const positionMessage = new PositionMessage();
positionMessage.setX(Math.floor(x));
positionMessage.setY(Math.floor(y));
@ -137,23 +202,47 @@ export class RoomConnection implements RoomConnection {
positionMessage.setDirection(directionEnum);
positionMessage.setMoving(moving);
return positionMessage;
}
private toViewportMessage(viewport: ViewportInterface): ViewportMessage {
const viewportMessage = new ViewportMessage();
viewportMessage.setLeft(Math.floor(viewport.left));
viewportMessage.setRight(Math.floor(viewport.right));
viewportMessage.setTop(Math.floor(viewport.top));
viewportMessage.setBottom(Math.floor(viewport.bottom));
return viewportMessage;
}
public sharePosition(x : number, y : number, direction : string, moving: boolean, viewport: ViewportInterface) : void{
if(!this.socket){
return;
}
const positionMessage = this.toPositionMessage(x, y, direction, moving);
const viewportMessage = this.toViewportMessage(viewport);
const userMovesMessage = new UserMovesMessage();
userMovesMessage.setPosition(positionMessage);
userMovesMessage.setViewport(viewportMessage);
//console.log('Sending position ', positionMessage.getX(), positionMessage.getY());
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setUsermovesmessage(userMovesMessage);
this.socket.emit(EventMessage.USER_POSITION, userMovesMessage.serializeBinary().buffer);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public setSilent(silent: boolean): void {
this.socket.emit(EventMessage.SET_SILENT, silent);
const silentMessage = new SilentMessage();
silentMessage.setSilent(silent);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setSilentmessage(silentMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public setViewport(viewport: ViewportInterface): void {
@ -163,108 +252,145 @@ export class RoomConnection implements RoomConnection {
viewportMessage.setLeft(Math.round(viewport.left));
viewportMessage.setRight(Math.round(viewport.right));
this.socket.emit(EventMessage.SET_VIEWPORT, viewportMessage.serializeBinary().buffer);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setViewportmessage(viewportMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public onUserJoins(callback: (message: MessageUserJoined) => void): void {
this.onBatchMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
const position = message.getPosition();
if (position === undefined) {
throw new Error('Invalid JOIN_ROOM message');
}
const messageUserJoined: MessageUserJoined = {
userId: message.getUserid(),
name: message.getName(),
characterLayers: message.getCharacterlayersList(),
position: ProtobufClientUtils.toPointInterface(position)
}
callback(messageUserJoined);
this.onMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
callback(this.toMessageUserJoined(message));
});
}
// TODO: move this to protobuf utils
private toMessageUserJoined(message: UserJoinedMessage): MessageUserJoined {
const position = message.getPosition();
if (position === undefined) {
throw new Error('Invalid JOIN_ROOM message');
}
return {
userId: message.getUserid(),
name: message.getName(),
characterLayers: message.getCharacterlayersList(),
position: ProtobufClientUtils.toPointInterface(position)
}
}
public onUserMoved(callback: (message: UserMovedMessage) => void): void {
this.onBatchMessage(EventMessage.USER_MOVED, callback);
this.onMessage(EventMessage.USER_MOVED, callback);
//this.socket.on(EventMessage.USER_MOVED, callback);
}
/**
* Registers a listener on a message that is part of a batch
*/
private onBatchMessage(eventName: string, callback: Function): void {
let callbacks = this.batchCallbacks.get(eventName);
private onMessage(eventName: string, callback: Function): void {
let callbacks = this.listeners.get(eventName);
if (callbacks === undefined) {
callbacks = new Array<Function>();
this.batchCallbacks.set(eventName, callbacks);
this.listeners.set(eventName, callbacks);
}
callbacks.push(callback);
}
public onUserLeft(callback: (userId: number) => void): void {
this.onBatchMessage(EventMessage.USER_LEFT, (message: UserLeftMessage) => {
this.onMessage(EventMessage.USER_LEFT, (message: UserLeftMessage) => {
callback(message.getUserid());
});
}
public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void {
this.onBatchMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
const position = message.getPosition();
if (position === undefined) {
throw new Error('Missing position in GROUP_CREATE_UPDATE');
}
const groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface = {
groupId: message.getGroupid(),
position: position.toObject()
}
//console.log('Group position: ', position.toObject());
callback(groupCreateUpdateMessage);
this.onMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
callback(this.toGroupCreatedUpdatedMessage(message));
});
}
private toGroupCreatedUpdatedMessage(message: GroupUpdateMessage): GroupCreatedUpdatedMessageInterface {
const position = message.getPosition();
if (position === undefined) {
throw new Error('Missing position in GROUP_CREATE_UPDATE');
}
return {
groupId: message.getGroupid(),
position: position.toObject()
}
}
public onGroupDeleted(callback: (groupId: number) => void): void {
this.onBatchMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
this.onMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
callback(message.getGroupid());
});
}
public onConnectError(callback: (error: object) => void): void {
this.socket.on(EventMessage.CONNECT_ERROR, callback)
public onConnectError(callback: (error: Event) => void): void {
this.socket.addEventListener('error', callback)
}
public onConnect(callback: (event: Event) => void): void {
this.socket.addEventListener('open', callback)
}
public sendWebrtcSignal(signal: unknown, receiverId: number) {
return this.socket.emit(EventMessage.WEBRTC_SIGNAL, {
receiverId: receiverId,
signal: signal
} as WebRtcSignalSentMessageInterface);
const webRtcSignal = new WebRtcSignalToServerMessage();
webRtcSignal.setReceiverid(receiverId);
webRtcSignal.setSignal(JSON.stringify(signal));
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) {
return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, {
receiverId: receiverId,
signal: signal
} as WebRtcSignalSentMessageInterface);
const webRtcSignal = new WebRtcSignalToServerMessage();
webRtcSignal.setReceiverid(receiverId);
webRtcSignal.setSignal(JSON.stringify(signal));
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcscreensharingsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public receiveWebrtcStart(callback: (message: WebRtcStartMessageInterface) => void) {
this.socket.on(EventMessage.WEBRTC_START, callback);
public receiveWebrtcStart(callback: (message: UserSimplePeerInterface) => void) {
this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => {
callback({
userId: message.getUserid(),
name: message.getName(),
initiator: message.getInitiator()
});
});
}
public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
this.onMessage(EventMessage.WEBRTC_SIGNAL, (message: WebRtcSignalToClientMessage) => {
callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal())
});
});
}
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback);
this.onMessage(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, (message: WebRtcSignalToClientMessage) => {
callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal())
});
});
}
public onServerDisconnected(callback: (reason: string) => void): void {
this.socket.on('disconnect', (reason: string) => {
if (reason === 'io client disconnect') {
// The client asks for disconnect, let's not trigger any event.
public onServerDisconnected(callback: (event: CloseEvent) => void): void {
this.socket.addEventListener('close', (event) => {
console.log('Socket closed with code '+event.code+". Reason: "+event.reason);
if (event.code === 1000) {
// Normal closure case
return;
}
callback(reason);
callback(event);
});
}
@ -274,7 +400,11 @@ export class RoomConnection implements RoomConnection {
}
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
this.socket.on(EventMessage.WEBRTC_DISCONNECT, callback);
this.onMessage(EventMessage.WEBRTC_DISCONNECT, (message: WebRtcDisconnectMessage) => {
callback({
userId: message.getUserid()
});
});
}
emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void {
@ -284,11 +414,14 @@ export class RoomConnection implements RoomConnection {
itemEventMessage.setStatejson(JSON.stringify(state));
itemEventMessage.setParametersjson(JSON.stringify(parameters));
this.socket.emit(EventMessage.ITEM_EVENT, itemEventMessage.serializeBinary().buffer);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setItemeventmessage(itemEventMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
onActionableEvent(callback: (message: ItemEventMessageInterface) => void): void {
this.onBatchMessage(EventMessage.ITEM_EVENT, (message: ItemEventMessage) => {
this.onMessage(EventMessage.ITEM_EVENT, (message: ItemEventMessage) => {
callback({
itemId: message.getItemid(),
event: message.getEvent(),

View file

@ -7,7 +7,7 @@ const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined
const RESOLUTION = 3;
const ZOOM_LEVEL = 1/*3/4*/;
const POSITION_DELAY = 200; // Wait 200ms between sending position events
const MAX_EXTRAPOLATION_TIME = 250; // Extrapolate a maximum of 250ms if no new movement is sent by the player
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
export {
DEBUG_MODE,

View file

@ -82,7 +82,7 @@ export class SimplePeer {
mediaManager.getCamera().then(() => {
//receive message start
this.Connection.receiveWebrtcStart((message: WebRtcStartMessageInterface) => {
this.Connection.receiveWebrtcStart((message: UserSimplePeerInterface) => {
this.receiveWebrtcStart(message);
});
@ -95,17 +95,22 @@ export class SimplePeer {
});
}
private receiveWebrtcStart(data: WebRtcStartMessageInterface) {
this.WebRtcRoomId = data.roomId;
this.Users = data.clients;
private receiveWebrtcStart(user: UserSimplePeerInterface) {
//this.WebRtcRoomId = data.roomId;
this.Users.push(user);
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group)
// So we can receive a request we already had before. (which will abort at the first line of createPeerConnection)
// TODO: refactor this to only send a message to connect to one user (rather than several users).
// TODO: refactor this to only send a message to connect to one user (rather than several users). => DONE
// This would be symmetrical to the way we handle disconnection.
//console.log('Start message', data);
//start connection
this.startWebRtc();
//this.startWebRtc();
console.log('receiveWebrtcStart. Initiator: ', user.initiator)
if(!user.initiator){
return;
}
this.createPeerConnection(user);
}
/**
@ -129,6 +134,7 @@ export class SimplePeer {
if(
this.PeerConnectionArray.has(user.userId)
){
console.log('Peer connection already exists to user '+user.userId)
return null;
}

View file

@ -27,6 +27,10 @@ message ViewportMessage {
int32 bottom = 4;
}
message SilentMessage {
bool silent = 1;
}
/*********** CLIENT TO SERVER MESSAGES *************/
message SetPlayerDetailsMessage {
@ -34,11 +38,36 @@ message SetPlayerDetailsMessage {
repeated string characterLayers = 2;
}
message JoinRoomMessage {
string roomId = 1;
PositionMessage position = 2;
ViewportMessage viewport = 3;
}
message UserMovesMessage {
PositionMessage position = 1;
ViewportMessage viewport = 2;
}
message WebRtcSignalToServerMessage {
int32 receiverId = 1;
string signal = 2;
}
message ClientToServerMessage {
oneof message {
JoinRoomMessage joinRoomMessage = 1;
UserMovesMessage userMovesMessage = 2;
SilentMessage silentMessage = 3;
ViewportMessage viewportMessage = 4;
ItemEventMessage itemEventMessage = 5;
SetPlayerDetailsMessage setPlayerDetailsMessage = 6;
WebRtcSignalToServerMessage webRtcSignalToServerMessage = 7;
WebRtcSignalToServerMessage webRtcScreenSharingSignalToServerMessage = 8;
}
}
/************ BI-DIRECTIONAL MESSAGES **************/
message ItemEventMessage {
@ -90,3 +119,50 @@ message UserJoinedMessage {
message UserLeftMessage {
int32 userId = 1;
}
message ErrorMessage {
string message = 1;
}
message SetUserIdMessage {
int32 userId = 1;
}
message ItemStateMessage {
int32 itemId = 1;
string stateJson = 2;
}
message RoomJoinedMessage {
repeated UserJoinedMessage user = 1;
repeated GroupUpdateMessage group = 2;
repeated ItemStateMessage item = 3;
}
message WebRtcStartMessage {
int32 userId = 1;
string name = 2;
bool initiator = 3;
}
message WebRtcDisconnectMessage {
int32 userId = 1;
}
message WebRtcSignalToClientMessage {
int32 userId = 1;
string signal = 2;
}
message ServerToClientMessage {
oneof message {
BatchMessage batchMessage = 1;
ErrorMessage errorMessage = 2;
RoomJoinedMessage roomJoinedMessage = 3;
SetUserIdMessage setUserIdMessage = 4; // TODO: merge this with RoomJoinedMessage ?
WebRtcStartMessage webRtcStartMessage = 5;
WebRtcSignalToClientMessage webRtcSignalToClientMessage = 6;
WebRtcSignalToClientMessage webRtcScreenSharingSignalToClientMessage = 7;
WebRtcDisconnectMessage webRtcDisconnectMessage = 8;
}
}