From 925545d74f1cee7794eadd9ac91d2c47a45d3ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gr=C3=A9goire=20parant?= Date: Thu, 29 Apr 2021 23:47:30 +0200 Subject: [PATCH] Add error message (#970) - Error link not found - Error user was banned - Error access dinied on the world --- front/src/Connexion/RoomConnection.ts | 8 +++- front/src/Connexion/WorldFullMessageStream.ts | 6 +-- front/src/Phaser/Game/GameScene.ts | 26 +++++++---- front/src/Phaser/Login/EntryScene.ts | 5 ++- front/src/Phaser/Reconnecting/ErrorScene.ts | 2 +- messages/protos/messages.proto | 5 +++ pusher/src/Controller/IoSocketController.ts | 43 ++++++++++++------- pusher/src/Services/SocketManager.ts | 11 +++++ 8 files changed, 76 insertions(+), 30 deletions(-) diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 946238b2..101bdd61 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -27,7 +27,8 @@ import { SendJitsiJwtMessage, CharacterLayerMessage, PingMessage, - SendUserMessage, BanUserMessage + SendUserMessage, + BanUserMessage } from "../Messages/generated/messages_pb" import {UserSimplePeerInterface} from "../WebRtc/SimplePeer"; @@ -169,7 +170,10 @@ export class RoomConnection implements RoomConnection { } else if (message.hasWorldfullmessage()) { worldFullMessageStream.onMessage(); this.closed = true; - } else if (message.hasWebrtcsignaltoclientmessage()) { + } else if (message.hasWorldconnexionmessage()) { + worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); + this.closed = true; + }else if (message.hasWebrtcsignaltoclientmessage()) { this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage()); } else if (message.hasWebrtcscreensharingsignaltoclientmessage()) { this.dispatch(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, message.getWebrtcscreensharingsignaltoclientmessage()); diff --git a/front/src/Connexion/WorldFullMessageStream.ts b/front/src/Connexion/WorldFullMessageStream.ts index c02530fa..c9f65d84 100644 --- a/front/src/Connexion/WorldFullMessageStream.ts +++ b/front/src/Connexion/WorldFullMessageStream.ts @@ -2,12 +2,12 @@ import {Subject} from "rxjs"; class WorldFullMessageStream { - private _stream:Subject = new Subject(); + private _stream:Subject = new Subject(); public stream = this._stream.asObservable(); - onMessage() { - this._stream.next(); + onMessage(message? :string) { + this._stream.next(message); } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index a1b5e98e..e2b07b13 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -372,7 +372,7 @@ export class GameScene extends ResizableScene implements CenterListener { new PinchManager(this); } - this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError()) + this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError(message)) const playerName = gameManager.getPlayerName(); if (!playerName) { @@ -909,7 +909,7 @@ ${escapedMessage} audioManager.unloadAudio(); // We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map. this.connection?.closeConnection(); - this.simplePeer.closeAllConnections(); + this.simplePeer?.closeAllConnections(); this.simplePeer?.unregister(); this.messageSubscription?.unsubscribe(); @@ -1488,14 +1488,24 @@ ${escapedMessage} } //todo: put this into an 'orchestrator' scene (EntryScene?) - private showWorldFullError(): void { + private showWorldFullError(message: string|null): void { this.cleanupClosingScene(); this.scene.stop(ReconnectingSceneName); + this.scene.remove(ReconnectingSceneName); this.userInputManager.disableControls(); - 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' - }); + //FIX ME to use status code + if(message == undefined){ + 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' + }); + }else{ + this.scene.start(ErrorSceneName, { + title: 'Connection rejected', + subTitle: 'You cannot join the World. Try again later. \n\r \n\r Error: '+message+'.', + message: 'If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com' + }); + } } } diff --git a/front/src/Phaser/Login/EntryScene.ts b/front/src/Phaser/Login/EntryScene.ts index 75ee0272..e7650750 100644 --- a/front/src/Phaser/Login/EntryScene.ts +++ b/front/src/Phaser/Login/EntryScene.ts @@ -21,7 +21,10 @@ export class EntryScene extends Scene { this.scene.start(nextSceneName); }).catch((err) => { if (err.response && err.response.status == 404) { - ErrorScene.showError(new WAError('Page Not Found', 'Could not find map', window.location.pathname), this.scene); + ErrorScene.showError(new WAError( + 'Access link incorrect', + 'Could not find map. Please check your access link.', + 'If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com'), this.scene); } else { ErrorScene.showError(err, this.scene); } diff --git a/front/src/Phaser/Reconnecting/ErrorScene.ts b/front/src/Phaser/Reconnecting/ErrorScene.ts index 921eeb58..dbde2628 100644 --- a/front/src/Phaser/Reconnecting/ErrorScene.ts +++ b/front/src/Phaser/Reconnecting/ErrorScene.ts @@ -52,7 +52,7 @@ export class ErrorScene extends Phaser.Scene { this.subTitleField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2 + 24, this.subTitle); - this.messageField = this.add.text(this.game.renderer.width / 2, this.game.renderer.height / 2 + 38, this.message, { + this.messageField = this.add.text(this.game.renderer.width / 2, this.game.renderer.height / 2 + 48, this.message, { fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif', fontSize: '10px' }); diff --git a/messages/protos/messages.proto b/messages/protos/messages.proto index b3d4e755..52ca4d50 100644 --- a/messages/protos/messages.proto +++ b/messages/protos/messages.proto @@ -218,6 +218,10 @@ message RefreshRoomMessage{ message WorldFullMessage{ } +message WorldConnexionMessage{ + string message = 2; +} + message BanUserMessage{ string type = 1; string message = 2; @@ -242,6 +246,7 @@ message ServerToClientMessage { WorldFullWarningMessage worldFullWarningMessage = 15; WorldFullMessage worldFullMessage = 16; RefreshRoomMessage refreshRoomMessage = 17; + WorldConnexionMessage worldConnexionMessage = 18; } } diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 87051bbc..5a3a362b 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -117,15 +117,15 @@ export class IoSocketController { upgradeAborted.aborted = true; }); - try { - const url = req.getUrl(); - const query = parse(req.getQuery()); - const websocketKey = req.getHeader('sec-websocket-key'); - const websocketProtocol = req.getHeader('sec-websocket-protocol'); - const websocketExtensions = req.getHeader('sec-websocket-extensions'); - const IPAddress = req.getHeader('x-forwarded-for'); + const url = req.getUrl(); + const query = parse(req.getQuery()); + const websocketKey = req.getHeader('sec-websocket-key'); + const websocketProtocol = req.getHeader('sec-websocket-protocol'); + const websocketExtensions = req.getHeader('sec-websocket-extensions'); + const IPAddress = req.getHeader('x-forwarded-for'); - const roomId = query.roomId; + const roomId = query.roomId; + try { if (typeof roomId !== 'string') { throw new Error('Undefined room ID: '); } @@ -184,13 +184,14 @@ export class IoSocketController { } 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({ + return res.upgrade({ rejected: true, + message: err?.response?.data.message, + status: err?.response?.status }, websocketKey, websocketProtocol, websocketExtensions, context); - return; }else{ throw err; } @@ -207,7 +208,7 @@ export class IoSocketController { } catch (e) { console.log('access not granted for user '+userUuid+' and room '+roomId); console.error(e); - throw new Error('Client cannot acces this ressource.') + throw new Error('User cannot acces on this world') } } @@ -254,21 +255,33 @@ export class IoSocketController { context); } catch (e) { - if (e instanceof Error) { + /*if (e instanceof Error) { console.log(e.message); res.writeStatus("401 Unauthorized").end(e.message); } else { res.writeStatus("500 Internal Server Error").end('An error occurred'); - } - return; + }*/ + return res.upgrade({ + rejected: true, + message: e.message ? e.message : '500 Internal Server Error' + }, websocketKey, + websocketProtocol, + websocketExtensions, + context); } })(); }, /* Handlers */ open: (ws) => { if(ws.rejected === true) { - socketManager.emitWorldFullMessage(ws); + //FIX ME to use status code + if(ws.message === 'World is full'){ + socketManager.emitWorldFullMessage(ws); + }else{ + socketManager.emitConnexionErrorMessage(ws, ws.message as string); + } ws.close(); + return; } // Let's join the room diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 726e11a1..d692186a 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -20,6 +20,7 @@ import { CharacterLayerMessage, PusherToBackMessage, WorldFullMessage, + WorldConnexionMessage, AdminPusherToBackMessage, ServerToAdminClientMessage, UserJoinedRoomMessage, UserLeftRoomMessage, AdminMessage, BanMessage, RefreshRoomMessage @@ -560,6 +561,16 @@ export class SocketManager implements ZoneEventListener { client.send(serverToClientMessage.serializeBinary().buffer, true); } + public emitConnexionErrorMessage(client: WebSocket, message: string) { + const errorMessage = new WorldConnexionMessage(); + errorMessage.setMessage(message); + + const serverToClientMessage = new ServerToClientMessage(); + serverToClientMessage.setWorldconnexionmessage(errorMessage); + + client.send(serverToClientMessage.serializeBinary().buffer, true); + } + private refreshRoomData(roomId: string, versionNumber: number): void { const room = this.rooms.get(roomId); //this function is run for every users connected to the room, so we need to make sure the room wasn't already refreshed.