Merge pull request #793 from thecodingmachine/adminWorldsLimit

FEATURE: the connexion error an user can get when a world is full is now correctly treated.
This commit is contained in:
Kharhamel 2021-03-09 17:45:43 +01:00 committed by GitHub
commit 21cc842c33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 127 additions and 215 deletions

View File

@ -77,8 +77,10 @@ export class TypeMessageExt implements TypeMessageInterface{
} }
} }
} }
export class Ban extends TypeMessageExt {
} export class Message extends TypeMessageExt {}
export class Ban extends TypeMessageExt {}
export class Banned extends TypeMessageExt { export class Banned extends TypeMessageExt {
showMessage(message: string){ showMessage(message: string){

View File

@ -6,11 +6,22 @@ import {GameConnexionTypes, urlManager} from "../Url/UrlManager";
import {localUserStore} from "./LocalUserStore"; import {localUserStore} from "./LocalUserStore";
import {LocalUser} from "./LocalUser"; import {LocalUser} from "./LocalUser";
import {Room} from "./Room"; import {Room} from "./Room";
import {Subject} from "rxjs";
export enum ConnexionMessageEventTypes {
worldFull = 1,
}
export interface ConnexionMessageEvent {
type: ConnexionMessageEventTypes,
}
class ConnectionManager { class ConnectionManager {
private localUser!:LocalUser; private localUser!:LocalUser;
private connexionType?: GameConnexionTypes private connexionType?: GameConnexionTypes
public _connexionMessageStream:Subject<ConnexionMessageEvent> = new Subject();
/** /**
* Tries to login to the node server and return the starting map url to be loaded * Tries to login to the node server and return the starting map url to be loaded
*/ */

View File

@ -42,14 +42,6 @@ export interface PointInterface {
moving: boolean; moving: boolean;
} }
export class Point implements PointInterface{
constructor(public x : number, public y : number, public direction : string = PlayerAnimationNames.WalkDown, public moving : boolean = false) {
if(x === null || y === null){
throw Error("position x and y cannot be null");
}
}
}
export interface MessageUserPositionInterface { export interface MessageUserPositionInterface {
userId: number; userId: number;
name: string; name: string;
@ -80,20 +72,10 @@ export interface GroupCreatedUpdatedMessageInterface {
groupSize: number groupSize: number
} }
export interface WebRtcStartMessageInterface {
roomId: string,
clients: UserSimplePeerInterface[]
}
export interface WebRtcDisconnectMessageInterface { export interface WebRtcDisconnectMessageInterface {
userId: number userId: number
} }
export interface WebRtcSignalSentMessageInterface {
receiverId: number,
signal: SignalData
}
export interface WebRtcSignalReceivedMessageInterface { export interface WebRtcSignalReceivedMessageInterface {
userId: number, userId: number,
signal: SignalData, signal: SignalData,
@ -113,11 +95,6 @@ export interface ViewportInterface {
bottom: number, bottom: number,
} }
export interface BatchedMessageInterface {
event: string,
payload: unknown
}
export interface ItemEventMessageInterface { export interface ItemEventMessageInterface {
itemId: number, itemId: number,
event: string, event: string,

View File

@ -43,6 +43,7 @@ import {
} from "./ConnexionModels"; } from "./ConnexionModels";
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures"; import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
import {adminMessagesService} from "./AdminMessagesService"; import {adminMessagesService} from "./AdminMessagesService";
import {connectionManager, ConnexionMessageEventTypes} from "./ConnectionManager";
const manualPingDelay = 20000; const manualPingDelay = 20000;
@ -101,7 +102,7 @@ export class RoomConnection implements RoomConnection {
} }
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry. // If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
if (this.userId === null) { if (this.userId === null && !this.closed) {
this.dispatch(EventMessage.CONNECTING_ERROR, event); this.dispatch(EventMessage.CONNECTING_ERROR, event);
} }
}); });
@ -156,7 +157,8 @@ export class RoomConnection implements RoomConnection {
} as RoomJoinedMessageInterface } as RoomJoinedMessageInterface
}); });
} else if (message.hasErrormessage()) { } else if (message.hasErrormessage()) {
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage()); connectionManager._connexionMessageStream.next({type: ConnexionMessageEventTypes.worldFull}); //todo: generalize this behavior to all messages
this.closed = true;
} else if (message.hasWebrtcsignaltoclientmessage()) { } else if (message.hasWebrtcsignaltoclientmessage()) {
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage()); this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) { } else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {

View File

@ -3,25 +3,15 @@ import {
GroupCreatedUpdatedMessageInterface, GroupCreatedUpdatedMessageInterface,
MessageUserJoined, MessageUserJoined,
MessageUserMovedInterface, MessageUserMovedInterface,
MessageUserPositionInterface, OnConnectInterface, MessageUserPositionInterface,
OnConnectInterface,
PointInterface, PointInterface,
PositionInterface, PositionInterface,
RoomJoinedMessageInterface RoomJoinedMessageInterface
} from "../../Connexion/ConnexionModels"; } from "../../Connexion/ConnexionModels";
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player"; import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
import { import {DEBUG_MODE, JITSI_PRIVATE_MODE, POSITION_DELAY, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
DEBUG_MODE, import {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, ITiledTileSet} from "../Map/ITiledMap";
JITSI_PRIVATE_MODE,
POSITION_DELAY,
RESOLUTION,
ZOOM_LEVEL
} from "../../Enum/EnvironmentVariable";
import {
ITiledMap,
ITiledMapLayer,
ITiledMapLayerProperty, ITiledMapObject,
ITiledTileSet
} from "../Map/ITiledMap";
import {AddPlayerInterface} from "./AddPlayerInterface"; import {AddPlayerInterface} from "./AddPlayerInterface";
import {PlayerAnimationNames} from "../Player/Animation"; import {PlayerAnimationNames} from "../Player/Animation";
import {PlayerMovement} from "./PlayerMovement"; import {PlayerMovement} from "./PlayerMovement";
@ -41,11 +31,6 @@ import {
TRIGGER_WEBSITE_PROPERTIES, TRIGGER_WEBSITE_PROPERTIES,
WEBSITE_MESSAGE_PROPERTIES WEBSITE_MESSAGE_PROPERTIES
} from "../../WebRtc/LayoutManager"; } from "../../WebRtc/LayoutManager";
import Texture = Phaser.Textures.Texture;
import Sprite = Phaser.GameObjects.Sprite;
import CanvasTexture = Phaser.Textures.CanvasTexture;
import GameObject = Phaser.GameObjects.GameObject;
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {GameMap} from "./GameMap"; import {GameMap} from "./GameMap";
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager"; import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
import {mediaManager} from "../../WebRtc/MediaManager"; import {mediaManager} from "../../WebRtc/MediaManager";
@ -54,7 +39,7 @@ import {ActionableItem} from "../Items/ActionableItem";
import {UserInputManager} from "../UserInput/UserInputManager"; import {UserInputManager} from "../UserInput/UserInputManager";
import {UserMovedMessage} from "../../Messages/generated/messages_pb"; import {UserMovedMessage} from "../../Messages/generated/messages_pb";
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils"; import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
import {connectionManager} from "../../Connexion/ConnectionManager"; import {connectionManager, ConnexionMessageEvent, ConnexionMessageEventTypes} from "../../Connexion/ConnectionManager";
import {RoomConnection} from "../../Connexion/RoomConnection"; import {RoomConnection} from "../../Connexion/RoomConnection";
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager"; import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
import {userMessageManager} from "../../Administration/UserMessageManager"; import {userMessageManager} from "../../Administration/UserMessageManager";
@ -72,6 +57,12 @@ import {TextureError} from "../../Exception/TextureError";
import {addLoader} from "../Components/Loader"; import {addLoader} from "../Components/Loader";
import {ErrorSceneName} from "../Reconnecting/ErrorScene"; import {ErrorSceneName} from "../Reconnecting/ErrorScene";
import {localUserStore} from "../../Connexion/LocalUserStore"; import {localUserStore} from "../../Connexion/LocalUserStore";
import Texture = Phaser.Textures.Texture;
import Sprite = Phaser.GameObjects.Sprite;
import CanvasTexture = Phaser.Textures.CanvasTexture;
import GameObject = Phaser.GameObjects.GameObject;
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {Subscription} from "rxjs";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface|null, initPosition: PointInterface|null,
@ -157,11 +148,12 @@ export class GameScene extends ResizableScene implements CenterListener {
// The item that can be selected by pressing the space key. // The item that can be selected by pressing the space key.
private outlinedItem: ActionableItem|null = null; private outlinedItem: ActionableItem|null = null;
public userInputManager!: UserInputManager; public userInputManager!: UserInputManager;
private isReconnecting: boolean = false; private isReconnecting: boolean|undefined = undefined;
private startLayerName!: string | null; private startLayerName!: string | null;
private openChatIcon!: OpenChatIcon; private openChatIcon!: OpenChatIcon;
private playerName!: string; private playerName!: string;
private characterLayers!: string[]; private characterLayers!: string[];
private messageSubscription: Subscription|null = null;
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) { constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
super({ super({
@ -293,25 +285,6 @@ export class GameScene extends ResizableScene implements CenterListener {
} }
}); });
}); });
// import(/* webpackIgnore: true */ scriptUrl).then(result => {
//
// result.default.preload(this.load);
//
// this.load.start(); // Let's manually start the loader because the import might be over AFTER the loading ends.
// this.load.on('complete', () => {
// // FIXME: the factory might fail because the resources might not be loaded yet...
// // We would need to add a loader ended event in addition to the createPromise
// this.createPromise.then(() => {
// result.default.create(this);
//
// for (let object of objectsOfType) {
// // TODO: we should pass here a factory to create sprites (maybe?)
// let objectSprite = result.default.factory(this, object);
// }
// });
// });
// });
} }
} }
@ -330,6 +303,8 @@ export class GameScene extends ResizableScene implements CenterListener {
gameManager.gameSceneIsCreated(this); gameManager.gameSceneIsCreated(this);
urlManager.pushRoomIdToUrl(this.room); urlManager.pushRoomIdToUrl(this.room);
this.startLayerName = urlManager.getStartLayerNameFromUrl(); this.startLayerName = urlManager.getStartLayerNameFromUrl();
this.messageSubscription = connectionManager._connexionMessageStream.subscribe((event) => this.onConnexionMessage(event))
const playerName = gameManager.getPlayerName(); const playerName = gameManager.getPlayerName();
if (!playerName) { if (!playerName) {
@ -401,13 +376,13 @@ export class GameScene extends ResizableScene implements CenterListener {
this.scene.launch(ReconnectingSceneName); this.scene.launch(ReconnectingSceneName);
}, 0); }, 0);
} else if (this.connection === undefined) { } else if (this.connection === undefined) {
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking // Let's wait 1 second before printing the "connecting" screen to avoid blinking
setTimeout(() => { setTimeout(() => {
if (this.connection === undefined) { if (this.connection === undefined) {
this.scene.sleep(); this.scene.sleep();
this.scene.launch(ReconnectingSceneName); this.scene.launch(ReconnectingSceneName);
} }
}, 500); }, 1000);
} }
this.createPromiseResolve(); this.createPromiseResolve();
@ -569,8 +544,6 @@ export class GameScene extends ResizableScene implements CenterListener {
//init user position and play trigger to check layers properties //init user position and play trigger to check layers properties
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y); this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
return this.connection;
}); });
} }
@ -607,30 +580,7 @@ export class GameScene extends ResizableScene implements CenterListener {
contextRed.stroke(); contextRed.stroke();
this.circleRedTexture.refresh(); this.circleRedTexture.refresh();
} }
private playAudio(url: string|number|boolean|undefined, loop=false): void {
if (url === undefined) {
audioManager.unloadAudio();
} else {
const audioPath = url as string;
let realAudioPath = '';
if (audioPath.indexOf('://') > 0) {
// remote file or stream
realAudioPath = audioPath;
} else {
// local file, include it relative to map directory
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
realAudioPath = mapDirUrl + '/' + url;
}
audioManager.loadAudio(realAudioPath);
if (loop) {
audioManager.loop();
}
}
}
private safeParseJSONstring(jsonString: string|undefined, propertyName: string) { private safeParseJSONstring(jsonString: string|undefined, propertyName: string) {
try { try {
@ -711,15 +661,19 @@ export class GameScene extends ResizableScene implements CenterListener {
} }
}); });
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => { this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
this.playAudio(newValue); newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
}); });
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => { this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
this.playAudio(newValue, true); newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
}); });
} }
private getMapDirUrl(): string {
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
}
private onMapExit(exitKey: string) { private onMapExit(exitKey: string) {
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey); if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
@ -745,14 +699,11 @@ export class GameScene extends ResizableScene implements CenterListener {
// stop playing audio, close any open website, stop any open Jitsi // stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsite(); coWebsiteManager.closeCoWebsite();
this.stopJitsi(); this.stopJitsi();
this.playAudio(undefined); audioManager.unloadAudio();
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map. // We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
if(this.connection) { this.connection?.closeConnection();
this.connection.closeConnection(); this.simplePeer?.unregister();
} this.messageSubscription?.unsubscribe();
if(this.simplePeer) {
this.simplePeer.unregister();
}
} }
private removeAllRemotePlayers(): void { private removeAllRemotePlayers(): void {
@ -1267,21 +1218,34 @@ export class GameScene extends ResizableScene implements CenterListener {
} }
public stopJitsi(): void { public stopJitsi(): void {
this.connection.setSilent(false); this.connection?.setSilent(false);
jitsiFactory.stop(); jitsiFactory.stop();
mediaManager.showGameOverlay(); mediaManager.showGameOverlay();
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi'); mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
} }
//todo: into onConnexionMessage
private bannedUser(){ private bannedUser(){
this.cleanupClosingScene(); this.cleanupClosingScene();
this.userInputManager.clearAllKeys(); this.userInputManager.clearAllKeys();
this.scene.start(ErrorSceneName, { this.scene.start(ErrorSceneName, {
title: 'Banned', title: 'Banned',
subTitle: 'You was banned of WorkAdventure', subTitle: 'You were banned from WorkAdventure',
message: 'If you want more information, you can contact us: workadventure@thecodingmachine.com' message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
}); });
} }
private onConnexionMessage(event: ConnexionMessageEvent) {
if (event.type === ConnexionMessageEventTypes.worldFull) {
this.cleanupClosingScene();
this.scene.stop(ReconnectingSceneName);
this.userInputManager.clearAllKeys();
this.scene.start(ErrorSceneName, {
title: 'Connection rejected',
subTitle: 'The world you are trying to join is full. Try again later.',
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
});
}
}
} }

View File

@ -38,6 +38,25 @@ class AudioManager {
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume; HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
} }
public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void {
const audioPath = url as string;
let realAudioPath = '';
if (audioPath.indexOf('://') > 0) {
// remote file or stream
realAudioPath = audioPath;
} else {
// local file, include it relative to map directory
realAudioPath = mapDirUrl + '/' + url;
}
this.loadAudio(realAudioPath);
if (loop) {
this.loop();
}
}
private close(): void { private close(): void {
this.audioPlayerCtrl.classList.remove('loading'); this.audioPlayerCtrl.classList.remove('loading');
this.audioPlayerCtrl.classList.add('hidden'); this.audioPlayerCtrl.classList.add('hidden');
@ -75,7 +94,7 @@ class AudioManager {
} }
public loadAudio(url: string): void { private loadAudio(url: string): void {
this.load(); this.load();
/* Solution 1, remove whole audio player */ /* Solution 1, remove whole audio player */
@ -125,7 +144,7 @@ class AudioManager {
this.open(); this.open();
} }
public loop(): void { private loop(): void {
if (this.audioPlayerElem !== undefined) { if (this.audioPlayerElem !== undefined) {
this.audioPlayerElem.loop = true; this.audioPlayerElem.loop = true;
} }

View File

@ -1,5 +1,5 @@
import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.." import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
import {GameRoomPolicyTypes} from "../Model/PusherRoom"; import {GameRoomPolicyTypes, PusherRoom} from "../Model/PusherRoom";
import {PointInterface} from "../Model/Websocket/PointInterface"; import {PointInterface} from "../Model/Websocket/PointInterface";
import { import {
SetPlayerDetailsMessage, SetPlayerDetailsMessage,
@ -20,7 +20,7 @@ import {parse} from "query-string";
import {jwtTokenManager} from "../Services/JWTTokenManager"; import {jwtTokenManager} from "../Services/JWTTokenManager";
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi"; import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
import {SocketManager, socketManager} from "../Services/SocketManager"; import {SocketManager, socketManager} from "../Services/SocketManager";
import {emitInBatch} from "../Services/IoSocketHelpers"; import {emitError, emitInBatch} from "../Services/IoSocketHelpers";
import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable"; import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
import {Zone} from "_Model/Zone"; import {Zone} from "_Model/Zone";
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface"; import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
@ -108,7 +108,6 @@ export class IoSocketController {
maxBackpressure: 65536, // Maximum 64kB of data in the buffer. maxBackpressure: 65536, // Maximum 64kB of data in the buffer.
//idleTimeout: 10, //idleTimeout: 10,
upgrade: (res, req, context) => { upgrade: (res, req, context) => {
//console.log('An Http connection wants to become WebSocket, URL: ' + req.getUrl() + '!');
(async () => { (async () => {
/* Keep track of abortions */ /* Keep track of abortions */
const upgradeAborted = {aborted: false}; const upgradeAborted = {aborted: false};
@ -156,12 +155,9 @@ export class IoSocketController {
const userUuid = await jwtTokenManager.getUserUuidFromToken(token, IPAddress, roomId); const userUuid = await jwtTokenManager.getUserUuidFromToken(token, IPAddress, roomId);
let memberTags: string[] = []; let memberTags: string[] = [];
let memberMessages: unknown;
let memberTextures: CharacterTexture[] = []; let memberTextures: CharacterTexture[] = [];
const room = await socketManager.getOrCreateRoom(roomId); const room = await socketManager.getOrCreateRoom(roomId);
// TODO: make sure the room isFull is ported in the back part.
/*if(room.isFull){
throw new Error('Room is full');
}*/
if (ADMIN_API_URL) { if (ADMIN_API_URL) {
try { try {
let userData : FetchMemberDataByUuidResponse = { let userData : FetchMemberDataByUuidResponse = {
@ -172,15 +168,26 @@ export class IoSocketController {
anonymous: true anonymous: true
}; };
try { try {
userData = await adminApi.fetchMemberDataByUuid(userUuid); userData = await adminApi.fetchMemberDataByUuid(userUuid, roomId);
}catch (err){ }catch (err){
if (err?.response?.status == 404) { if (err?.response?.status == 404) {
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login! // If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
console.warn('Cannot find user with uuid "'+userUuid+'". Performing an anonymous login instead.'); console.warn('Cannot find user with uuid "'+userUuid+'". Performing an anonymous login instead.');
} else if(err?.response?.status == 403) {
// If we get an HTTP 404, the world is full. We need to broadcast a special error to the client.
// we finish immediatly the upgrade then we will close the socket as soon as it starts opening.
res.upgrade({
rejected: true,
}, websocketKey,
websocketProtocol,
websocketExtensions,
context);
return;
}else{ }else{
throw err; throw err;
} }
} }
memberMessages = userData.messages;
memberTags = userData.tags; memberTags = userData.tags;
memberTextures = userData.textures; memberTextures = userData.textures;
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && (userData.anonymous === true || !room.canAccess(memberTags))) { if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && (userData.anonymous === true || !room.canAccess(memberTags))) {
@ -215,6 +222,7 @@ export class IoSocketController {
roomId, roomId,
name, name,
characterLayers: characterLayerObjs, characterLayers: characterLayerObjs,
messages: memberMessages,
tags: memberTags, tags: memberTags,
textures: memberTextures, textures: memberTextures,
position: { position: {
@ -241,7 +249,6 @@ export class IoSocketController {
console.log(e.message); console.log(e.message);
res.writeStatus("401 Unauthorized").end(e.message); res.writeStatus("401 Unauthorized").end(e.message);
} else { } else {
console.log(e);
res.writeStatus("500 Internal Server Error").end('An error occurred'); res.writeStatus("500 Internal Server Error").end('An error occurred');
} }
return; return;
@ -250,32 +257,30 @@ export class IoSocketController {
}, },
/* Handlers */ /* Handlers */
open: (ws) => { open: (ws) => {
if(ws.rejected === true) {
emitError(ws, 'World is full');
ws.close();
}
// Let's join the room // Let's join the room
const client = this.initClient(ws); //todo: into the upgrade instead? const client = this.initClient(ws); //todo: into the upgrade instead?
socketManager.handleJoinRoom(client); socketManager.handleJoinRoom(client);
//get data information and show messages //get data information and show messages
if (ADMIN_API_URL) { if (client.messages && Array.isArray(client.messages)) {
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => { client.messages.forEach((c: unknown) => {
if (!res.messages) { const messageToSend = c as { type: string, message: string };
return;
const sendUserMessage = new SendUserMessage();
sendUserMessage.setType(messageToSend.type);
sendUserMessage.setMessage(messageToSend.message);
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setSendusermessage(sendUserMessage);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
} }
res.messages.forEach((c: unknown) => {
const messageToSend = c as { type: string, message: string };
const sendUserMessage = new SendUserMessage();
sendUserMessage.setType(messageToSend.type);
sendUserMessage.setMessage(messageToSend.message);
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setSendusermessage(sendUserMessage);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
});
}).catch((err) => {
console.error('fetchMemberDataByUuid => err', err);
}); });
} }
}, },
@ -340,6 +345,7 @@ export class IoSocketController {
} }
client.disconnecting = false; client.disconnecting = false;
client.messages = ws.messages;
client.name = ws.name; client.name = ws.name;
client.tags = ws.tags; client.tags = ws.tags;
client.textures = ws.textures; client.textures = ws.textures;

View File

@ -36,6 +36,7 @@ export interface ExSocketInterface extends WebSocket, Identificable {
batchedMessages: BatchMessage; batchedMessages: BatchMessage;
batchTimeout: NodeJS.Timeout|null; batchTimeout: NodeJS.Timeout|null;
disconnecting: boolean, disconnecting: boolean,
messages: unknown,
tags: string[], tags: string[],
textures: CharacterTexture[], textures: CharacterTexture[],
backConnection: BackConnection, backConnection: BackConnection,

View File

@ -58,12 +58,12 @@ class AdminApi {
return res.data; return res.data;
} }
async fetchMemberDataByUuid(uuid: string): Promise<FetchMemberDataByUuidResponse> { async fetchMemberDataByUuid(uuid: string, roomId: string): Promise<FetchMemberDataByUuidResponse> {
if (!ADMIN_API_URL) { if (!ADMIN_API_URL) {
return Promise.reject('No admin backoffice set!'); return Promise.reject('No admin backoffice set!');
} }
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid, const res = await Axios.get(ADMIN_API_URL+'/api/room/access',
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} } { params: {uuid, roomId}, headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
) )
return res.data; return res.data;
} }

View File

@ -1,5 +1,6 @@
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
import {BatchMessage, ErrorMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb"; import {BatchMessage, ErrorMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb";
import {WebSocket} from "uWebSockets.js";
export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void { export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
socket.batchedMessages.addPayload(payload); socket.batchedMessages.addPayload(payload);
@ -20,7 +21,7 @@ export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): voi
} }
} }
export function emitError(Client: ExSocketInterface, message: string): void { export function emitError(Client: WebSocket, message: string): void {
const errorMessage = new ErrorMessage(); const errorMessage = new ErrorMessage();
errorMessage.setMessage(message); errorMessage.setMessage(message);

View File

@ -4,7 +4,6 @@ import {
GroupDeleteMessage, GroupDeleteMessage,
ItemEventMessage, ItemEventMessage,
PlayGlobalMessage, PlayGlobalMessage,
PositionMessage,
RoomJoinedMessage, RoomJoinedMessage,
ServerToClientMessage, ServerToClientMessage,
SetPlayerDetailsMessage, SetPlayerDetailsMessage,
@ -25,21 +24,15 @@ import {
SendUserMessage, SendUserMessage,
BanUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage BanUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {PointInterface} from "../Model/Websocket/PointInterface";
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils"; import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
import {cpuTracker} from "./CpuTracker"; import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
import {Movable} from "../Model/Movable";
import {PositionInterface} from "../Model/PositionInterface";
import {adminApi, CharacterTexture} from "./AdminApi"; import {adminApi, CharacterTexture} from "./AdminApi";
import Direction = PositionMessage.Direction;
import {emitError, emitInBatch} from "./IoSocketHelpers"; import {emitError, emitInBatch} from "./IoSocketHelpers";
import Jwt from "jsonwebtoken"; import Jwt from "jsonwebtoken";
import {JITSI_URL} from "../Enum/EnvironmentVariable"; import {JITSI_URL} from "../Enum/EnvironmentVariable";
import {clientEventsEmitter} from "./ClientEventsEmitter"; import {clientEventsEmitter} from "./ClientEventsEmitter";
import {gaugeManager} from "./GaugeManager"; import {gaugeManager} from "./GaugeManager";
import {apiClientRepository} from "./ApiClientRepository"; import {apiClientRepository} from "./ApiClientRepository";
import {ServiceError} from "grpc";
import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone"; import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone";
import Debug from "debug"; import Debug from "debug";
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface"; import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
@ -408,17 +401,7 @@ export class SocketManager implements ZoneEventListener {
//check and create new world for a room //check and create new world for a room
let world = this.Worlds.get(roomId) let world = this.Worlds.get(roomId)
if(world === undefined){ if(world === undefined){
world = new PusherRoom( world = new PusherRoom(roomId, this);
roomId,
this
/* (user: User, group: Group) => this.joinWebRtcRoom(user, group),
(user: User, group: Group) => this.disConnectedUser(user, group),
MINIMUM_DISTANCE,
GROUP_RADIUS,
(thing: Movable, listener: User) => this.onRoomEnter(thing, listener),
(thing: Movable, position:PositionInterface, listener:User) => this.onClientMove(thing, position, listener),
(thing: Movable, listener:User) => this.onClientLeave(thing, listener)*/
);
if (!world.anonymous) { if (!world.anonymous) {
const data = await adminApi.fetchMapDetails(world.organizationSlug, world.worldSlug, world.roomSlug) const data = await adminApi.fetchMapDetails(world.organizationSlug, world.worldSlug, world.roomSlug)
world.tags = data.tags world.tags = data.tags
@ -429,60 +412,6 @@ export class SocketManager implements ZoneEventListener {
return Promise.resolve(world) return Promise.resolve(world)
} }
/* private joinRoom(client : ExSocketInterface, position: PointInterface): PusherRoom {
const roomId = client.roomId;
client.position = position;
const world = this.Worlds.get(roomId)
if(world === undefined){
throw new Error('Could not find room for ID: '+client.roomId)
}
// Dispatch groups position to newly connected user
world.getGroups().forEach((group: Group) => {
this.emitCreateUpdateGroupEvent(client, group);
});
//join world
world.join(client, client.position);
clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId);
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
return world;
}
private onClientMove(thing: Movable, position:PositionInterface, listener:User): void {
const clientListener = this.searchClientByIdOrFail(listener.id);
if (thing instanceof User) {
const clientUser = this.searchClientByIdOrFail(thing.id);
const userMovedMessage = new UserMovedMessage();
userMovedMessage.setUserid(clientUser.userId);
userMovedMessage.setPosition(ProtobufUtils.toPositionMessage(clientUser.position));
const subMessage = new SubMessage();
subMessage.setUsermovedmessage(userMovedMessage);
clientListener.emitInBatch(subMessage);
//console.log("Sending USER_MOVED event");
} else if (thing instanceof Group) {
this.emitCreateUpdateGroupEvent(clientListener, thing);
} else {
console.error('Unexpected type for Movable.');
}
}
private onClientLeave(thing: Movable, listener:User) {
const clientListener = this.searchClientByIdOrFail(listener.id);
if (thing instanceof User) {
const clientUser = this.searchClientByIdOrFail(thing.id);
this.emitUserLeftEvent(clientListener, clientUser.userId);
} else if (thing instanceof Group) {
this.emitDeleteGroupEvent(clientListener, thing.getId());
} else {
console.error('Unexpected type for Movable.');
}
}*/
emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) { emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) {
const pusherToBackMessage = new PusherToBackMessage(); const pusherToBackMessage = new PusherToBackMessage();
pusherToBackMessage.setPlayglobalmessage(playglobalmessage); pusherToBackMessage.setPlayglobalmessage(playglobalmessage);