Migrating to uWS
This commit is contained in:
parent
783d58d3cb
commit
6a4c0c8678
@ -38,27 +38,27 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
|
"busboy": "^0.3.1",
|
||||||
"circular-json": "^0.5.9",
|
"circular-json": "^0.5.9",
|
||||||
"express": "^4.17.1",
|
|
||||||
"generic-type-guard": "^3.2.0",
|
"generic-type-guard": "^3.2.0",
|
||||||
"google-protobuf": "^3.13.0",
|
"google-protobuf": "^3.13.0",
|
||||||
"http-status-codes": "^1.4.0",
|
"http-status-codes": "^1.4.0",
|
||||||
|
"iterall": "^1.3.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"prom-client": "^12.0.0",
|
"prom-client": "^12.0.0",
|
||||||
"socket.io": "^2.3.0",
|
"query-string": "^6.13.3",
|
||||||
"systeminformation": "^4.26.5",
|
"systeminformation": "^4.26.5",
|
||||||
"ts-node-dev": "^1.0.0-pre.44",
|
"ts-node-dev": "^1.0.0-pre.44",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
|
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
||||||
"uuidv4": "^6.0.7"
|
"uuidv4": "^6.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/circular-json": "^0.4.0",
|
"@types/circular-json": "^0.4.0",
|
||||||
"@types/express": "^4.17.4",
|
|
||||||
"@types/google-protobuf": "^3.7.3",
|
"@types/google-protobuf": "^3.7.3",
|
||||||
"@types/http-status-codes": "^1.2.0",
|
"@types/http-status-codes": "^1.2.0",
|
||||||
"@types/jasmine": "^3.5.10",
|
"@types/jasmine": "^3.5.10",
|
||||||
"@types/jsonwebtoken": "^8.3.8",
|
"@types/jsonwebtoken": "^8.3.8",
|
||||||
"@types/socket.io": "^2.1.4",
|
|
||||||
"@types/uuidv4": "^5.0.0",
|
"@types/uuidv4": "^5.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||||
"@typescript-eslint/parser": "^2.26.0",
|
"@typescript-eslint/parser": "^2.26.0",
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
// lib/server.ts
|
// lib/server.ts
|
||||||
import App from "./src/App";
|
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!`))
|
||||||
|
@ -9,10 +9,10 @@ import {MapController} from "./Controller/MapController";
|
|||||||
import {PrometheusController} from "./Controller/PrometheusController";
|
import {PrometheusController} from "./Controller/PrometheusController";
|
||||||
import {AdminController} from "./Controller/AdminController";
|
import {AdminController} from "./Controller/AdminController";
|
||||||
import {DebugController} from "./Controller/DebugController";
|
import {DebugController} from "./Controller/DebugController";
|
||||||
|
import {App as uwsApp} from "./Server/sifrr.server";
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
public app: Application;
|
public app: uwsApp;
|
||||||
public server: http.Server;
|
|
||||||
public ioSocketController: IoSocketController;
|
public ioSocketController: IoSocketController;
|
||||||
public authenticateController: AuthenticateController;
|
public authenticateController: AuthenticateController;
|
||||||
public mapController: MapController;
|
public mapController: MapController;
|
||||||
@ -21,18 +21,25 @@ class App {
|
|||||||
private debugController: DebugController;
|
private debugController: DebugController;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = express();
|
this.app = new uwsApp();
|
||||||
|
|
||||||
//config server http
|
|
||||||
this.server = http.createServer(this.app);
|
|
||||||
|
|
||||||
this.config();
|
this.config();
|
||||||
this.crossOrigin();
|
this.crossOrigin();
|
||||||
|
|
||||||
//TODO add middleware with access token to secure api
|
//TODO add middleware with access token to secure api
|
||||||
|
|
||||||
|
// STUPID CORS IMPLEMENTATION.
|
||||||
|
// TODO: SECURE THIS
|
||||||
|
this.app.any('/*', (res, req) => {
|
||||||
|
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', '*');
|
||||||
|
|
||||||
|
req.setYield(true);
|
||||||
|
});
|
||||||
|
|
||||||
//create socket controllers
|
//create socket controllers
|
||||||
this.ioSocketController = new IoSocketController(this.server);
|
this.ioSocketController = new IoSocketController(this.app);
|
||||||
this.authenticateController = new AuthenticateController(this.app);
|
this.authenticateController = new AuthenticateController(this.app);
|
||||||
this.mapController = new MapController(this.app);
|
this.mapController = new MapController(this.app);
|
||||||
this.prometheusController = new PrometheusController(this.app, this.ioSocketController);
|
this.prometheusController = new PrometheusController(this.app, this.ioSocketController);
|
||||||
@ -42,20 +49,20 @@ class App {
|
|||||||
|
|
||||||
// TODO add session user
|
// TODO add session user
|
||||||
private config(): void {
|
private config(): void {
|
||||||
this.app.use(bodyParser.json());
|
/*this.app.use(bodyParser.json());
|
||||||
this.app.use(bodyParser.urlencoded({extended: false}));
|
this.app.use(bodyParser.urlencoded({extended: false}));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private crossOrigin(){
|
private crossOrigin(){
|
||||||
this.app.use((req: Request, res: Response, next) => {
|
/*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
|
res.setHeader("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
|
||||||
// Request methods you wish to allow
|
// Request methods you wish to allow
|
||||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
||||||
// Request headers you wish to allow
|
// Request headers you wish to allow
|
||||||
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||||
next();
|
next();
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new App().server;
|
export default new App().app;
|
||||||
|
@ -3,38 +3,58 @@ import Jwt from "jsonwebtoken";
|
|||||||
import {BAD_REQUEST, OK} from "http-status-codes";
|
import {BAD_REQUEST, OK} from "http-status-codes";
|
||||||
import {SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
import {SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
||||||
import { uuid } from 'uuidv4';
|
import { uuid } from 'uuidv4';
|
||||||
|
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
|
||||||
|
import {BaseController} from "./BaseController";
|
||||||
|
|
||||||
export interface TokenInterface {
|
export interface TokenInterface {
|
||||||
name: string,
|
name: string,
|
||||||
userUuid: string
|
userUuid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuthenticateController {
|
export class AuthenticateController extends BaseController {
|
||||||
App : Application;
|
|
||||||
|
|
||||||
constructor(App : Application) {
|
constructor(private App : TemplatedApp) {
|
||||||
this.App = App;
|
super();
|
||||||
this.login();
|
this.login();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAbortedOrFinishedResponse(res: HttpResponse/*, readStream: any*/) {
|
||||||
|
|
||||||
|
console.log("ERROR! onAbortedOrFinishedResponse called!");
|
||||||
|
/*if (res.id == -1) {
|
||||||
|
console.log("ERROR! onAbortedOrFinishedResponse called twice for the same res!");
|
||||||
|
} else {
|
||||||
|
console.log('Stream was closed, openStreams: ' + --openStreams);
|
||||||
|
console.timeEnd(res.id);
|
||||||
|
readStream.destroy();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* Mark this response already accounted for */
|
||||||
|
//res.id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
//permit to login on application. Return token to connect on Websocket IO.
|
//permit to login on application. Return token to connect on Websocket IO.
|
||||||
login(){
|
login(){
|
||||||
// For now, let's completely forget the /login route.
|
this.App.options("/login", (res: HttpResponse, req: HttpRequest) => {
|
||||||
this.App.post("/login", (req: Request, res: Response) => {
|
this.addCorsHeaders(res);
|
||||||
const param = req.body;
|
|
||||||
/*if(!param.name){
|
res.end();
|
||||||
return res.status(BAD_REQUEST).send({
|
});
|
||||||
message: "email parameter is empty"
|
|
||||||
});
|
this.App.post("/login", async (res: HttpResponse, req: HttpRequest) => {
|
||||||
}*/
|
this.addCorsHeaders(res);
|
||||||
//TODO check user email for The Coding Machine game
|
|
||||||
|
res.onAborted(() => {
|
||||||
|
console.warn('Login request was aborted');
|
||||||
|
})
|
||||||
|
const param = await res.json();
|
||||||
const userUuid = uuid();
|
const userUuid = uuid();
|
||||||
const token = Jwt.sign({name: param.name, userUuid: userUuid} as TokenInterface, SECRET_KEY, {expiresIn: '24h'});
|
const token = Jwt.sign({name: param.name, userUuid: userUuid} as TokenInterface, SECRET_KEY, {expiresIn: '24h'});
|
||||||
return res.status(OK).send({
|
res.writeStatus("200 OK").end(JSON.stringify({
|
||||||
token: token,
|
token: token,
|
||||||
mapUrlStart: URL_ROOM_STARTED,
|
mapUrlStart: URL_ROOM_STARTED,
|
||||||
userId: userUuid,
|
userId: userUuid,
|
||||||
});
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
back/src/Controller/BaseController.ts
Normal file
10
back/src/Controller/BaseController.ts
Normal 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', '*');
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
import socketIO = require('socket.io');
|
|
||||||
import {Socket} from "socket.io";
|
|
||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
import {MessageUserPosition, Point} from "../Model/Websocket/MessageUserPosition"; //TODO fix import by "_Model/.."
|
import {MessageUserPosition, Point} from "../Model/Websocket/MessageUserPosition"; //TODO fix import by "_Model/.."
|
||||||
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
||||||
@ -32,11 +30,19 @@ import {
|
|||||||
GroupDeleteMessage,
|
GroupDeleteMessage,
|
||||||
UserJoinedMessage,
|
UserJoinedMessage,
|
||||||
UserLeftMessage,
|
UserLeftMessage,
|
||||||
ItemEventMessage, ViewportMessage
|
ItemEventMessage,
|
||||||
|
ViewportMessage,
|
||||||
|
ClientToServerMessage,
|
||||||
|
JoinRoomMessage,
|
||||||
|
ErrorMessage,
|
||||||
|
RoomJoinedMessage,
|
||||||
|
ItemStateMessage,
|
||||||
|
ServerToClientMessage, SetUserIdMessage, SilentMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
|
import {App, TemplatedApp, WebSocket} from "uWebSockets.js"
|
||||||
|
|
||||||
enum SocketIoEvent {
|
enum SocketIoEvent {
|
||||||
CONNECTION = "connection",
|
CONNECTION = "connection",
|
||||||
@ -59,12 +65,18 @@ enum SocketIoEvent {
|
|||||||
BATCH = "batch",
|
BATCH = "batch",
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitInBatch(socket: ExSocketInterface, event: string, payload: SubMessage): void {
|
function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
||||||
|
if (socket.disconnecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
socket.batchedMessages.addPayload(payload);
|
socket.batchedMessages.addPayload(payload);
|
||||||
|
|
||||||
if (socket.batchTimeout === null) {
|
if (socket.batchTimeout === null) {
|
||||||
socket.batchTimeout = setTimeout(() => {
|
socket.batchTimeout = setTimeout(() => {
|
||||||
socket./*binary(true).*/emit(SocketIoEvent.BATCH, socket.batchedMessages.serializeBinary().buffer);
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setBatchmessage(socket.batchedMessages);
|
||||||
|
|
||||||
|
socket.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
socket.batchedMessages = new BatchMessage();
|
socket.batchedMessages = new BatchMessage();
|
||||||
socket.batchTimeout = null;
|
socket.batchTimeout = null;
|
||||||
}, 100);
|
}, 100);
|
||||||
@ -72,15 +84,14 @@ function emitInBatch(socket: ExSocketInterface, event: string, payload: SubMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
public readonly Io: socketIO.Server;
|
|
||||||
private Worlds: Map<string, World> = new Map<string, World>();
|
private Worlds: Map<string, World> = new Map<string, World>();
|
||||||
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
||||||
private nbClientsGauge: Gauge<string>;
|
private nbClientsGauge: Gauge<string>;
|
||||||
private nbClientsPerRoomGauge: Gauge<string>;
|
private nbClientsPerRoomGauge: Gauge<string>;
|
||||||
private nextUserId: number = 1;
|
private nextUserId: number = 1;
|
||||||
|
|
||||||
constructor(server: http.Server) {
|
constructor(private readonly app: TemplatedApp) {
|
||||||
this.Io = socketIO(server);
|
|
||||||
this.nbClientsGauge = new Gauge({
|
this.nbClientsGauge = new Gauge({
|
||||||
name: 'workadventure_nb_sockets',
|
name: 'workadventure_nb_sockets',
|
||||||
help: 'Number of connected sockets',
|
help: 'Number of connected sockets',
|
||||||
@ -92,52 +103,6 @@ export class IoSocketController {
|
|||||||
labelNames: [ 'room' ]
|
labelNames: [ 'room' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Authentication with token. it will be decoded and stored in the socket.
|
|
||||||
// Completely commented for now, as we do not use the "/login" route at all.
|
|
||||||
this.Io.use((socket: Socket, next) => {
|
|
||||||
//console.log(socket.handshake.query.token);
|
|
||||||
if (!socket.handshake.query || !socket.handshake.query.token) {
|
|
||||||
console.error('An authentication error happened, a user tried to connect without a token.');
|
|
||||||
return next(new Error('Authentication error'));
|
|
||||||
}
|
|
||||||
if(socket.handshake.query.token === 'test'){
|
|
||||||
if (ALLOW_ARTILLERY) {
|
|
||||||
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
|
||||||
(socket as ExSocketInterface).userId = this.nextUserId;
|
|
||||||
(socket as ExSocketInterface).userUuid = uuid();
|
|
||||||
this.nextUserId++;
|
|
||||||
(socket as ExSocketInterface).isArtillery = true;
|
|
||||||
console.log((socket as ExSocketInterface).userId);
|
|
||||||
next();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
console.warn("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(socket as ExSocketInterface).isArtillery = false;
|
|
||||||
if(this.searchClientByToken(socket.handshake.query.token)){
|
|
||||||
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
|
|
||||||
return next(new Error('Authentication error'));
|
|
||||||
}
|
|
||||||
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
|
||||||
return next(new Error('Authentication error'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.isValidToken(tokenDecoded)) {
|
|
||||||
return next(new Error('Authentication error, invalid token structure'));
|
|
||||||
}
|
|
||||||
|
|
||||||
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
|
||||||
(socket as ExSocketInterface).userId = this.nextUserId;
|
|
||||||
(socket as ExSocketInterface).userUuid = tokenDecoded.userUuid;
|
|
||||||
this.nextUserId++;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ioConnection();
|
this.ioConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,201 +132,107 @@ export class IoSocketController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ioConnection() {
|
private authenticate(ws: WebSocket) {
|
||||||
this.Io.on(SocketIoEvent.CONNECTION, (socket: Socket) => {
|
//console.log(socket.handshake.query.token);
|
||||||
const client : ExSocketInterface = socket as ExSocketInterface;
|
|
||||||
client.batchedMessages = new BatchMessage();
|
/*if (!socket.handshake.query || !socket.handshake.query.token) {
|
||||||
client.batchTimeout = null;
|
console.error('An authentication error happened, a user tried to connect without a token.');
|
||||||
client.emitInBatch = (event: string, payload: SubMessage): void => {
|
return next(new Error('Authentication error'));
|
||||||
emitInBatch(client, event, payload);
|
}
|
||||||
|
if(socket.handshake.query.token === 'test'){
|
||||||
|
if (ALLOW_ARTILLERY) {
|
||||||
|
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
||||||
|
(socket as ExSocketInterface).userId = this.nextUserId;
|
||||||
|
(socket as ExSocketInterface).userUuid = uuid();
|
||||||
|
this.nextUserId++;
|
||||||
|
(socket as ExSocketInterface).isArtillery = true;
|
||||||
|
console.log((socket as ExSocketInterface).userId);
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.warn("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(socket as ExSocketInterface).isArtillery = false;
|
||||||
|
if(this.searchClientByToken(socket.handshake.query.token)){
|
||||||
|
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
|
||||||
|
return next(new Error('Authentication error'));
|
||||||
|
}
|
||||||
|
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
||||||
|
return next(new Error('Authentication error'));
|
||||||
}
|
}
|
||||||
this.sockets.set(client.userId, client);
|
|
||||||
|
|
||||||
// Let's log server load when a user joins
|
if (!this.isValidToken(tokenDecoded)) {
|
||||||
const srvSockets = this.Io.sockets.sockets;
|
return next(new Error('Authentication error, invalid token structure'));
|
||||||
this.nbClientsGauge.inc();
|
}
|
||||||
console.log(new Date().toISOString() + ' A user joined (', Object.keys(srvSockets).length, ' connected users)');
|
|
||||||
//si.currentLoad().then(data => console.log(' Current load: ', data.avgload));
|
|
||||||
//si.currentLoad().then(data => console.log(' CPU: ', data.currentload, '%'));
|
|
||||||
// End log server load
|
|
||||||
|
|
||||||
/*join-rom event permit to join one room.
|
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
||||||
message :
|
(socket as ExSocketInterface).userId = this.nextUserId;
|
||||||
userId : user identification
|
(socket as ExSocketInterface).userUuid = tokenDecoded.userUuid;
|
||||||
roomId: room identification
|
this.nextUserId++;
|
||||||
position: position of user in map
|
next();
|
||||||
x: user x position on map
|
});*/
|
||||||
y: user y position on map
|
const socket = ws as ExSocketInterface;
|
||||||
*/
|
socket.userId = this.nextUserId;
|
||||||
socket.on(SocketIoEvent.JOIN_ROOM, (message: unknown, answerFn): void => {
|
this.nextUserId++;
|
||||||
//console.log(SocketIoEvent.JOIN_ROOM, message);
|
}
|
||||||
try {
|
|
||||||
if (!isJoinRoomMessageInterface(message)) {
|
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid JOIN_ROOM message.'});
|
|
||||||
console.warn('Invalid JOIN_ROOM message received: ', message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const roomId = message.roomId;
|
|
||||||
|
|
||||||
const Client = (socket as ExSocketInterface);
|
ioConnection() {
|
||||||
|
this.app.ws('/*', {
|
||||||
|
/* Options */
|
||||||
|
//compression: uWS.SHARED_COMPRESSOR,
|
||||||
|
maxPayloadLength: 16 * 1024 * 1024,
|
||||||
|
idleTimeout: 10,
|
||||||
|
/* Handlers */
|
||||||
|
open: (ws) => {
|
||||||
|
this.authenticate(ws);
|
||||||
|
// TODO: close if authenticate is ko
|
||||||
|
|
||||||
if (Client.roomId === roomId) {
|
const client : ExSocketInterface = ws as ExSocketInterface;
|
||||||
return;
|
client.batchedMessages = new BatchMessage();
|
||||||
}
|
client.batchTimeout = null;
|
||||||
|
client.emitInBatch = (payload: SubMessage): void => {
|
||||||
//leave previous room
|
emitInBatch(client, payload);
|
||||||
this.leaveRoom(Client);
|
|
||||||
|
|
||||||
//join new previous room
|
|
||||||
const world = this.joinRoom(Client, roomId, message.position);
|
|
||||||
|
|
||||||
const things = world.setViewport(Client, message.viewport);
|
|
||||||
|
|
||||||
const listOfUsers: Array<MessageUserPosition> = [];
|
|
||||||
const listOfGroups: Array<GroupUpdateInterface> = [];
|
|
||||||
|
|
||||||
for (const thing of things) {
|
|
||||||
if (thing instanceof User) {
|
|
||||||
const player: ExSocketInterface|undefined = this.sockets.get(thing.id);
|
|
||||||
if (player === undefined) {
|
|
||||||
console.warn('Something went wrong. The World contains a user "'+thing.id+"' but this user does not exist in the sockets list!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
listOfUsers.push(new MessageUserPosition(thing.id, player.name, player.characterLayers, player.position));
|
|
||||||
} else if (thing instanceof Group) {
|
|
||||||
listOfGroups.push({
|
|
||||||
groupId: thing.getId(),
|
|
||||||
position: thing.getPosition(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error("Unexpected type for Movable returned by setViewport");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const listOfItems: {[itemId: string]: unknown} = {};
|
|
||||||
for (const [itemId, item] of world.getItemsState().entries()) {
|
|
||||||
listOfItems[itemId] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.warn('ANSWER PLAYER POSITIONS', listOfUsers);
|
|
||||||
if (answerFn === undefined && ALLOW_ARTILLERY === true) {
|
|
||||||
// For some reason, answerFn can be undefined if we use Artillery (?)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
answerFn({
|
|
||||||
users: listOfUsers,
|
|
||||||
groups: listOfGroups,
|
|
||||||
items: listOfItems
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error('An error occurred on "join_room" event');
|
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
});
|
client.disconnecting = false;
|
||||||
|
this.sockets.set(client.userId, client);
|
||||||
|
|
||||||
socket.on(SocketIoEvent.SET_VIEWPORT, (message: unknown): void => {
|
// Let's log server load when a user joins
|
||||||
try {
|
this.nbClientsGauge.inc();
|
||||||
if (!(message instanceof Buffer)) {
|
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid SET_VIEWPORT message. Expecting binary buffer.'});
|
|
||||||
console.warn('Invalid SET_VIEWPORT message received (expecting binary buffer): ', message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewportMessage = ViewportMessage.deserializeBinary(new Uint8Array(message as ArrayBuffer));
|
},
|
||||||
const viewport = viewportMessage.toObject();
|
message: (ws, arrayBuffer, isBinary) => {
|
||||||
|
const client = ws as ExSocketInterface;
|
||||||
|
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
||||||
|
|
||||||
const Client = (socket as ExSocketInterface);
|
if (message.hasJoinroommessage()) {
|
||||||
Client.viewport = viewport;
|
this.handleJoinRoom(client, message.getJoinroommessage() as JoinRoomMessage);
|
||||||
|
} else if (message.hasViewportmessage()) {
|
||||||
const world = this.Worlds.get(Client.roomId);
|
this.handleViewport(client, message.getViewportmessage() as ViewportMessage);
|
||||||
if (!world) {
|
} else if (message.hasUsermovesmessage()) {
|
||||||
console.error("In SET_VIEWPORT, could not find world with id '", Client.roomId, "'");
|
this.handleUserMovesMessage(client, message.getUsermovesmessage() as UserMovesMessage);
|
||||||
return;
|
} else if (message.hasSetplayerdetailsmessage()) {
|
||||||
}
|
this.handleSetPlayerDetails(client, message.getSetplayerdetailsmessage() as SetPlayerDetailsMessage);
|
||||||
world.setViewport(Client, Client.viewport);
|
} else if (message.hasSilentmessage()) {
|
||||||
} catch (e) {
|
this.handleSilentMessage(client, message.getSilentmessage() as SilentMessage);
|
||||||
console.error('An error occurred on "SET_VIEWPORT" event');
|
} else if (message.hasItemeventmessage()) {
|
||||||
console.error(e);
|
this.handleItemEvent(client, message.getItemeventmessage() as ItemEventMessage);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
socket.on(SocketIoEvent.USER_POSITION, (message: unknown): void => {
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
//console.log(SockerIoEvent.USER_POSITION, userMovesMessage);
|
//let ok = ws.send(message, isBinary);
|
||||||
try {
|
},
|
||||||
if (!(message instanceof Buffer)) {
|
drain: (ws) => {
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid USER_POSITION message. Expecting binary buffer.'});
|
console.log('WebSocket backpressure: ' + ws.getBufferedAmount());
|
||||||
console.warn('Invalid USER_POSITION message received (expecting binary buffer): ', message);
|
},
|
||||||
return;
|
close: (ws, code, message) => {
|
||||||
}
|
const Client = (ws as ExSocketInterface);
|
||||||
|
|
||||||
const userMovesMessage = UserMovesMessage.deserializeBinary(new Uint8Array(message as ArrayBuffer));
|
|
||||||
const userMoves = userMovesMessage.toObject();
|
|
||||||
|
|
||||||
const position = userMoves.position;
|
|
||||||
if (position === undefined) {
|
|
||||||
throw new Error('Position not found in message');
|
|
||||||
}
|
|
||||||
const viewport = userMoves.viewport;
|
|
||||||
if (viewport === undefined) {
|
|
||||||
throw new Error('Viewport not found in message');
|
|
||||||
}
|
|
||||||
|
|
||||||
let direction: string;
|
|
||||||
switch (position.direction) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
const Client = (socket as ExSocketInterface);
|
|
||||||
|
|
||||||
// sending to all clients in room except sender
|
|
||||||
Client.position = {
|
|
||||||
x: position.x,
|
|
||||||
y: position.y,
|
|
||||||
direction,
|
|
||||||
moving: position.moving,
|
|
||||||
};
|
|
||||||
Client.viewport = viewport;
|
|
||||||
|
|
||||||
// update position in the world
|
|
||||||
const world = this.Worlds.get(Client.roomId);
|
|
||||||
if (!world) {
|
|
||||||
console.error("In USER_POSITION, could not find world with id '", Client.roomId, "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
world.updatePosition(Client, Client.position);
|
|
||||||
world.setViewport(Client, Client.viewport);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('An error occurred on "user_position" event');
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on(SocketIoEvent.WEBRTC_SIGNAL, (data: unknown) => {
|
|
||||||
this.emitVideo((socket as ExSocketInterface), data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on(SocketIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => {
|
|
||||||
this.emitScreenSharing((socket as ExSocketInterface), data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on(SocketIoEvent.DISCONNECT, () => {
|
|
||||||
const Client = (socket as ExSocketInterface);
|
|
||||||
try {
|
try {
|
||||||
|
Client.disconnecting = true;
|
||||||
//leave room
|
//leave room
|
||||||
this.leaveRoom(Client);
|
this.leaveRoom(Client);
|
||||||
|
|
||||||
@ -377,112 +248,251 @@ export class IoSocketController {
|
|||||||
console.error('An error occurred on "disconnect"');
|
console.error('An error occurred on "disconnect"');
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sockets.delete(Client.userId);
|
this.sockets.delete(Client.userId);
|
||||||
|
|
||||||
// Let's log server load when a user leaves
|
// Let's log server load when a user leaves
|
||||||
const srvSockets = this.Io.sockets.sockets;
|
|
||||||
this.nbClientsGauge.dec();
|
this.nbClientsGauge.dec();
|
||||||
console.log('A user left (', Object.keys(srvSockets).length, ' connected users)');
|
console.log('A user left (', this.sockets.size, ' connected users)');
|
||||||
//si.currentLoad().then(data => console.log('Current load: ', data.avgload));
|
}
|
||||||
//si.currentLoad().then(data => console.log('CPU: ', data.currentload, '%'));
|
})
|
||||||
// End log server load
|
|
||||||
|
// TODO: finish this!
|
||||||
|
/*this.Io.on(SocketIoEvent.CONNECTION, (socket: Socket) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
socket.on(SocketIoEvent.WEBRTC_SIGNAL, (data: unknown) => {
|
||||||
|
this.emitVideo((socket as ExSocketInterface), data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Let's send the user id to the user
|
socket.on(SocketIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => {
|
||||||
socket.on(SocketIoEvent.SET_PLAYER_DETAILS, (message: unknown, answerFn) => {
|
this.emitScreenSharing((socket as ExSocketInterface), data);
|
||||||
//console.log(SocketIoEvent.SET_PLAYER_DETAILS, message);
|
|
||||||
if (!(message instanceof Buffer)) {
|
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid SET_PLAYER_DETAILS message. Expecting binary buffer.'});
|
|
||||||
console.warn('Invalid SET_PLAYER_DETAILS message received (expecting binary buffer): ', message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const playerDetailsMessage = SetPlayerDetailsMessage.deserializeBinary(new Uint8Array(message));
|
|
||||||
const playerDetails = {
|
|
||||||
name: playerDetailsMessage.getName(),
|
|
||||||
characterLayers: playerDetailsMessage.getCharacterlayersList()
|
|
||||||
};
|
|
||||||
//console.log(SocketIoEvent.SET_PLAYER_DETAILS, playerDetails);
|
|
||||||
if (!isSetPlayerDetailsMessage(playerDetails)) {
|
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid SET_PLAYER_DETAILS message.'});
|
|
||||||
console.warn('Invalid SET_PLAYER_DETAILS message received: ', playerDetails);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const Client = (socket as ExSocketInterface);
|
|
||||||
Client.name = playerDetails.name;
|
|
||||||
Client.characterLayers = playerDetails.characterLayers;
|
|
||||||
// Artillery fails when receiving an acknowledgement that is not a JSON object
|
|
||||||
if (!Client.isArtillery) {
|
|
||||||
answerFn(Client.userId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on(SocketIoEvent.SET_SILENT, (silent: unknown) => {
|
});*/
|
||||||
//console.log(SocketIoEvent.SET_SILENT, silent);
|
}
|
||||||
if (typeof silent !== "boolean") {
|
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid SET_SILENT message.'});
|
|
||||||
console.warn('Invalid SET_SILENT message received: ', silent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
private emitError(Client: ExSocketInterface, message: string): void {
|
||||||
const Client = (socket as ExSocketInterface);
|
const errorMessage = new ErrorMessage();
|
||||||
|
errorMessage.setMessage(message);
|
||||||
|
|
||||||
// update position in the world
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
const world = this.Worlds.get(Client.roomId);
|
serverToClientMessage.setErrormessage(errorMessage);
|
||||||
if (!world) {
|
|
||||||
console.error("In SET_SILENT, could not find world with id '", Client.roomId, "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
world.setSilent(Client, silent);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('An error occurred on "SET_SILENT"');
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on(SocketIoEvent.ITEM_EVENT, (message: unknown) => {
|
if (!Client.disconnecting) {
|
||||||
if (!(message instanceof Buffer)) {
|
Client.send(serverToClientMessage.serializeBinary().buffer);
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid ITEM_EVENT message. Expecting binary buffer.'});
|
}
|
||||||
console.warn('Invalid ITEM_EVENT message received (expecting binary buffer): ', message);
|
console.warn(message);
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
const itemEventMessage = ItemEventMessage.deserializeBinary(new Uint8Array(message));
|
|
||||||
|
|
||||||
const itemEvent = ProtobufUtils.toItemEvent(itemEventMessage);
|
private handleJoinRoom(Client: ExSocketInterface, message: JoinRoomMessage): void {
|
||||||
|
try {
|
||||||
|
/*if (!isJoinRoomMessageInterface(message.toObject())) {
|
||||||
|
console.log(message.toObject())
|
||||||
|
this.emitError(Client, 'Invalid JOIN_ROOM message received: ' + message.toObject().toString());
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
const roomId = message.getRoomid();
|
||||||
|
|
||||||
/*if (!isItemEventMessageInterface(itemEvent)) {
|
if (Client.roomId === roomId) {
|
||||||
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid ITEM_EVENT message.'});
|
return;
|
||||||
console.warn('Invalid ITEM_EVENT message received: ', itemEvent);
|
}
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
try {
|
|
||||||
const Client = (socket as ExSocketInterface);
|
|
||||||
|
|
||||||
//socket.to(Client.roomId).emit(SocketIoEvent.ITEM_EVENT, itemEvent);
|
//leave previous room
|
||||||
|
this.leaveRoom(Client);
|
||||||
|
|
||||||
const world = this.Worlds.get(Client.roomId);
|
//join new previous room
|
||||||
if (!world) {
|
const world = this.joinRoom(Client, roomId, ProtobufUtils.toPointInterface(message.getPosition() as PositionMessage));
|
||||||
console.error("Could not find world with id '", Client.roomId, "'");
|
|
||||||
return;
|
const things = world.setViewport(Client, (message.getViewport() as ViewportMessage).toObject());
|
||||||
|
|
||||||
|
const roomJoinedMessage = new RoomJoinedMessage();
|
||||||
|
|
||||||
|
for (const thing of things) {
|
||||||
|
if (thing instanceof User) {
|
||||||
|
const player: ExSocketInterface|undefined = this.sockets.get(thing.id);
|
||||||
|
if (player === undefined) {
|
||||||
|
console.warn('Something went wrong. The World contains a user "'+thing.id+"' but this user does not exist in the sockets list!");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const subMessage = new SubMessage();
|
const userJoinedMessage = new UserJoinedMessage();
|
||||||
subMessage.setItemeventmessage(itemEventMessage);
|
userJoinedMessage.setUserid(thing.id);
|
||||||
|
userJoinedMessage.setName(player.name);
|
||||||
|
userJoinedMessage.setCharacterlayersList(player.characterLayers);
|
||||||
|
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
||||||
|
|
||||||
// Let's send the event without using the SocketIO room.
|
roomJoinedMessage.addUser(userJoinedMessage);
|
||||||
for (const user of world.getUsers().values()) {
|
} else if (thing instanceof Group) {
|
||||||
const client = this.searchClientByIdOrFail(user.id);
|
const groupUpdateMessage = new GroupUpdateMessage();
|
||||||
//client.emit(SocketIoEvent.ITEM_EVENT, itemEvent);
|
groupUpdateMessage.setGroupid(thing.getId());
|
||||||
emitInBatch(client, SocketIoEvent.ITEM_EVENT, subMessage);
|
groupUpdateMessage.setPosition(ProtobufUtils.toPointMessage(thing.getPosition()));
|
||||||
}
|
|
||||||
|
|
||||||
world.setItemState(itemEvent.itemId, itemEvent.state);
|
roomJoinedMessage.addGroup(groupUpdateMessage);
|
||||||
} catch (e) {
|
} else {
|
||||||
console.error('An error occurred on "item_event"');
|
console.error("Unexpected type for Movable returned by setViewport");
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
for (const [itemId, item] of world.getItemsState().entries()) {
|
||||||
|
const itemStateMessage = new ItemStateMessage();
|
||||||
|
itemStateMessage.setItemid(itemId);
|
||||||
|
itemStateMessage.setStatejson(JSON.stringify(item));
|
||||||
|
|
||||||
|
roomJoinedMessage.addItem(itemStateMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
||||||
|
|
||||||
|
if (!Client.disconnecting) {
|
||||||
|
Client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('An error occurred on "join_room" event');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleViewport(client: ExSocketInterface, viewportMessage: ViewportMessage) {
|
||||||
|
try {
|
||||||
|
const viewport = viewportMessage.toObject();
|
||||||
|
|
||||||
|
client.viewport = viewport;
|
||||||
|
|
||||||
|
const world = this.Worlds.get(client.roomId);
|
||||||
|
if (!world) {
|
||||||
|
console.error("In SET_VIEWPORT, could not find world with id '", client.roomId, "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
world.setViewport(client, client.viewport);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('An error occurred on "SET_VIEWPORT" event');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleUserMovesMessage(client: ExSocketInterface, userMovesMessage: UserMovesMessage) {
|
||||||
|
//console.log(SockerIoEvent.USER_POSITION, userMovesMessage);
|
||||||
|
try {
|
||||||
|
const userMoves = userMovesMessage.toObject();
|
||||||
|
|
||||||
|
const position = userMoves.position;
|
||||||
|
if (position === undefined) {
|
||||||
|
throw new Error('Position not found in message');
|
||||||
|
}
|
||||||
|
const viewport = userMoves.viewport;
|
||||||
|
if (viewport === undefined) {
|
||||||
|
throw new Error('Viewport not found in message');
|
||||||
|
}
|
||||||
|
|
||||||
|
let direction: string;
|
||||||
|
switch (position.direction) {
|
||||||
|
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
|
||||||
|
client.position = {
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
direction,
|
||||||
|
moving: position.moving,
|
||||||
|
};
|
||||||
|
client.viewport = viewport;
|
||||||
|
|
||||||
|
// update position in the world
|
||||||
|
const world = this.Worlds.get(client.roomId);
|
||||||
|
if (!world) {
|
||||||
|
console.error("In USER_POSITION, could not find world with id '", client.roomId, "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
world.updatePosition(client, client.position);
|
||||||
|
world.setViewport(client, client.viewport);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('An error occurred on "user_position" event');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSetPlayerDetails(client: ExSocketInterface, playerDetailsMessage: SetPlayerDetailsMessage) {
|
||||||
|
const playerDetails = {
|
||||||
|
name: playerDetailsMessage.getName(),
|
||||||
|
characterLayers: playerDetailsMessage.getCharacterlayersList()
|
||||||
|
};
|
||||||
|
//console.log(SocketIoEvent.SET_PLAYER_DETAILS, playerDetails);
|
||||||
|
if (!isSetPlayerDetailsMessage(playerDetails)) {
|
||||||
|
this.emitError(client, 'Invalid SET_PLAYER_DETAILS message received: ');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.name = playerDetails.name;
|
||||||
|
client.characterLayers = playerDetails.characterLayers;
|
||||||
|
|
||||||
|
|
||||||
|
const setUserIdMessage = new SetUserIdMessage();
|
||||||
|
setUserIdMessage.setUserid(client.userId);
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setSetuseridmessage(setUserIdMessage);
|
||||||
|
|
||||||
|
if (!client.disconnecting) {
|
||||||
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSilentMessage(client: ExSocketInterface, silentMessage: SilentMessage) {
|
||||||
|
try {
|
||||||
|
// update position in the world
|
||||||
|
const world = this.Worlds.get(client.roomId);
|
||||||
|
if (!world) {
|
||||||
|
console.error("In handleSilentMessage, could not find world with id '", client.roomId, "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
world.setSilent(client, silentMessage.getSilent());
|
||||||
|
} catch (e) {
|
||||||
|
console.error('An error occurred on "handleSilentMessage"');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleItemEvent(ws: ExSocketInterface, itemEventMessage: ItemEventMessage) {
|
||||||
|
const itemEvent = ProtobufUtils.toItemEvent(itemEventMessage);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const world = this.Worlds.get(ws.roomId);
|
||||||
|
if (!world) {
|
||||||
|
console.error("Could not find world with id '", ws.roomId, "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subMessage = new SubMessage();
|
||||||
|
subMessage.setItemeventmessage(itemEventMessage);
|
||||||
|
|
||||||
|
// Let's send the event without using the SocketIO room.
|
||||||
|
for (const user of world.getUsers().values()) {
|
||||||
|
const client = this.searchClientByIdOrFail(user.id);
|
||||||
|
//client.emit(SocketIoEvent.ITEM_EVENT, itemEvent);
|
||||||
|
emitInBatch(client, subMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
world.setItemState(itemEvent.itemId, itemEvent.state);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('An error occurred on "item_event"');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitVideo(socket: ExSocketInterface, data: unknown){
|
emitVideo(socket: ExSocketInterface, data: unknown){
|
||||||
@ -542,7 +552,7 @@ export class IoSocketController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//user leave previous room
|
//user leave previous room
|
||||||
Client.leave(Client.roomId);
|
//Client.leave(Client.roomId);
|
||||||
} finally {
|
} finally {
|
||||||
this.nbClientsPerRoomGauge.dec({ room: Client.roomId });
|
this.nbClientsPerRoomGauge.dec({ room: Client.roomId });
|
||||||
delete Client.roomId;
|
delete Client.roomId;
|
||||||
@ -552,7 +562,7 @@ export class IoSocketController {
|
|||||||
|
|
||||||
private joinRoom(Client : ExSocketInterface, roomId: string, position: PointInterface): World {
|
private joinRoom(Client : ExSocketInterface, roomId: string, position: PointInterface): World {
|
||||||
//join user in room
|
//join user in room
|
||||||
Client.join(roomId);
|
//Client.join(roomId);
|
||||||
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
||||||
Client.roomId = roomId;
|
Client.roomId = roomId;
|
||||||
Client.position = position;
|
Client.position = position;
|
||||||
@ -570,6 +580,9 @@ export class IoSocketController {
|
|||||||
const clientUser = this.searchClientByIdOrFail(thing.id);
|
const clientUser = this.searchClientByIdOrFail(thing.id);
|
||||||
|
|
||||||
const userJoinedMessage = new UserJoinedMessage();
|
const userJoinedMessage = new UserJoinedMessage();
|
||||||
|
if (!Number.isInteger(clientUser.userId)) {
|
||||||
|
throw new Error('clientUser.userId is not an integer '+clientUser.userId);
|
||||||
|
}
|
||||||
userJoinedMessage.setUserid(clientUser.userId);
|
userJoinedMessage.setUserid(clientUser.userId);
|
||||||
userJoinedMessage.setName(clientUser.name);
|
userJoinedMessage.setName(clientUser.name);
|
||||||
userJoinedMessage.setCharacterlayersList(clientUser.characterLayers);
|
userJoinedMessage.setCharacterlayersList(clientUser.characterLayers);
|
||||||
@ -578,7 +591,7 @@ export class IoSocketController {
|
|||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setUserjoinedmessage(userJoinedMessage);
|
subMessage.setUserjoinedmessage(userJoinedMessage);
|
||||||
|
|
||||||
emitInBatch(clientListener, SocketIoEvent.JOIN_ROOM, subMessage);
|
emitInBatch(clientListener, subMessage);
|
||||||
} else if (thing instanceof Group) {
|
} else if (thing instanceof Group) {
|
||||||
this.emitCreateUpdateGroupEvent(clientListener, thing);
|
this.emitCreateUpdateGroupEvent(clientListener, thing);
|
||||||
} else {
|
} else {
|
||||||
@ -596,7 +609,7 @@ export class IoSocketController {
|
|||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setUsermovedmessage(userMovedMessage);
|
subMessage.setUsermovedmessage(userMovedMessage);
|
||||||
|
|
||||||
clientListener.emitInBatch(SocketIoEvent.USER_MOVED, subMessage);
|
clientListener.emitInBatch(subMessage);
|
||||||
//console.log("Sending USER_MOVED event");
|
//console.log("Sending USER_MOVED event");
|
||||||
} else if (thing instanceof Group) {
|
} else if (thing instanceof Group) {
|
||||||
this.emitCreateUpdateGroupEvent(clientListener, thing);
|
this.emitCreateUpdateGroupEvent(clientListener, thing);
|
||||||
@ -627,7 +640,7 @@ export class IoSocketController {
|
|||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitCreateUpdateGroupEvent(socket: Socket, group: Group): void {
|
private emitCreateUpdateGroupEvent(client: ExSocketInterface, group: Group): void {
|
||||||
const position = group.getPosition();
|
const position = group.getPosition();
|
||||||
const pointMessage = new PointMessage();
|
const pointMessage = new PointMessage();
|
||||||
pointMessage.setX(Math.floor(position.x));
|
pointMessage.setX(Math.floor(position.x));
|
||||||
@ -639,8 +652,7 @@ export class IoSocketController {
|
|||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setGroupupdatemessage(groupUpdateMessage);
|
subMessage.setGroupupdatemessage(groupUpdateMessage);
|
||||||
|
|
||||||
const client : ExSocketInterface = socket as ExSocketInterface;
|
emitInBatch(client, subMessage);
|
||||||
emitInBatch(client, SocketIoEvent.GROUP_CREATE_UPDATE, subMessage);
|
|
||||||
//socket.emit(SocketIoEvent.GROUP_CREATE_UPDATE, groupUpdateMessage.serializeBinary().buffer);
|
//socket.emit(SocketIoEvent.GROUP_CREATE_UPDATE, groupUpdateMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +664,7 @@ export class IoSocketController {
|
|||||||
subMessage.setGroupdeletemessage(groupDeleteMessage);
|
subMessage.setGroupdeletemessage(groupDeleteMessage);
|
||||||
|
|
||||||
const client : ExSocketInterface = socket as ExSocketInterface;
|
const client : ExSocketInterface = socket as ExSocketInterface;
|
||||||
emitInBatch(client, SocketIoEvent.GROUP_DELETE, subMessage);
|
emitInBatch(client, subMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitUserLeftEvent(socket: Socket, userId: number): void {
|
private emitUserLeftEvent(socket: Socket, userId: number): void {
|
||||||
@ -663,7 +675,7 @@ export class IoSocketController {
|
|||||||
subMessage.setUserleftmessage(userLeftMessage);
|
subMessage.setUserleftmessage(userLeftMessage);
|
||||||
|
|
||||||
const client : ExSocketInterface = socket as ExSocketInterface;
|
const client : ExSocketInterface = socket as ExSocketInterface;
|
||||||
emitInBatch(client, SocketIoEvent.USER_LEFT, subMessage);
|
emitInBatch(client, subMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -672,6 +684,10 @@ export class IoSocketController {
|
|||||||
* @param roomId
|
* @param roomId
|
||||||
*/
|
*/
|
||||||
joinWebRtcRoom(socket: ExSocketInterface, roomId: string) {
|
joinWebRtcRoom(socket: ExSocketInterface, roomId: string) {
|
||||||
|
|
||||||
|
// TODO: REBUILD THIS
|
||||||
|
return;
|
||||||
|
|
||||||
if (socket.webRtcRoomId === roomId) {
|
if (socket.webRtcRoomId === roomId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -734,6 +750,9 @@ export class IoSocketController {
|
|||||||
|
|
||||||
//disconnect user
|
//disconnect user
|
||||||
disConnectedUser(userId: number, group: Group) {
|
disConnectedUser(userId: number, group: Group) {
|
||||||
|
// TODO: rebuild this
|
||||||
|
return;
|
||||||
|
|
||||||
const Client = this.searchClientByIdOrFail(userId);
|
const Client = this.searchClientByIdOrFail(userId);
|
||||||
Client.to("webrtcroom"+group.getId()).emit(SocketIoEvent.WEBRTC_DISCONNECT, {
|
Client.to("webrtcroom"+group.getId()).emit(SocketIoEvent.WEBRTC_DISCONNECT, {
|
||||||
userId: userId
|
userId: userId
|
||||||
@ -761,4 +780,5 @@ export class IoSocketController {
|
|||||||
public getWorlds(): Map<string, World> {
|
public getWorlds(): Map<string, World> {
|
||||||
return this.Worlds;
|
return this.Worlds;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,33 @@
|
|||||||
import express from "express";
|
|
||||||
import {Application, Request, Response} from "express";
|
|
||||||
import {OK} from "http-status-codes";
|
import {OK} from "http-status-codes";
|
||||||
import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable";
|
import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable";
|
||||||
|
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
|
||||||
|
import {BaseController} from "./BaseController";
|
||||||
|
|
||||||
export class MapController {
|
export class MapController extends BaseController{
|
||||||
App: Application;
|
|
||||||
|
|
||||||
constructor(App: Application) {
|
constructor(private App : TemplatedApp) {
|
||||||
|
super();
|
||||||
this.App = App;
|
this.App = App;
|
||||||
this.getStartMap();
|
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
|
// Returns a map mapping map name to file name of the map
|
||||||
getStartMap() {
|
getStartMap() {
|
||||||
this.App.get("/start-map", (req: Request, res: Response) => {
|
this.App.options("/start-map", (res: HttpResponse, req: HttpRequest) => {
|
||||||
const url = req.headers.host?.replace('api.', 'maps.') + URL_ROOM_STARTED;
|
this.addCorsHeaders(res);
|
||||||
res.status(OK).send({
|
|
||||||
|
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,
|
mapUrlStart: url,
|
||||||
startInstance: "global"
|
startInstance: "global"
|
||||||
});
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import {Socket} from "socket.io";
|
|
||||||
import {PointInterface} from "./PointInterface";
|
import {PointInterface} from "./PointInterface";
|
||||||
import {Identificable} from "./Identificable";
|
import {Identificable} from "./Identificable";
|
||||||
import {TokenInterface} from "../../Controller/AuthenticateController";
|
import {TokenInterface} from "../../Controller/AuthenticateController";
|
||||||
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||||
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
|
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
|
||||||
|
import {WebSocket} from "uWebSockets.js"
|
||||||
|
|
||||||
export interface ExSocketInterface extends Socket, Identificable {
|
export interface ExSocketInterface extends WebSocket, Identificable {
|
||||||
token: string;
|
token: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
webRtcRoomId: string|undefined;
|
webRtcRoomId: string|undefined;
|
||||||
@ -19,7 +19,8 @@ export interface ExSocketInterface extends Socket, Identificable {
|
|||||||
/**
|
/**
|
||||||
* Pushes an event that will be sent in the next batch of events
|
* 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;
|
batchedMessages: BatchMessage;
|
||||||
batchTimeout: NodeJS.Timeout|null;
|
batchTimeout: NodeJS.Timeout|null;
|
||||||
|
disconnecting: boolean
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {PointInterface} from "./PointInterface";
|
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 {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {ItemEventMessageInterface} from "_Model/Websocket/ItemEventMessage";
|
import {ItemEventMessageInterface} from "_Model/Websocket/ItemEventMessage";
|
||||||
|
import {PositionInterface} from "_Model/PositionInterface";
|
||||||
|
|
||||||
export class ProtobufUtils {
|
export class ProtobufUtils {
|
||||||
|
|
||||||
@ -34,6 +35,42 @@ export class ProtobufUtils {
|
|||||||
return position;
|
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 {
|
public static toItemEvent(itemEventMessage: ItemEventMessage): ItemEventMessageInterface {
|
||||||
return {
|
return {
|
||||||
itemId: itemEventMessage.getItemid(),
|
itemId: itemEventMessage.getItemid(),
|
||||||
|
@ -74,8 +74,8 @@ export class World {
|
|||||||
this.users.delete(user.userId);
|
this.users.delete(user.userId);
|
||||||
|
|
||||||
if (userObj !== undefined) {
|
if (userObj !== undefined) {
|
||||||
this.positionNotifier.leave(userObj);
|
|
||||||
this.positionNotifier.removeViewport(userObj);
|
this.positionNotifier.removeViewport(userObj);
|
||||||
|
this.positionNotifier.leave(userObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
back/src/Server/server/app.ts
Normal file
13
back/src/Server/server/app.ts
Normal 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);
|
||||||
|
extend(this, new BaseApp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
220
back/src/Server/server/baseapp.ts
Normal file
220
back/src/Server/server/baseapp.ts
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
import { readdirSync, statSync } from 'fs';
|
||||||
|
import { join, relative } from 'path';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import { us_listen_socket_close, TemplatedApp, HttpResponse, HttpRequest } from 'uWebSockets.js';
|
||||||
|
//import { watch } from 'chokidar';
|
||||||
|
|
||||||
|
import { wsConfig } from './livereload';
|
||||||
|
import sendFile from './sendfile';
|
||||||
|
import formData from './formdata';
|
||||||
|
import loadroutes from './loadroutes';
|
||||||
|
import { graphqlPost, graphqlWs } from './graphql';
|
||||||
|
import { stob } from './utils';
|
||||||
|
import { SendFileOptions, Handler } from './types';
|
||||||
|
|
||||||
|
const contTypes = ['application/x-www-form-urlencoded', 'multipart/form-data'];
|
||||||
|
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;
|
||||||
|
|
||||||
|
this.onData((ab, isLast) => {
|
||||||
|
// uint and then slicing is bit faster than slice and then uint
|
||||||
|
stream.push(new Uint8Array(ab.slice(ab.byteOffset, ab.byteLength)));
|
||||||
|
if (isLast) {
|
||||||
|
stream.push(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
res.body = () => stob(res.bodyStream());
|
||||||
|
|
||||||
|
if (contType.indexOf('application/json') > -1)
|
||||||
|
res.json = async () => JSON.parse(await res.body());
|
||||||
|
if (contTypes.map(t => contType.indexOf(t) > -1).indexOf(true) > -1)
|
||||||
|
res.formData = formData.bind(res, contType);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseApp {
|
||||||
|
_staticPaths = new Map();
|
||||||
|
//_watched = new Map();
|
||||||
|
_sockets = new Map();
|
||||||
|
__livereloadenabled = false;
|
||||||
|
ws!: TemplatedApp['ws'];
|
||||||
|
get!: TemplatedApp['get'];
|
||||||
|
_post!: TemplatedApp['post'];
|
||||||
|
_put!: TemplatedApp['put'];
|
||||||
|
_patch!: TemplatedApp['patch'];
|
||||||
|
_listen!: TemplatedApp['listen'];
|
||||||
|
|
||||||
|
file(pattern: string, filePath: string, options: SendFileOptions = {}) {
|
||||||
|
pattern=pattern.replace(/\\/g,'/');
|
||||||
|
if (this._staticPaths.has(pattern)) {
|
||||||
|
if (options.failOnDuplicateRoute)
|
||||||
|
throw Error(
|
||||||
|
`Error serving '${filePath}' for '${pattern}', already serving '${
|
||||||
|
this._staticPaths.get(pattern)[0]
|
||||||
|
}' file for this pattern.`
|
||||||
|
);
|
||||||
|
else if (!options.overwriteRoute) return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.livereload && !this.__livereloadenabled) {
|
||||||
|
this.ws('/__sifrrLiveReload', wsConfig);
|
||||||
|
this.file('/livereload.js', join(__dirname, './livereloadjs.js'));
|
||||||
|
this.__livereloadenabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._staticPaths.set(pattern, [filePath, options]);
|
||||||
|
this.get(pattern, this._serveStatic);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
folder(prefix: string, folder: string, options: SendFileOptions, base: string = folder) {
|
||||||
|
// not a folder
|
||||||
|
if (!statSync(folder).isDirectory()) {
|
||||||
|
throw Error('Given path is not a directory: ' + folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure slash in beginning and no trailing slash for prefix
|
||||||
|
if (prefix[0] !== '/') prefix = '/' + prefix;
|
||||||
|
if (prefix[prefix.length - 1] === '/') prefix = prefix.slice(0, -1);
|
||||||
|
|
||||||
|
// serve folder
|
||||||
|
const filter = options ? options.filter || noOp : noOp;
|
||||||
|
readdirSync(folder).forEach(file => {
|
||||||
|
// Absolute path
|
||||||
|
const filePath = join(folder, file);
|
||||||
|
// Return if filtered
|
||||||
|
if (!filter(filePath)) return;
|
||||||
|
|
||||||
|
if (statSync(filePath).isDirectory()) {
|
||||||
|
// Recursive if directory
|
||||||
|
this.folder(prefix, filePath, options, base);
|
||||||
|
} else {
|
||||||
|
this.file(prefix + '/' + relative(base, filePath), filePath, options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*if (options && options.watch) {
|
||||||
|
if (!this._watched.has(folder)) {
|
||||||
|
const w = watch(folder);
|
||||||
|
|
||||||
|
w.on('unlink', filePath => {
|
||||||
|
const url = '/' + relative(base, filePath);
|
||||||
|
this._staticPaths.delete(prefix + url);
|
||||||
|
});
|
||||||
|
|
||||||
|
w.on('add', filePath => {
|
||||||
|
const url = '/' + relative(base, filePath);
|
||||||
|
this.file(prefix + url, filePath, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._watched.set(folder, w);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_serveStatic(res: HttpResponse, req: HttpRequest) {
|
||||||
|
res.onAborted(noOp);
|
||||||
|
const options = this._staticPaths.get(req.getUrl());
|
||||||
|
if (typeof options === 'undefined') {
|
||||||
|
res.writeStatus('404 Not Found');
|
||||||
|
res.end();
|
||||||
|
} else sendFile(res, req, options[0], options[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphql(route: string, schema, graphqlOptions: any = {}, uwsOptions = {}, graphql) {
|
||||||
|
const handler = graphqlPost(schema, graphqlOptions, graphql);
|
||||||
|
this.post(route, handler);
|
||||||
|
this.ws(route, graphqlWs(schema, graphqlOptions, uwsOptions, graphql));
|
||||||
|
// this.get(route, handler);
|
||||||
|
if (graphqlOptions && graphqlOptions.graphiqlPath)
|
||||||
|
this.file(graphqlOptions.graphiqlPath, join(__dirname, './graphiql.html'));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
load(dir: string, options) {
|
||||||
|
loadroutes.call(this, dir, options);
|
||||||
|
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) {
|
||||||
|
//this._watched.forEach(v => v.close());
|
||||||
|
//this._watched.clear();
|
||||||
|
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;
|
48
back/src/Server/server/cluster.ts
Normal file
48
back/src/Server/server/cluster.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const noop = (a, b) => {};
|
||||||
|
|
||||||
|
export default class Cluster {
|
||||||
|
apps: any[];
|
||||||
|
listens = {};
|
||||||
|
// apps = [ { app: SifrrServerApp, port/ports: int } ]
|
||||||
|
constructor(apps) {
|
||||||
|
if (!Array.isArray(apps)) apps = [apps];
|
||||||
|
this.apps = apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(onListen = noop) {
|
||||||
|
for (let i = 0; i < this.apps.length; i++) {
|
||||||
|
const config = this.apps[i];
|
||||||
|
let { app, port, ports } = config;
|
||||||
|
if (!Array.isArray(ports) || ports.length === 0) {
|
||||||
|
ports = [port];
|
||||||
|
}
|
||||||
|
ports.forEach(p => {
|
||||||
|
if (typeof p !== 'number') throw Error(`Port should be a number, given ${p}`);
|
||||||
|
if (this.listens[p]) return;
|
||||||
|
|
||||||
|
app.listen(p, socket => {
|
||||||
|
onListen.call(app, socket, p);
|
||||||
|
});
|
||||||
|
this.listens[p] = app;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAll() {
|
||||||
|
Object.keys(this.listens).forEach(port => {
|
||||||
|
this.close(port);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(port = null) {
|
||||||
|
if (port) {
|
||||||
|
this.listens[port] && this.listens[port].close(port);
|
||||||
|
delete this.listens[port];
|
||||||
|
} else {
|
||||||
|
this.closeAll();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
99
back/src/Server/server/formdata.ts
Normal file
99
back/src/Server/server/formdata.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { createWriteStream } from 'fs';
|
||||||
|
import { join, dirname } from 'path';
|
||||||
|
import Busboy from 'busboy';
|
||||||
|
import mkdirp from 'mkdirp';
|
||||||
|
|
||||||
|
function formData(
|
||||||
|
contType: string,
|
||||||
|
options: busboy.BusboyConfig & {
|
||||||
|
abortOnLimit?: boolean;
|
||||||
|
tmpDir?: string;
|
||||||
|
onFile?: (
|
||||||
|
fieldname: string,
|
||||||
|
file: NodeJS.ReadableStream,
|
||||||
|
filename: string,
|
||||||
|
encoding: string,
|
||||||
|
mimetype: string
|
||||||
|
) => string;
|
||||||
|
onField?: (fieldname: string, value: any) => void;
|
||||||
|
filename?: (oldName: string) => string;
|
||||||
|
} = {}
|
||||||
|
) {
|
||||||
|
options.headers = {
|
||||||
|
'content-type': contType
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const busb = new Busboy(options);
|
||||||
|
const ret = {};
|
||||||
|
|
||||||
|
this.bodyStream().pipe(busb);
|
||||||
|
|
||||||
|
busb.on('limit', () => {
|
||||||
|
if (options.abortOnLimit) {
|
||||||
|
reject(Error('limit'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
busb.on('file', function(fieldname, file, filename, encoding, mimetype) {
|
||||||
|
const value = {
|
||||||
|
filename,
|
||||||
|
encoding,
|
||||||
|
mimetype,
|
||||||
|
filePath: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof options.tmpDir === 'string') {
|
||||||
|
if (typeof options.filename === 'function') filename = options.filename(filename);
|
||||||
|
const fileToSave = join(options.tmpDir, filename);
|
||||||
|
mkdirp(dirname(fileToSave));
|
||||||
|
|
||||||
|
file.pipe(createWriteStream(fileToSave));
|
||||||
|
value.filePath = fileToSave;
|
||||||
|
}
|
||||||
|
if (typeof options.onFile === 'function') {
|
||||||
|
value.filePath =
|
||||||
|
options.onFile(fieldname, file, filename, encoding, mimetype) || value.filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
setRetValue(ret, fieldname, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
busb.on('field', function(fieldname, value) {
|
||||||
|
if (typeof options.onField === 'function') options.onField(fieldname, value);
|
||||||
|
|
||||||
|
setRetValue(ret, fieldname, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
busb.on('finish', function() {
|
||||||
|
resolve(ret);
|
||||||
|
});
|
||||||
|
|
||||||
|
busb.on('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRetValue(
|
||||||
|
ret: { [x: string]: any },
|
||||||
|
fieldname: string,
|
||||||
|
value: { filename: string; encoding: string; mimetype: string; filePath?: string } | any
|
||||||
|
) {
|
||||||
|
if (fieldname.slice(-2) === '[]') {
|
||||||
|
fieldname = fieldname.slice(0, fieldname.length - 2);
|
||||||
|
if (Array.isArray(ret[fieldname])) {
|
||||||
|
ret[fieldname].push(value);
|
||||||
|
} else {
|
||||||
|
ret[fieldname] = [value];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Array.isArray(ret[fieldname])) {
|
||||||
|
ret[fieldname].push(value);
|
||||||
|
} else if (ret[fieldname]) {
|
||||||
|
ret[fieldname] = [ret[fieldname], value];
|
||||||
|
} else {
|
||||||
|
ret[fieldname] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default formData;
|
133
back/src/Server/server/graphiql.html
Normal file
133
back/src/Server/server/graphiql.html
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<!--
|
||||||
|
* Copyright (c) 2019 GraphQL Contributors
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#graphiql {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This GraphiQL example depends on Promise and fetch, which are available in
|
||||||
|
modern browsers, but can be "polyfilled" for older browsers.
|
||||||
|
GraphiQL itself depends on React DOM.
|
||||||
|
If you do not want to rely on a CDN, you can host these files locally or
|
||||||
|
include them directly in your favored resource bunder.
|
||||||
|
-->
|
||||||
|
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
|
||||||
|
<script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
These two files can be found in the npm module, however you may wish to
|
||||||
|
copy them directly into your environment, or perhaps include them in your
|
||||||
|
favored resource bundler.
|
||||||
|
-->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphiql/graphiql.css" />
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/graphiql/graphiql.js" charset="utf-8"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@sifrr/fetch" charset="utf-8"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="graphiql">Loading...</div>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* This GraphiQL example illustrates how to use some of GraphiQL's props
|
||||||
|
* in order to enable reading and updating the URL parameters, making
|
||||||
|
* link sharing of queries a little bit easier.
|
||||||
|
*
|
||||||
|
* This is only one example of this kind of feature, GraphiQL exposes
|
||||||
|
* various React params to enable interesting integrations.
|
||||||
|
*/
|
||||||
|
// Parse the search string to get url parameters.
|
||||||
|
var search = window.location.search;
|
||||||
|
var parameters = {};
|
||||||
|
search
|
||||||
|
.substr(1)
|
||||||
|
.split('&')
|
||||||
|
.forEach(function(entry) {
|
||||||
|
var eq = entry.indexOf('=');
|
||||||
|
if (eq >= 0) {
|
||||||
|
parameters[decodeURIComponent(entry.slice(0, eq))] = decodeURIComponent(
|
||||||
|
entry.slice(eq + 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// if variables was provided, try to format it.
|
||||||
|
if (parameters.variables) {
|
||||||
|
try {
|
||||||
|
parameters.variables = JSON.stringify(JSON.parse(parameters.variables), null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
// Do nothing, we want to display the invalid JSON as a string, rather
|
||||||
|
// than present an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When the query and variables string is edited, update the URL bar so
|
||||||
|
// that it can be easily shared
|
||||||
|
function onEditQuery(newQuery) {
|
||||||
|
parameters.query = newQuery;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
function onEditVariables(newVariables) {
|
||||||
|
parameters.variables = newVariables;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
function onEditOperationName(newOperationName) {
|
||||||
|
parameters.operationName = newOperationName;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
function updateURL() {
|
||||||
|
var newSearch =
|
||||||
|
'?' +
|
||||||
|
Object.keys(parameters)
|
||||||
|
.filter(function(key) {
|
||||||
|
return Boolean(parameters[key]);
|
||||||
|
})
|
||||||
|
.map(function(key) {
|
||||||
|
return encodeURIComponent(key) + '=' + encodeURIComponent(parameters[key]);
|
||||||
|
})
|
||||||
|
.join('&');
|
||||||
|
history.replaceState(null, null, newSearch);
|
||||||
|
}
|
||||||
|
// Defines a GraphQL fetcher using the fetch API. You're not required to
|
||||||
|
// use fetch, and could instead implement graphQLFetcher however you like,
|
||||||
|
// as long as it returns a Promise or Observable.
|
||||||
|
function graphQLFetcher(graphQLParams) {
|
||||||
|
// When working locally, the example expects a GraphQL server at the path /graphql.
|
||||||
|
// In a PR preview, it connects to the Star Wars API externally.
|
||||||
|
// Change this to point wherever you host your GraphQL server.
|
||||||
|
const api = '/graphql';
|
||||||
|
return Sifrr.Fetch.graphql(api, {
|
||||||
|
...graphQLParams
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Render <GraphiQL /> into the body.
|
||||||
|
// See the README in the top level of this module to learn more about
|
||||||
|
// how you can customize GraphiQL by providing different values or
|
||||||
|
// additional child elements.
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(GraphiQL, {
|
||||||
|
fetcher: graphQLFetcher,
|
||||||
|
query: parameters.query,
|
||||||
|
variables: parameters.variables,
|
||||||
|
operationName: parameters.operationName,
|
||||||
|
onEditQuery: onEditQuery,
|
||||||
|
onEditVariables: onEditVariables,
|
||||||
|
onEditOperationName: onEditOperationName
|
||||||
|
}),
|
||||||
|
document.getElementById('graphiql')
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
138
back/src/Server/server/graphql.ts
Normal file
138
back/src/Server/server/graphql.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { parse } from 'query-string';
|
||||||
|
import { createAsyncIterator, forAwaitEach, isAsyncIterable } from 'iterall';
|
||||||
|
import { HttpResponse, HttpRequest } from 'uWebSockets.js';
|
||||||
|
// client -> server
|
||||||
|
const GQL_START = 'start';
|
||||||
|
const GQL_STOP = 'stop';
|
||||||
|
// server -> client
|
||||||
|
const GQL_DATA = 'data';
|
||||||
|
const GQL_QUERY = 'query';
|
||||||
|
|
||||||
|
async function getGraphqlParams(res: HttpResponse, req: HttpRequest) {
|
||||||
|
// query and variables
|
||||||
|
const queryParams = parse(req.getQuery());
|
||||||
|
let { query, variables, operationName } = queryParams;
|
||||||
|
if (typeof variables === 'string') variables = JSON.parse(variables);
|
||||||
|
|
||||||
|
// body
|
||||||
|
if (res && typeof res.json === 'function') {
|
||||||
|
const data = await res.json();
|
||||||
|
query = data.query || query;
|
||||||
|
variables = data.variables || variables;
|
||||||
|
operationName = data.operationName || operationName;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
source: query,
|
||||||
|
variableValues: variables,
|
||||||
|
operationName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function graphqlPost(schema, graphqlOptions: any = {}, graphql: any = {}) {
|
||||||
|
const execute = graphql.graphql || require('graphql').graphql;
|
||||||
|
|
||||||
|
return async (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
res.onAborted(console.error);
|
||||||
|
|
||||||
|
res.writeHeader('content-type', 'application/json');
|
||||||
|
res.end(
|
||||||
|
JSON.stringify(
|
||||||
|
await execute({
|
||||||
|
schema,
|
||||||
|
...(await getGraphqlParams(res, req)),
|
||||||
|
...graphqlOptions,
|
||||||
|
contextValue: {
|
||||||
|
res,
|
||||||
|
req,
|
||||||
|
...(graphqlOptions &&
|
||||||
|
(graphqlOptions.contextValue ||
|
||||||
|
(graphqlOptions.contextFxn && (await graphqlOptions.contextFxn(res, req)))))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopGqsSubscription(operations, reqOpId) {
|
||||||
|
if (!reqOpId) return;
|
||||||
|
operations[reqOpId] && operations[reqOpId].return && operations[reqOpId].return();
|
||||||
|
delete operations[reqOpId];
|
||||||
|
}
|
||||||
|
|
||||||
|
function graphqlWs(schema, graphqlOptions: any = {}, uwsOptions: any = {}, graphql: any = {}) {
|
||||||
|
const subscribe = graphql.subscribe || require('graphql').subscribe;
|
||||||
|
const execute = graphql.graphql || require('graphql').graphql;
|
||||||
|
|
||||||
|
return {
|
||||||
|
open: (ws, req) => {
|
||||||
|
ws.req = req;
|
||||||
|
ws.operations = {};
|
||||||
|
ws.opId = 1;
|
||||||
|
},
|
||||||
|
message: async (ws, message) => {
|
||||||
|
const { type, payload = {}, id: reqOpId } = JSON.parse(Buffer.from(message).toString('utf8'));
|
||||||
|
let opId;
|
||||||
|
if (reqOpId) {
|
||||||
|
opId = reqOpId;
|
||||||
|
} else {
|
||||||
|
opId = ws.opId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
schema,
|
||||||
|
source: payload.query,
|
||||||
|
variableValues: payload.variables,
|
||||||
|
operationName: payload.operationName,
|
||||||
|
contextValue: {
|
||||||
|
ws,
|
||||||
|
...(graphqlOptions &&
|
||||||
|
(graphqlOptions.contextValue ||
|
||||||
|
(graphqlOptions.contextFxn && (await graphqlOptions.contextFxn(ws)))))
|
||||||
|
},
|
||||||
|
...graphqlOptions
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GQL_START:
|
||||||
|
stopGqsSubscription(ws.operations, opId);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-case-declarations
|
||||||
|
let asyncIterable = await subscribe(
|
||||||
|
params.schema,
|
||||||
|
graphql.parse(params.source),
|
||||||
|
params.rootValue,
|
||||||
|
params.contextValue,
|
||||||
|
params.variableValues,
|
||||||
|
params.operationName
|
||||||
|
);
|
||||||
|
asyncIterable = isAsyncIterable(asyncIterable)
|
||||||
|
? asyncIterable
|
||||||
|
: createAsyncIterator([asyncIterable]);
|
||||||
|
|
||||||
|
forAwaitEach(asyncIterable, result =>
|
||||||
|
ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
id: opId,
|
||||||
|
type: GQL_DATA,
|
||||||
|
payload: result
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GQL_STOP:
|
||||||
|
stopGqsSubscription(ws.operations, reqOpId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ws.send(JSON.stringify({ payload: await execute(params), type: GQL_QUERY, id: opId }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
idleTimeout: 24 * 60 * 60,
|
||||||
|
...uwsOptions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { graphqlPost, graphqlWs };
|
35
back/src/Server/server/livereload.ts
Normal file
35
back/src/Server/server/livereload.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { WebSocketBehavior, WebSocket } from 'uWebSockets.js';
|
||||||
|
|
||||||
|
const websockets = {};
|
||||||
|
let id = 0;
|
||||||
|
|
||||||
|
const wsConfig: WebSocketBehavior = {
|
||||||
|
open: (ws: WebSocket & { id: number }, req) => {
|
||||||
|
websockets[id] = {
|
||||||
|
dirty: false
|
||||||
|
};
|
||||||
|
ws.id = id;
|
||||||
|
console.log('websocket connected: ', id);
|
||||||
|
id++;
|
||||||
|
},
|
||||||
|
message: ws => {
|
||||||
|
ws.send(JSON.stringify(websockets[ws.id].dirty));
|
||||||
|
websockets[ws.id].dirty = false;
|
||||||
|
},
|
||||||
|
close: (ws, code, message) => {
|
||||||
|
delete websockets[ws.id];
|
||||||
|
console.log(
|
||||||
|
`websocket disconnected with code ${code} and message ${message}:`,
|
||||||
|
ws.id,
|
||||||
|
websockets
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendSignal = (type: string, path: string) => {
|
||||||
|
console.log(type, 'signal for file: ', path);
|
||||||
|
for (let i in websockets) websockets[i].dirty = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default { websockets, wsConfig, sendSignal };
|
||||||
|
export { websockets, wsConfig, sendSignal };
|
47
back/src/Server/server/livereloadjs.js
Normal file
47
back/src/Server/server/livereloadjs.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const loc = window.location;
|
||||||
|
let path;
|
||||||
|
if (loc.protocol === 'https:') {
|
||||||
|
path = 'wss:';
|
||||||
|
} else {
|
||||||
|
path = 'ws:';
|
||||||
|
}
|
||||||
|
path += '//' + loc.host + '/__sifrrLiveReload';
|
||||||
|
|
||||||
|
let ws,
|
||||||
|
ttr = 500,
|
||||||
|
timeout;
|
||||||
|
|
||||||
|
function newWsConnection() {
|
||||||
|
ws = new WebSocket(path);
|
||||||
|
ws.onopen = function() {
|
||||||
|
ttr = 500;
|
||||||
|
checkMessage();
|
||||||
|
console.log('watching for file changes through sifrr-server livereload mode.');
|
||||||
|
};
|
||||||
|
ws.onmessage = function(event) {
|
||||||
|
if (JSON.parse(event.data)) {
|
||||||
|
console.log('Files changed, refreshing page.');
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ws.onerror = e => {
|
||||||
|
console.error('Webosocket error: ', e);
|
||||||
|
console.log('Retrying after ', ttr / 4, 'ms');
|
||||||
|
ttr *= 4;
|
||||||
|
};
|
||||||
|
ws.onclose = e => {
|
||||||
|
console.error(`Webosocket closed with code \${e.code} error \${e.message}`);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMessage() {
|
||||||
|
if (!ws) return;
|
||||||
|
if (ws.readyState === WebSocket.OPEN) ws.send('');
|
||||||
|
else if (ws.readyState === WebSocket.CLOSED) newWsConnection();
|
||||||
|
|
||||||
|
if (timeout) clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(checkMessage, ttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
newWsConnection();
|
||||||
|
setTimeout(checkMessage, ttr);
|
42
back/src/Server/server/loadroutes.ts
Normal file
42
back/src/Server/server/loadroutes.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { statSync, readdirSync } from 'fs';
|
||||||
|
import { join, extname } from 'path';
|
||||||
|
|
||||||
|
function loadRoutes(dir, { filter = () => true, basePath = '' } = {}) {
|
||||||
|
let files;
|
||||||
|
const paths = [];
|
||||||
|
|
||||||
|
if (statSync(dir).isDirectory()) {
|
||||||
|
files = readdirSync(dir)
|
||||||
|
.filter(filter)
|
||||||
|
.map(file => join(dir, file));
|
||||||
|
} else {
|
||||||
|
files = [dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
if (statSync(file).isDirectory()) {
|
||||||
|
// Recursive if directory
|
||||||
|
paths.push(...loadRoutes.call(this, file, { filter, basePath }));
|
||||||
|
} else if (extname(file) === '.js') {
|
||||||
|
const routes = require(file);
|
||||||
|
let basePaths = routes.basePath || [''];
|
||||||
|
delete routes.basePath;
|
||||||
|
if (typeof basePaths === 'string') basePaths = [basePaths];
|
||||||
|
|
||||||
|
basePaths.forEach(basep => {
|
||||||
|
for (const method in routes) {
|
||||||
|
const methodRoutes = routes[method];
|
||||||
|
for (let r in methodRoutes) {
|
||||||
|
if (!Array.isArray(methodRoutes[r])) methodRoutes[r] = [methodRoutes[r]];
|
||||||
|
this[method](basePath + basep + r, ...methodRoutes[r]);
|
||||||
|
paths.push(basePath + basep + r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default loadRoutes;
|
176
back/src/Server/server/mime.ts
Normal file
176
back/src/Server/server/mime.ts
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
const mimes = {
|
||||||
|
'3gp': 'video/3gpp',
|
||||||
|
a: 'application/octet-stream',
|
||||||
|
ai: 'application/postscript',
|
||||||
|
aif: 'audio/x-aiff',
|
||||||
|
aiff: 'audio/x-aiff',
|
||||||
|
asc: 'application/pgp-signature',
|
||||||
|
asf: 'video/x-ms-asf',
|
||||||
|
asm: 'text/x-asm',
|
||||||
|
asx: 'video/x-ms-asf',
|
||||||
|
atom: 'application/atom+xml',
|
||||||
|
au: 'audio/basic',
|
||||||
|
avi: 'video/x-msvideo',
|
||||||
|
bat: 'application/x-msdownload',
|
||||||
|
bin: 'application/octet-stream',
|
||||||
|
bmp: 'image/bmp',
|
||||||
|
bz2: 'application/x-bzip2',
|
||||||
|
c: 'text/x-c',
|
||||||
|
cab: 'application/vnd.ms-cab-compressed',
|
||||||
|
cc: 'text/x-c',
|
||||||
|
chm: 'application/vnd.ms-htmlhelp',
|
||||||
|
class: 'application/octet-stream',
|
||||||
|
com: 'application/x-msdownload',
|
||||||
|
conf: 'text/plain',
|
||||||
|
cpp: 'text/x-c',
|
||||||
|
crt: 'application/x-x509-ca-cert',
|
||||||
|
css: 'text/css',
|
||||||
|
csv: 'text/csv',
|
||||||
|
cxx: 'text/x-c',
|
||||||
|
deb: 'application/x-debian-package',
|
||||||
|
der: 'application/x-x509-ca-cert',
|
||||||
|
diff: 'text/x-diff',
|
||||||
|
djv: 'image/vnd.djvu',
|
||||||
|
djvu: 'image/vnd.djvu',
|
||||||
|
dll: 'application/x-msdownload',
|
||||||
|
dmg: 'application/octet-stream',
|
||||||
|
doc: 'application/msword',
|
||||||
|
dot: 'application/msword',
|
||||||
|
dtd: 'application/xml-dtd',
|
||||||
|
dvi: 'application/x-dvi',
|
||||||
|
ear: 'application/java-archive',
|
||||||
|
eml: 'message/rfc822',
|
||||||
|
eps: 'application/postscript',
|
||||||
|
exe: 'application/x-msdownload',
|
||||||
|
f: 'text/x-fortran',
|
||||||
|
f77: 'text/x-fortran',
|
||||||
|
f90: 'text/x-fortran',
|
||||||
|
flv: 'video/x-flv',
|
||||||
|
for: 'text/x-fortran',
|
||||||
|
gem: 'application/octet-stream',
|
||||||
|
gemspec: 'text/x-script.ruby',
|
||||||
|
gif: 'image/gif',
|
||||||
|
gz: 'application/x-gzip',
|
||||||
|
h: 'text/x-c',
|
||||||
|
hh: 'text/x-c',
|
||||||
|
htm: 'text/html',
|
||||||
|
html: 'text/html',
|
||||||
|
ico: 'image/vnd.microsoft.icon',
|
||||||
|
ics: 'text/calendar',
|
||||||
|
ifb: 'text/calendar',
|
||||||
|
iso: 'application/octet-stream',
|
||||||
|
jar: 'application/java-archive',
|
||||||
|
java: 'text/x-java-source',
|
||||||
|
jnlp: 'application/x-java-jnlp-file',
|
||||||
|
jpeg: 'image/jpeg',
|
||||||
|
jpg: 'image/jpeg',
|
||||||
|
js: 'application/javascript',
|
||||||
|
json: 'application/json',
|
||||||
|
log: 'text/plain',
|
||||||
|
m3u: 'audio/x-mpegurl',
|
||||||
|
m4v: 'video/mp4',
|
||||||
|
man: 'text/troff',
|
||||||
|
mathml: 'application/mathml+xml',
|
||||||
|
mbox: 'application/mbox',
|
||||||
|
mdoc: 'text/troff',
|
||||||
|
me: 'text/troff',
|
||||||
|
mid: 'audio/midi',
|
||||||
|
midi: 'audio/midi',
|
||||||
|
mime: 'message/rfc822',
|
||||||
|
mjs: 'application/javascript',
|
||||||
|
mml: 'application/mathml+xml',
|
||||||
|
mng: 'video/x-mng',
|
||||||
|
mov: 'video/quicktime',
|
||||||
|
mp3: 'audio/mpeg',
|
||||||
|
mp4: 'video/mp4',
|
||||||
|
mp4v: 'video/mp4',
|
||||||
|
mpeg: 'video/mpeg',
|
||||||
|
mpg: 'video/mpeg',
|
||||||
|
ms: 'text/troff',
|
||||||
|
msi: 'application/x-msdownload',
|
||||||
|
odp: 'application/vnd.oasis.opendocument.presentation',
|
||||||
|
ods: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
odt: 'application/vnd.oasis.opendocument.text',
|
||||||
|
ogg: 'application/ogg',
|
||||||
|
p: 'text/x-pascal',
|
||||||
|
pas: 'text/x-pascal',
|
||||||
|
pbm: 'image/x-portable-bitmap',
|
||||||
|
pdf: 'application/pdf',
|
||||||
|
pem: 'application/x-x509-ca-cert',
|
||||||
|
pgm: 'image/x-portable-graymap',
|
||||||
|
pgp: 'application/pgp-encrypted',
|
||||||
|
pkg: 'application/octet-stream',
|
||||||
|
pl: 'text/x-script.perl',
|
||||||
|
pm: 'text/x-script.perl-module',
|
||||||
|
png: 'image/png',
|
||||||
|
pnm: 'image/x-portable-anymap',
|
||||||
|
ppm: 'image/x-portable-pixmap',
|
||||||
|
pps: 'application/vnd.ms-powerpoint',
|
||||||
|
ppt: 'application/vnd.ms-powerpoint',
|
||||||
|
ps: 'application/postscript',
|
||||||
|
psd: 'image/vnd.adobe.photoshop',
|
||||||
|
py: 'text/x-script.python',
|
||||||
|
qt: 'video/quicktime',
|
||||||
|
ra: 'audio/x-pn-realaudio',
|
||||||
|
rake: 'text/x-script.ruby',
|
||||||
|
ram: 'audio/x-pn-realaudio',
|
||||||
|
rar: 'application/x-rar-compressed',
|
||||||
|
rb: 'text/x-script.ruby',
|
||||||
|
rdf: 'application/rdf+xml',
|
||||||
|
roff: 'text/troff',
|
||||||
|
rpm: 'application/x-redhat-package-manager',
|
||||||
|
rss: 'application/rss+xml',
|
||||||
|
rtf: 'application/rtf',
|
||||||
|
ru: 'text/x-script.ruby',
|
||||||
|
s: 'text/x-asm',
|
||||||
|
sgm: 'text/sgml',
|
||||||
|
sgml: 'text/sgml',
|
||||||
|
sh: 'application/x-sh',
|
||||||
|
sig: 'application/pgp-signature',
|
||||||
|
snd: 'audio/basic',
|
||||||
|
so: 'application/octet-stream',
|
||||||
|
svg: 'image/svg+xml',
|
||||||
|
svgz: 'image/svg+xml',
|
||||||
|
swf: 'application/x-shockwave-flash',
|
||||||
|
t: 'text/troff',
|
||||||
|
tar: 'application/x-tar',
|
||||||
|
tbz: 'application/x-bzip-compressed-tar',
|
||||||
|
tcl: 'application/x-tcl',
|
||||||
|
tex: 'application/x-tex',
|
||||||
|
texi: 'application/x-texinfo',
|
||||||
|
texinfo: 'application/x-texinfo',
|
||||||
|
text: 'text/plain',
|
||||||
|
tif: 'image/tiff',
|
||||||
|
tiff: 'image/tiff',
|
||||||
|
torrent: 'application/x-bittorrent',
|
||||||
|
tr: 'text/troff',
|
||||||
|
txt: 'text/plain',
|
||||||
|
vcf: 'text/x-vcard',
|
||||||
|
vcs: 'text/x-vcalendar',
|
||||||
|
vrml: 'model/vrml',
|
||||||
|
war: 'application/java-archive',
|
||||||
|
wav: 'audio/x-wav',
|
||||||
|
wma: 'audio/x-ms-wma',
|
||||||
|
wmv: 'video/x-ms-wmv',
|
||||||
|
wmx: 'video/x-ms-wmx',
|
||||||
|
wrl: 'model/vrml',
|
||||||
|
wsdl: 'application/wsdl+xml',
|
||||||
|
xbm: 'image/x-xbitmap',
|
||||||
|
xhtml: 'application/xhtml+xml',
|
||||||
|
xls: 'application/vnd.ms-excel',
|
||||||
|
xml: 'application/xml',
|
||||||
|
xpm: 'image/x-xpixmap',
|
||||||
|
xsl: 'application/xml',
|
||||||
|
xslt: 'application/xslt+xml',
|
||||||
|
yaml: 'text/yaml',
|
||||||
|
yml: 'text/yaml',
|
||||||
|
zip: 'application/zip',
|
||||||
|
default: 'text/html'
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMime = (path: string): string => {
|
||||||
|
const i = path.lastIndexOf('.');
|
||||||
|
return mimes[path.substr(i + 1).toLowerCase()] || mimes['default'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getMime, mimes };
|
172
back/src/Server/server/sendfile.ts
Normal file
172
back/src/Server/server/sendfile.ts
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import { watch, statSync, createReadStream } from 'fs';
|
||||||
|
import { createBrotliCompress, createGzip, createDeflate } from 'zlib';
|
||||||
|
const watchedPaths = new Set();
|
||||||
|
|
||||||
|
const compressions = {
|
||||||
|
br: createBrotliCompress,
|
||||||
|
gzip: createGzip,
|
||||||
|
deflate: createDeflate
|
||||||
|
};
|
||||||
|
import { writeHeaders } from './utils';
|
||||||
|
import { getMime } from './mime';
|
||||||
|
const bytes = 'bytes=';
|
||||||
|
import { stob } from './utils';
|
||||||
|
import { sendSignal } from './livereload';
|
||||||
|
import { SendFileOptions } from './types';
|
||||||
|
import { HttpResponse, HttpRequest } from 'uWebSockets.js';
|
||||||
|
|
||||||
|
function sendFile(res: HttpResponse, req: HttpRequest, path: string, options: SendFileOptions) {
|
||||||
|
if (options && options.livereload && !watchedPaths.has(path)) {
|
||||||
|
watchedPaths.add(path);
|
||||||
|
watch(path, sendSignal);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendFileToRes(
|
||||||
|
res,
|
||||||
|
{
|
||||||
|
'if-modified-since': req.getHeader('if-modified-since'),
|
||||||
|
range: req.getHeader('range'),
|
||||||
|
'accept-encoding': req.getHeader('accept-encoding')
|
||||||
|
},
|
||||||
|
path,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendFileToRes(
|
||||||
|
res: HttpResponse,
|
||||||
|
reqHeaders: { [name: string]: string },
|
||||||
|
path: string,
|
||||||
|
{
|
||||||
|
lastModified = true,
|
||||||
|
headers = {},
|
||||||
|
compress = false,
|
||||||
|
compressionOptions = {
|
||||||
|
priority: ['gzip', 'br', 'deflate']
|
||||||
|
},
|
||||||
|
cache = false
|
||||||
|
}: { cache: any } & any = {}
|
||||||
|
) {
|
||||||
|
let { mtime, size } = statSync(path);
|
||||||
|
mtime.setMilliseconds(0);
|
||||||
|
const mtimeutc = mtime.toUTCString();
|
||||||
|
|
||||||
|
headers = Object.assign({}, headers);
|
||||||
|
// handling last modified
|
||||||
|
if (lastModified) {
|
||||||
|
// Return 304 if last-modified
|
||||||
|
if (reqHeaders['if-modified-since']) {
|
||||||
|
if (new Date(reqHeaders['if-modified-since']) >= mtime) {
|
||||||
|
res.writeStatus('304 Not Modified');
|
||||||
|
return res.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headers['last-modified'] = mtimeutc;
|
||||||
|
}
|
||||||
|
headers['content-type'] = getMime(path);
|
||||||
|
|
||||||
|
// write data
|
||||||
|
let start = 0,
|
||||||
|
end = size - 1;
|
||||||
|
|
||||||
|
if (reqHeaders.range) {
|
||||||
|
compress = false;
|
||||||
|
const parts = reqHeaders.range.replace(bytes, '').split('-');
|
||||||
|
start = parseInt(parts[0], 10);
|
||||||
|
end = parts[1] ? parseInt(parts[1], 10) : end;
|
||||||
|
headers['accept-ranges'] = 'bytes';
|
||||||
|
headers['content-range'] = `bytes ${start}-${end}/${size}`;
|
||||||
|
size = end - start + 1;
|
||||||
|
res.writeStatus('206 Partial Content');
|
||||||
|
}
|
||||||
|
|
||||||
|
// for size = 0
|
||||||
|
if (end < 0) end = 0;
|
||||||
|
|
||||||
|
let readStream = createReadStream(path, { start, end });
|
||||||
|
// Compression;
|
||||||
|
let compressed: boolean | string = false;
|
||||||
|
if (compress) {
|
||||||
|
const l = compressionOptions.priority.length;
|
||||||
|
for (let i = 0; i < l; i++) {
|
||||||
|
const type = compressionOptions.priority[i];
|
||||||
|
if (reqHeaders['accept-encoding'].indexOf(type) > -1) {
|
||||||
|
compressed = type;
|
||||||
|
const compressor = compressions[type](compressionOptions);
|
||||||
|
readStream.pipe(compressor);
|
||||||
|
readStream = compressor;
|
||||||
|
headers['content-encoding'] = compressionOptions.priority[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.onAborted(() => readStream.destroy());
|
||||||
|
writeHeaders(res, headers);
|
||||||
|
// check cache
|
||||||
|
if (cache) {
|
||||||
|
return cache.wrap(
|
||||||
|
`${path}_${mtimeutc}_${start}_${end}_${compressed}`,
|
||||||
|
cb => {
|
||||||
|
stob(readStream)
|
||||||
|
.then(b => cb(null, b))
|
||||||
|
.catch(cb);
|
||||||
|
},
|
||||||
|
{ ttl: 0 },
|
||||||
|
(err, buffer) => {
|
||||||
|
if (err) {
|
||||||
|
res.writeStatus('500 Internal server error');
|
||||||
|
res.end();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
res.end(buffer);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (compressed) {
|
||||||
|
readStream.on('data', buffer => {
|
||||||
|
res.write(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
readStream.on('data', buffer => {
|
||||||
|
const chunk = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength),
|
||||||
|
lastOffset = res.getWriteOffset();
|
||||||
|
|
||||||
|
// First try
|
||||||
|
const [ok, done] = res.tryEnd(chunk, size);
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
readStream.destroy();
|
||||||
|
} else if (!ok) {
|
||||||
|
// pause because backpressure
|
||||||
|
readStream.pause();
|
||||||
|
|
||||||
|
// Save unsent chunk for later
|
||||||
|
res.ab = chunk;
|
||||||
|
res.abOffset = lastOffset;
|
||||||
|
|
||||||
|
// Register async handlers for drainage
|
||||||
|
res.onWritable(offset => {
|
||||||
|
const [ok, done] = res.tryEnd(res.ab.slice(offset - res.abOffset), size);
|
||||||
|
if (done) {
|
||||||
|
readStream.destroy();
|
||||||
|
} else if (ok) {
|
||||||
|
readStream.resume();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
readStream
|
||||||
|
.on('error', e => {
|
||||||
|
res.writeStatus('500 Internal server error');
|
||||||
|
res.end();
|
||||||
|
readStream.destroy();
|
||||||
|
throw e;
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default sendFile;
|
13
back/src/Server/server/sslapp.ts
Normal file
13
back/src/Server/server/sslapp.ts
Normal 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);
|
||||||
|
extend(this, new BaseApp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SSLApp;
|
26
back/src/Server/server/types.ts
Normal file
26
back/src/Server/server/types.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { AppOptions, TemplatedApp, HttpResponse, HttpRequest } from 'uWebSockets.js';
|
||||||
|
|
||||||
|
export type UwsApp = {
|
||||||
|
(options: AppOptions): TemplatedApp;
|
||||||
|
new (options: AppOptions): TemplatedApp;
|
||||||
|
prototype: TemplatedApp;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SendFileOptions = {
|
||||||
|
failOnDuplicateRoute?: boolean;
|
||||||
|
overwriteRoute?: boolean;
|
||||||
|
watch?: boolean;
|
||||||
|
filter?: (path: string) => boolean;
|
||||||
|
livereload?: boolean;
|
||||||
|
lastModified?: boolean;
|
||||||
|
headers?: { [name: string]: string };
|
||||||
|
compress?: boolean;
|
||||||
|
compressionOptions?: {
|
||||||
|
priority?: 'gzip' | 'br' | 'deflate';
|
||||||
|
};
|
||||||
|
cache?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Handler = (res: HttpResponse, req: HttpRequest) => void;
|
||||||
|
|
||||||
|
export {};
|
52
back/src/Server/server/utils.ts
Normal file
52
back/src/Server/server/utils.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { HttpResponse } from 'uWebSockets.js';
|
||||||
|
import { ReadStream } from 'fs';
|
||||||
|
|
||||||
|
function writeHeaders(
|
||||||
|
res: HttpResponse,
|
||||||
|
headers: { [name: string]: string } | string,
|
||||||
|
other?: string
|
||||||
|
) {
|
||||||
|
if (typeof headers === 'string') {
|
||||||
|
res.writeHeader(headers, other.toString());
|
||||||
|
} else {
|
||||||
|
for (const n in headers) {
|
||||||
|
res.writeHeader(n, headers[n].toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extend(who: object, from: object, overwrite = true) {
|
||||||
|
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 = [];
|
||||||
|
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 { writeHeaders, extend, stob };
|
30
back/src/Server/sifrr.server.ts
Normal file
30
back/src/Server/sifrr.server.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { parse } from 'query-string';
|
||||||
|
import { HttpRequest } from 'uWebSockets.js';
|
||||||
|
import App from './server/app';
|
||||||
|
import SSLApp from './server/sslapp';
|
||||||
|
import { mimes, getMime } from './server/mime';
|
||||||
|
import { writeHeaders } from './server/utils';
|
||||||
|
import sendFile from './server/sendfile';
|
||||||
|
import Cluster from './server/cluster';
|
||||||
|
import livereload from './server/livereload';
|
||||||
|
import * as types from './server/types';
|
||||||
|
|
||||||
|
const getQuery = (req: HttpRequest) => {
|
||||||
|
return parse(req.getQuery());
|
||||||
|
};
|
||||||
|
|
||||||
|
export { App, SSLApp, mimes, getMime, writeHeaders, sendFile, Cluster, livereload, getQuery };
|
||||||
|
export * from './server/types';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
App,
|
||||||
|
SSLApp,
|
||||||
|
mimes,
|
||||||
|
getMime,
|
||||||
|
writeHeaders,
|
||||||
|
sendFile,
|
||||||
|
Cluster,
|
||||||
|
livereload,
|
||||||
|
getQuery,
|
||||||
|
...types
|
||||||
|
};
|
505
back/yarn.lock
505
back/yarn.lock
@ -20,13 +20,6 @@
|
|||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.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":
|
"@types/circular-json@^0.4.0":
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be"
|
resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be"
|
||||||
@ -36,32 +29,10 @@
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
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":
|
"@types/eslint-visitor-keys@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
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":
|
"@types/google-protobuf@^3.7.3":
|
||||||
version "3.7.3"
|
version "3.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.7.3.tgz#429512e541bbd777f2c867692e6335ee08d1f6d4"
|
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.7.3.tgz#429512e541bbd777f2c867692e6335ee08d1f6d4"
|
||||||
@ -87,35 +58,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/mime@*":
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
|
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "13.11.0"
|
version "13.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
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":
|
"@types/strip-bom@^3.0.0":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
|
resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
|
||||||
@ -169,13 +115,6 @@
|
|||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
tsutils "^3.17.1"
|
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:
|
acorn-jsx@^5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
|
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"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
|
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:
|
ajv@^6.10.0, ajv@^6.10.2:
|
||||||
version "6.12.0"
|
version "6.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
|
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"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
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:
|
astral-regex@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
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:
|
axios@^0.20.0:
|
||||||
version "0.20.0"
|
version "0.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
|
||||||
@ -261,38 +184,16 @@ axios@^0.20.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects "^1.10.0"
|
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:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
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:
|
bintrees@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
|
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
|
||||||
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
|
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
|
||||||
|
|
||||||
blob@0.0.5:
|
body-parser@^1.19.0:
|
||||||
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:
|
|
||||||
version "1.19.0"
|
version "1.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -322,14 +223,17 @@ buffer-from@^1.0.0:
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
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:
|
bytes@3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
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:
|
callsites@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
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"
|
version "1.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
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:
|
concat-map@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
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:
|
content-type@~1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
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:
|
cross-spawn@^6.0.5:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||||
@ -470,22 +344,21 @@ debug@2.6.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
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"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.1"
|
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:
|
decamelize@^1.1.2:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
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:
|
deep-is@~0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
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"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||||
|
|
||||||
destroy@~1.0.4:
|
dicer@0.3.0:
|
||||||
version "1.0.4"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
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:
|
diff@^4.0.1:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
@ -532,57 +408,12 @@ emoji-regex@^8.0.0:
|
|||||||
version "8.0.0"
|
version "8.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
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:
|
error-ex@^1.2.0:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish "^0.2.1"
|
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:
|
escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
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"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
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:
|
external-editor@^3.0.3:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
|
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
|
||||||
@ -765,18 +557,6 @@ filewatcher@~3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
debounce "^1.0.0"
|
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:
|
find-up@^1.0.0:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
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"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
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:
|
fs.realpath@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
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"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
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:
|
has-flag@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
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"
|
statuses ">= 1.5.0 < 2"
|
||||||
toidentifier "1.0.0"
|
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:
|
http-status-codes@*, http-status-codes@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477"
|
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:
|
dependencies:
|
||||||
repeating "^2.0.0"
|
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:
|
inflight@^1.0.4:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||||
@ -946,7 +694,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@2, inherits@2.0.4:
|
inherits@2:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
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"
|
strip-ansi "^6.0.0"
|
||||||
through "^2.3.6"
|
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:
|
is-arrayish@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
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"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
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:
|
isexe@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
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:
|
jasmine-core@~3.5.0:
|
||||||
version "3.5.0"
|
version "3.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.5.0.tgz#132c23e645af96d85c8bca13c8758b18429fc1e4"
|
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"
|
redent "^1.0.0"
|
||||||
trim-newlines "^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:
|
mime-db@1.43.0:
|
||||||
version "1.43.0"
|
version "1.43.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||||
@ -1183,10 +920,6 @@ mime-types@~2.1.24:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime-db "1.43.0"
|
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:
|
mimic-fn@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
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"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
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:
|
ms@^2.1.1:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
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"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
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:
|
nice-try@^1.0.4:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
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"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
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:
|
on-finished@~2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||||
@ -1307,22 +1028,6 @@ parse-json@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
error-ex "^1.2.0"
|
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:
|
path-exists@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
|
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"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
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:
|
path-type@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||||
@ -1382,13 +1083,6 @@ prom-client@^12.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tdigest "^0.1.1"
|
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:
|
punycode@^2.1.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||||
@ -1397,9 +1091,14 @@ qs@6.7.0:
|
|||||||
version "6.7.0"
|
version "6.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
|
|
||||||
range-parser@~1.2.1:
|
query-string@^6.13.3:
|
||||||
version "1.2.1"
|
version "6.13.3"
|
||||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
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:
|
raw-body@2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
@ -1487,10 +1186,6 @@ rxjs@^6.5.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
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:
|
safe-buffer@^5.0.1:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
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"
|
version "6.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
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:
|
setprototypeof@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
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"
|
astral-regex "^1.0.0"
|
||||||
is-fullwidth-code-point "^2.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:
|
source-map-support@^0.5.12, source-map-support@^0.5.6:
|
||||||
version "0.5.16"
|
version "0.5.16"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
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"
|
version "3.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
|
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:
|
sprintf-js@~1.0.2:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
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"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
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:
|
string-width@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||||
@ -1753,10 +1386,6 @@ tmp@^0.0.33:
|
|||||||
dependencies:
|
dependencies:
|
||||||
os-tmpdir "~1.0.2"
|
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:
|
toidentifier@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
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"
|
version "0.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
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"
|
version "1.6.18"
|
||||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1840,7 +1469,11 @@ typescript@^3.8.3:
|
|||||||
version "3.8.3"
|
version "3.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
|
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"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||||
|
|
||||||
@ -1850,10 +1483,6 @@ uri-js@^4.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
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:
|
uuid@7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
|
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-correct "^3.0.0"
|
||||||
spdx-expression-parse "^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:
|
which@^1.2.9, which@^1.3.0:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||||
@ -1899,28 +1524,10 @@ write@1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mkdirp "^0.5.1"
|
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:
|
xtend@^4.0.0:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
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:
|
yn@3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import {Connection} from "../front/src/Connection";
|
import {Connection} from "../front/src/Connection";
|
||||||
|
import * as WebSocket from "ws"
|
||||||
|
|
||||||
function sleep(ms) {
|
function sleep(ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connection.setWebsocketFactory((url: string) => {
|
||||||
|
return new WebSocket(url);
|
||||||
|
});
|
||||||
|
|
||||||
async function startOneUser(): Promise<void> {
|
async function startOneUser(): Promise<void> {
|
||||||
const connection = await Connection.createConnection('foo', ['male3']);
|
const connection = await Connection.createConnection('foo', ['male3']);
|
||||||
|
|
||||||
|
@ -21,11 +21,10 @@
|
|||||||
],
|
],
|
||||||
"license": "SEE LICENSE IN LICENSE.txt",
|
"license": "SEE LICENSE IN LICENSE.txt",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"socket.io-client": "^2.3.0",
|
"@types/ws": "^7.2.6",
|
||||||
"ts-node-dev": "^1.0.0-pre.62",
|
"ts-node-dev": "^1.0.0-pre.62",
|
||||||
"typescript": "^4.0.2"
|
"typescript": "^4.0.2",
|
||||||
|
"ws": "^7.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {}
|
||||||
"@types/socket.io-client": "^1.4.33"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@types/socket.io-client@^1.4.33":
|
"@types/node@*":
|
||||||
version "1.4.33"
|
version "14.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.33.tgz#8e705b9b3f7fba6cb329d27cd2eda222812adbf1"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.2.tgz#2de1ed6670439387da1c9f549a2ade2b0a799256"
|
||||||
|
|
||||||
"@types/strip-bom@^3.0.0":
|
"@types/strip-bom@^3.0.0":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
@ -14,9 +14,11 @@
|
|||||||
version "0.0.30"
|
version "0.0.30"
|
||||||
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
|
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
|
||||||
|
|
||||||
after@0.8.2:
|
"@types/ws@^7.2.6":
|
||||||
version "0.8.2"
|
version "7.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
|
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.6.tgz#516cbfb818310f87b43940460e065eb912a4178d"
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
anymatch@~3.1.1:
|
anymatch@~3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
@ -33,40 +35,14 @@ array-find-index@^1.0.1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
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:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
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:
|
binary-extensions@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
|
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:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
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"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
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:
|
camelcase-keys@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
|
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
|
||||||
@ -113,22 +85,6 @@ chokidar@^3.4.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.1.2"
|
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:
|
concat-map@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
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"
|
get-stdin "^4.0.1"
|
||||||
meow "^3.3.0"
|
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:
|
decamelize@^1.1.2:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||||
@ -172,32 +116,6 @@ dynamic-dedupe@^0.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xtend "^4.0.0"
|
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:
|
error-ex@^1.2.0:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
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"
|
version "4.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
|
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:
|
hosted-git-info@^2.1.4:
|
||||||
version "2.8.8"
|
version "2.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
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:
|
dependencies:
|
||||||
repeating "^2.0.0"
|
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:
|
inflight@^1.0.4:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
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"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
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:
|
load-json-file@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
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"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
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:
|
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
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"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
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:
|
once@^1.3.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||||
@ -416,18 +304,6 @@ parse-json@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
error-ex "^1.2.0"
|
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:
|
path-exists@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
|
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"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
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:
|
source-map-support@^0.5.12, source-map-support@^0.5.17:
|
||||||
version "0.5.19"
|
version "0.5.19"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
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"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
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:
|
to-regex-range@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
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"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||||
|
|
||||||
ws@~6.1.0:
|
ws@^7.3.1:
|
||||||
version "6.1.4"
|
version "7.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
|
||||||
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:
|
xtend@^4.0.0:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
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:
|
yn@3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
@ -2,15 +2,13 @@ import Axios from "axios";
|
|||||||
import {API_URL} from "./Enum/EnvironmentVariable";
|
import {API_URL} from "./Enum/EnvironmentVariable";
|
||||||
import {MessageUI} from "./Logger/MessageUI";
|
import {MessageUI} from "./Logger/MessageUI";
|
||||||
import {
|
import {
|
||||||
BatchMessage, GroupDeleteMessage, GroupUpdateMessage, ItemEventMessage,
|
BatchMessage, ClientToServerMessage, GroupDeleteMessage, GroupUpdateMessage, ItemEventMessage, JoinRoomMessage,
|
||||||
PositionMessage,
|
PositionMessage, RoomJoinedMessage, ServerToClientMessage,
|
||||||
SetPlayerDetailsMessage, UserJoinedMessage, UserLeftMessage, UserMovedMessage,
|
SetPlayerDetailsMessage, SetUserIdMessage, SilentMessage, UserJoinedMessage, UserLeftMessage, UserMovedMessage,
|
||||||
UserMovesMessage,
|
UserMovesMessage,
|
||||||
ViewportMessage
|
ViewportMessage
|
||||||
} from "./Messages/generated/messages_pb"
|
} from "./Messages/generated/messages_pb"
|
||||||
|
|
||||||
const SocketIo = require('socket.io-client');
|
|
||||||
import Socket = SocketIOClient.Socket;
|
|
||||||
import {PlayerAnimationNames} from "./Phaser/Player/Animation";
|
import {PlayerAnimationNames} from "./Phaser/Player/Animation";
|
||||||
import {UserSimplePeerInterface} from "./WebRtc/SimplePeer";
|
import {UserSimplePeerInterface} from "./WebRtc/SimplePeer";
|
||||||
import {SignalData} from "simple-peer";
|
import {SignalData} from "simple-peer";
|
||||||
@ -132,63 +130,91 @@ export interface RoomJoinedMessageInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Connection implements Connection {
|
export class Connection implements Connection {
|
||||||
private readonly socket: Socket;
|
private readonly socket: WebSocket;
|
||||||
private userId: number|null = null;
|
private userId: number|null = null;
|
||||||
private batchCallbacks: Map<string, Function[]> = new Map<string, Function[]>();
|
private batchCallbacks: Map<string, Function[]> = new Map<string, Function[]>();
|
||||||
|
private static websocketFactory: null|((url: string)=>any) = null;
|
||||||
|
|
||||||
|
public static setWebsocketFactory(websocketFactory: (url: string)=>any): void {
|
||||||
|
Connection.websocketFactory = websocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
private constructor(token: string) {
|
private constructor(token: string) {
|
||||||
|
let url = API_URL.replace('http://', 'ws://').replace('https://', 'wss://');
|
||||||
|
url += '?token='+token;
|
||||||
|
|
||||||
this.socket = SocketIo(`${API_URL}`, {
|
if (Connection.websocketFactory) {
|
||||||
query: {
|
this.socket = Connection.websocketFactory(url);
|
||||||
token: token
|
} else {
|
||||||
},
|
this.socket = new WebSocket(url);
|
||||||
reconnection: false // Reconnection is handled by the application itself
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.socket.on(EventMessage.MESSAGE_ERROR, (message: string) => {
|
this.socket.binaryType = 'arraybuffer';
|
||||||
console.error(EventMessage.MESSAGE_ERROR, message);
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
this.socket.onopen = (ev) => {
|
||||||
* Messages inside batched messages are extracted and sent to listeners directly.
|
console.log('WS connected');
|
||||||
*/
|
};
|
||||||
this.socket.on(EventMessage.BATCH, (batchedMessagesBinary: ArrayBuffer) => {
|
|
||||||
const batchMessage = BatchMessage.deserializeBinary(new Uint8Array(batchedMessagesBinary));
|
|
||||||
|
|
||||||
for (const message of batchMessage.getPayloadList()) {
|
this.socket.onmessage = (messageEvent) => {
|
||||||
let event: string;
|
const arrayBuffer: ArrayBuffer = messageEvent.data;
|
||||||
let payload;
|
const message = ServerToClientMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
||||||
if (message.hasUsermovedmessage()) {
|
|
||||||
event = EventMessage.USER_MOVED;
|
if (message.hasBatchmessage()) {
|
||||||
payload = message.getUsermovedmessage();
|
for (const subMessage of (message.getBatchmessage() as BatchMessage).getPayloadList()) {
|
||||||
} else if (message.hasGroupupdatemessage()) {
|
let event: string;
|
||||||
event = EventMessage.GROUP_CREATE_UPDATE;
|
let payload;
|
||||||
payload = message.getGroupupdatemessage();
|
if (subMessage.hasUsermovedmessage()) {
|
||||||
} else if (message.hasGroupdeletemessage()) {
|
event = EventMessage.USER_MOVED;
|
||||||
event = EventMessage.GROUP_DELETE;
|
payload = subMessage.getUsermovedmessage();
|
||||||
payload = message.getGroupdeletemessage();
|
} else if (subMessage.hasGroupupdatemessage()) {
|
||||||
} else if (message.hasUserjoinedmessage()) {
|
event = EventMessage.GROUP_CREATE_UPDATE;
|
||||||
event = EventMessage.JOIN_ROOM;
|
payload = subMessage.getGroupupdatemessage();
|
||||||
payload = message.getUserjoinedmessage();
|
} else if (subMessage.hasGroupdeletemessage()) {
|
||||||
} else if (message.hasUserleftmessage()) {
|
event = EventMessage.GROUP_DELETE;
|
||||||
event = EventMessage.USER_LEFT;
|
payload = subMessage.getGroupdeletemessage();
|
||||||
payload = message.getUserleftmessage();
|
} else if (subMessage.hasUserjoinedmessage()) {
|
||||||
} else if (message.hasItemeventmessage()) {
|
event = EventMessage.JOIN_ROOM;
|
||||||
event = EventMessage.ITEM_EVENT;
|
payload = subMessage.getUserjoinedmessage();
|
||||||
payload = message.getItemeventmessage();
|
} else if (subMessage.hasUserleftmessage()) {
|
||||||
} else {
|
event = EventMessage.USER_LEFT;
|
||||||
throw new Error('Unexpected batch message type');
|
payload = subMessage.getUserleftmessage();
|
||||||
|
} else if (subMessage.hasItemeventmessage()) {
|
||||||
|
event = EventMessage.ITEM_EVENT;
|
||||||
|
payload = subMessage.getItemeventmessage();
|
||||||
|
} else {
|
||||||
|
throw new Error('Unexpected batch message type');
|
||||||
|
}
|
||||||
|
|
||||||
|
const listeners = this.batchCallbacks.get(event);
|
||||||
|
if (listeners === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const listener of listeners) {
|
||||||
|
listener(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (message.hasRoomjoinedmessage()) {
|
||||||
|
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
|
||||||
|
|
||||||
|
const users: Array<MessageUserJoined> = roomJoinedMessage.getUserList().map(this.toMessageUserJoined);
|
||||||
|
const groups: Array<GroupCreatedUpdatedMessageInterface> = roomJoinedMessage.getGroupList().map(this.toGroupCreatedUpdatedMessage);
|
||||||
|
let items: { [itemId: number] : unknown } = {};
|
||||||
|
for (const item of roomJoinedMessage.getItemList()) {
|
||||||
|
items[item.getItemid()] = JSON.parse(item.getStatejson());
|
||||||
}
|
}
|
||||||
|
|
||||||
const listeners = this.batchCallbacks.get(event);
|
this.resolveJoinRoom({
|
||||||
if (listeners === undefined) {
|
users,
|
||||||
continue;
|
groups,
|
||||||
}
|
items
|
||||||
for (const listener of listeners) {
|
})
|
||||||
listener(payload);
|
} else if (message.hasSetuseridmessage()) {
|
||||||
}
|
this.userId = (message.getSetuseridmessage() as SetUserIdMessage).getUserid();
|
||||||
|
} else if (message.hasErrormessage()) {
|
||||||
|
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createConnection(name: string, characterLayersSelected: string[]): Promise<Connection> {
|
public static createConnection(name: string, characterLayersSelected: string[]): Promise<Connection> {
|
||||||
@ -203,18 +229,23 @@ export class Connection implements Connection {
|
|||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
const message = new SetPlayerDetailsMessage();
|
connection.onConnect(() => {
|
||||||
message.setName(name);
|
const message = new SetPlayerDetailsMessage();
|
||||||
message.setCharacterlayersList(characterLayersSelected);
|
message.setName(name);
|
||||||
connection.socket.emit(EventMessage.SET_PLAYER_DETAILS, message.serializeBinary().buffer, (id: number) => {
|
message.setCharacterlayersList(characterLayersSelected);
|
||||||
connection.userId = id;
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve(connection);
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setSetplayerdetailsmessage(message);
|
||||||
|
|
||||||
|
connection.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
|
||||||
|
resolve(connection);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
// Let's retry in 4-6 seconds
|
// Let's retry in 4-6 seconds
|
||||||
|
console.error('Connection failed. Retrying', err);
|
||||||
return new Promise<Connection>((resolve, reject) => {
|
return new Promise<Connection>((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Connection.createConnection(name, characterLayersSelected).then((connection) => resolve(connection))
|
Connection.createConnection(name, characterLayersSelected).then((connection) => resolve(connection))
|
||||||
@ -228,24 +259,30 @@ export class Connection implements Connection {
|
|||||||
this.socket?.close();
|
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> {
|
public joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean, viewport: ViewportInterface): Promise<RoomJoinedMessageInterface> {
|
||||||
const promise = new Promise<RoomJoinedMessageInterface>((resolve, reject) => {
|
const promise = new Promise<RoomJoinedMessageInterface>((resolve, reject) => {
|
||||||
this.socket.emit(EventMessage.JOIN_ROOM, {
|
this.resolveJoinRoom = resolve;
|
||||||
roomId,
|
|
||||||
position: {x: startX, y: startY, direction, moving },
|
const positionMessage = this.toPositionMessage(startX, startY, direction, moving);
|
||||||
viewport,
|
const viewportMessage = this.toViewportMessage(viewport);
|
||||||
}, (roomJoinedMessage: RoomJoinedMessageInterface) => {
|
|
||||||
resolve(roomJoinedMessage);
|
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;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sharePosition(x : number, y : number, direction : string, moving: boolean, viewport: ViewportInterface) : void{
|
private toPositionMessage(x : number, y : number, direction : string, moving: boolean): PositionMessage {
|
||||||
if(!this.socket){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const positionMessage = new PositionMessage();
|
const positionMessage = new PositionMessage();
|
||||||
positionMessage.setX(Math.floor(x));
|
positionMessage.setX(Math.floor(x));
|
||||||
positionMessage.setY(Math.floor(y));
|
positionMessage.setY(Math.floor(y));
|
||||||
@ -269,23 +306,47 @@ export class Connection implements Connection {
|
|||||||
positionMessage.setDirection(directionEnum);
|
positionMessage.setDirection(directionEnum);
|
||||||
positionMessage.setMoving(moving);
|
positionMessage.setMoving(moving);
|
||||||
|
|
||||||
|
return positionMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toViewportMessage(viewport: ViewportInterface): ViewportMessage {
|
||||||
const viewportMessage = new ViewportMessage();
|
const viewportMessage = new ViewportMessage();
|
||||||
viewportMessage.setLeft(Math.floor(viewport.left));
|
viewportMessage.setLeft(Math.floor(viewport.left));
|
||||||
viewportMessage.setRight(Math.floor(viewport.right));
|
viewportMessage.setRight(Math.floor(viewport.right));
|
||||||
viewportMessage.setTop(Math.floor(viewport.top));
|
viewportMessage.setTop(Math.floor(viewport.top));
|
||||||
viewportMessage.setBottom(Math.floor(viewport.bottom));
|
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();
|
const userMovesMessage = new UserMovesMessage();
|
||||||
userMovesMessage.setPosition(positionMessage);
|
userMovesMessage.setPosition(positionMessage);
|
||||||
userMovesMessage.setViewport(viewportMessage);
|
userMovesMessage.setViewport(viewportMessage);
|
||||||
|
|
||||||
//console.log('Sending position ', positionMessage.getX(), positionMessage.getY());
|
//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 {
|
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 {
|
public setViewport(viewport: ViewportInterface): void {
|
||||||
@ -295,25 +356,32 @@ export class Connection implements Connection {
|
|||||||
viewportMessage.setLeft(Math.round(viewport.left));
|
viewportMessage.setLeft(Math.round(viewport.left));
|
||||||
viewportMessage.setRight(Math.round(viewport.right));
|
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 {
|
public onUserJoins(callback: (message: MessageUserJoined) => void): void {
|
||||||
this.onBatchMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
|
this.onBatchMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
|
||||||
const position = message.getPosition();
|
callback(this.toMessageUserJoined(message));
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
public onUserMoved(callback: (message: UserMovedMessage) => void): void {
|
||||||
this.onBatchMessage(EventMessage.USER_MOVED, callback);
|
this.onBatchMessage(EventMessage.USER_MOVED, callback);
|
||||||
//this.socket.on(EventMessage.USER_MOVED, callback);
|
//this.socket.on(EventMessage.USER_MOVED, callback);
|
||||||
@ -339,64 +407,73 @@ export class Connection implements Connection {
|
|||||||
|
|
||||||
public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void {
|
public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void {
|
||||||
this.onBatchMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
|
this.onBatchMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
|
||||||
const position = message.getPosition();
|
callback(this.toGroupCreatedUpdatedMessage(message));
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
public onGroupDeleted(callback: (groupId: number) => void): void {
|
||||||
this.onBatchMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
|
this.onBatchMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
|
||||||
callback(message.getGroupid());
|
callback(message.getGroupid());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onConnectError(callback: (error: object) => void): void {
|
public onConnectError(callback: (error: Event) => void): void {
|
||||||
this.socket.on(EventMessage.CONNECT_ERROR, callback)
|
this.socket.addEventListener('error', callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
public onConnect(callback: (event: Event) => void): void {
|
||||||
|
this.socket.addEventListener('open', callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendWebrtcSignal(signal: unknown, receiverId: number) {
|
public sendWebrtcSignal(signal: unknown, receiverId: number) {
|
||||||
return this.socket.emit(EventMessage.WEBRTC_SIGNAL, {
|
/* return this.socket.emit(EventMessage.WEBRTC_SIGNAL, {
|
||||||
receiverId: receiverId,
|
receiverId: receiverId,
|
||||||
signal: signal
|
signal: signal
|
||||||
} as WebRtcSignalSentMessageInterface);
|
} as WebRtcSignalSentMessageInterface);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) {
|
public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) {
|
||||||
return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, {
|
/* return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, {
|
||||||
receiverId: receiverId,
|
receiverId: receiverId,
|
||||||
signal: signal
|
signal: signal
|
||||||
} as WebRtcSignalSentMessageInterface);
|
} as WebRtcSignalSentMessageInterface);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public receiveWebrtcStart(callback: (message: WebRtcStartMessageInterface) => void) {
|
public receiveWebrtcStart(callback: (message: WebRtcStartMessageInterface) => void) {
|
||||||
this.socket.on(EventMessage.WEBRTC_START, callback);
|
// TODO
|
||||||
|
// this.socket.on(EventMessage.WEBRTC_START, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
|
public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
|
||||||
return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
|
// TODO
|
||||||
|
// return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
|
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
|
||||||
return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback);
|
// TODO
|
||||||
|
// return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onServerDisconnected(callback: (reason: string) => void): void {
|
public onServerDisconnected(callback: (event: CloseEvent) => void): void {
|
||||||
this.socket.on('disconnect', (reason: string) => {
|
this.socket.addEventListener('close', (event) => {
|
||||||
if (reason === 'io client disconnect') {
|
|
||||||
// The client asks for disconnect, let's not trigger any event.
|
if (event.code === 1000) {
|
||||||
|
// Normal closure case
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback(reason);
|
callback(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -406,7 +483,8 @@ export class Connection implements Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
|
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
|
||||||
this.socket.on(EventMessage.WEBRTC_DISCONNECT, callback);
|
// TODO
|
||||||
|
// this.socket.on(EventMessage.WEBRTC_DISCONNECT, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void {
|
emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void {
|
||||||
@ -416,7 +494,10 @@ export class Connection implements Connection {
|
|||||||
itemEventMessage.setStatejson(JSON.stringify(state));
|
itemEventMessage.setStatejson(JSON.stringify(state));
|
||||||
itemEventMessage.setParametersjson(JSON.stringify(parameters));
|
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 {
|
onActionableEvent(callback: (message: ItemEventMessageInterface) => void): void {
|
||||||
|
@ -27,6 +27,10 @@ message ViewportMessage {
|
|||||||
int32 bottom = 4;
|
int32 bottom = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SilentMessage {
|
||||||
|
bool silent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*********** CLIENT TO SERVER MESSAGES *************/
|
/*********** CLIENT TO SERVER MESSAGES *************/
|
||||||
|
|
||||||
message SetPlayerDetailsMessage {
|
message SetPlayerDetailsMessage {
|
||||||
@ -34,11 +38,29 @@ message SetPlayerDetailsMessage {
|
|||||||
repeated string characterLayers = 2;
|
repeated string characterLayers = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message JoinRoomMessage {
|
||||||
|
string roomId = 1;
|
||||||
|
PositionMessage position = 2;
|
||||||
|
ViewportMessage viewport = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message UserMovesMessage {
|
message UserMovesMessage {
|
||||||
PositionMessage position = 1;
|
PositionMessage position = 1;
|
||||||
ViewportMessage viewport = 2;
|
ViewportMessage viewport = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ClientToServerMessage {
|
||||||
|
oneof message {
|
||||||
|
JoinRoomMessage joinRoomMessage = 1;
|
||||||
|
UserMovesMessage userMovesMessage = 2;
|
||||||
|
SilentMessage silentMessage = 3;
|
||||||
|
ViewportMessage viewportMessage = 4;
|
||||||
|
ItemEventMessage itemEventMessage = 5;
|
||||||
|
SetPlayerDetailsMessage setPlayerDetailsMessage = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************ BI-DIRECTIONAL MESSAGES **************/
|
/************ BI-DIRECTIONAL MESSAGES **************/
|
||||||
|
|
||||||
message ItemEventMessage {
|
message ItemEventMessage {
|
||||||
@ -90,3 +112,44 @@ message UserJoinedMessage {
|
|||||||
message UserLeftMessage {
|
message UserLeftMessage {
|
||||||
int32 userId = 1;
|
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 itemId = 1;
|
||||||
|
string event = 2;
|
||||||
|
string stateJson = 3;
|
||||||
|
string parametersJson = 4;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
message ServerToClientMessage {
|
||||||
|
oneof message {
|
||||||
|
BatchMessage batchMessage = 1;
|
||||||
|
ErrorMessage errorMessage = 2;
|
||||||
|
RoomJoinedMessage roomJoinedMessage = 3;
|
||||||
|
SetUserIdMessage setUserIdMessage = 4; // TODO: merge this with RoomJoinedMessage ?
|
||||||
|
// WebRtcStartMessage webRtcStartMessage = 3;
|
||||||
|
// WebRtcSignalMessage webRtcSignalMessage = 4;
|
||||||
|
// WebRtcScreenSharingSignalMessage webRtcScreenSharingSignalMessage = 5;
|
||||||
|
// WebRtcDisconnectMessage webRtcDisconnectMessage = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user