Merge remote-tracking branch 'upstream/develop' into main

This commit is contained in:
_Bastler 2021-03-25 11:15:59 +01:00
commit 0e10a76eeb
19 changed files with 203 additions and 79 deletions

View File

@ -15,7 +15,7 @@ import {
ServerToClientMessage, ServerToClientMessage,
SilentMessage, SilentMessage,
UserMovesMessage, UserMovesMessage,
WebRtcSignalToServerMessage, WebRtcSignalToServerMessage, WorldFullWarningToRoomMessage,
ZoneMessage ZoneMessage
} from "./Messages/generated/messages_pb"; } from "./Messages/generated/messages_pb";
import {sendUnaryData, ServerDuplexStream, ServerUnaryCall, ServerWritableStream} from "grpc"; import {sendUnaryData, ServerDuplexStream, ServerUnaryCall, ServerWritableStream} from "grpc";
@ -184,6 +184,10 @@ const roomManager: IRoomManagerServer = {
socketManager.sendAdminRoomMessage(call.request.getRoomid(), call.request.getMessage()); socketManager.sendAdminRoomMessage(call.request.getRoomid(), call.request.getMessage());
callback(null, new EmptyMessage()); callback(null, new EmptyMessage());
}, },
sendWorldFullWarningToRoom(call: ServerUnaryCall<WorldFullWarningToRoomMessage>, callback: sendUnaryData<EmptyMessage>): void {
socketManager.dispatchWorlFullWarning(call.request.getRoomid());
callback(null, new EmptyMessage());
},
}; };
export {roomManager}; export {roomManager};

View File

@ -24,6 +24,7 @@ import {
UserJoinedZoneMessage, UserJoinedZoneMessage,
GroupUpdateZoneMessage, GroupUpdateZoneMessage,
GroupLeftZoneMessage, GroupLeftZoneMessage,
WorldFullWarningMessage,
UserLeftZoneMessage, UserLeftZoneMessage,
BanUserMessage, BanUserMessage,
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
@ -59,6 +60,7 @@ function emitZoneMessage(subMessage: SubToPusherMessage, socket: ZoneSocket): vo
const batchMessage = new BatchToPusherMessage(); const batchMessage = new BatchToPusherMessage();
batchMessage.addPayload(subMessage); batchMessage.addPayload(subMessage);
socket.write(batchMessage); socket.write(batchMessage);
} }
@ -298,20 +300,14 @@ export class SocketManager {
const roomId = joinRoomMessage.getRoomid(); const roomId = joinRoomMessage.getRoomid();
const world = await socketManager.getOrCreateRoom(roomId); const room = await socketManager.getOrCreateRoom(roomId);
// Dispatch groups position to newly connected user
/*world.getGroups().forEach((group: Group) => {
this.emitCreateUpdateGroupEvent(socket, group);
});*/
//join world //join world
const user = world.join(socket, joinRoomMessage); const user = room.join(socket, joinRoomMessage);
clientEventsEmitter.emitClientJoin(user.uuid, roomId); clientEventsEmitter.emitClientJoin(user.uuid, roomId);
//console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
console.log(new Date().toISOString() + ' A user joined'); console.log(new Date().toISOString() + ' A user joined');
return {room: world, user}; return {room, user};
} }
private onZoneEnter(thing: Movable, fromZone: Zone|null, listener: ZoneSocket) { private onZoneEnter(thing: Movable, fromZone: Zone|null, listener: ZoneSocket) {
@ -758,6 +754,24 @@ export class SocketManager {
recipient.socket.write(clientMessage); recipient.socket.write(clientMessage);
}); });
} }
dispatchWorlFullWarning(roomId: string,): void {
const room = this.rooms.get(roomId);
if (!room) {
//todo: this should cause the http call to return a 500
console.error("In sendAdminRoomMessage, could not find room with id '" + roomId + "'. Maybe the room was closed a few milliseconds ago and there was a race condition?");
return;
}
room.getUsers().forEach((recipient) => {
const worldFullMessage = new WorldFullWarningMessage();
const clientMessage = new ServerToClientMessage();
clientMessage.setWorldfullwarningmessage(worldFullMessage);
recipient.socket.write(clientMessage);
});
}
} }
export const socketManager = new SocketManager(); export const socketManager = new SocketManager();

View File

@ -0,0 +1,18 @@
<style>
#warningMain {
border-radius: 5px;
height: 100px;
width: 300px;
background-color: red;
text-align: center;
}
#warningMain h2 {
padding: 5px;
}
</style>
<main id="warningMain">
<h2>Warning!</h2>
<p>This world is close to its limit!</p>
</main>

View File

@ -7,21 +7,15 @@ import {localUserStore} from "./LocalUserStore";
import {LocalUser} from "./LocalUser"; import {LocalUser} from "./LocalUser";
import {Room} from "./Room"; import {Room} from "./Room";
import {Subject} from "rxjs"; import {Subject} from "rxjs";
import {ServerToClientMessage} from "../Messages/generated/messages_pb";
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(); public _serverToClientMessageStream:Subject<ServerToClientMessage> = 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

@ -8,6 +8,7 @@ const gameQualityKey = 'gameQuality';
const videoQualityKey = 'videoQuality'; const videoQualityKey = 'videoQuality';
const audioPlayerVolumeKey = 'audioVolume'; const audioPlayerVolumeKey = 'audioVolume';
const audioPlayerMuteKey = 'audioMute'; const audioPlayerMuteKey = 'audioMute';
const helpCameraSettingsShown = 'helpCameraSettingsShown';
class LocalUserStore { class LocalUserStore {
saveUser(localUser: LocalUser) { saveUser(localUser: LocalUser) {
@ -73,6 +74,13 @@ class LocalUserStore {
getAudioPlayerMuted(): boolean { getAudioPlayerMuted(): boolean {
return localStorage.getItem(audioPlayerMuteKey) === 'true'; return localStorage.getItem(audioPlayerMuteKey) === 'true';
} }
setHelpCameraSettingsShown(): void {
localStorage.setItem(helpCameraSettingsShown, '1');
}
getHelpCameraSettingsShown(): boolean {
return localStorage.getItem(helpCameraSettingsShown) === '1';
}
} }
export const localUserStore = new LocalUserStore(); export const localUserStore = new LocalUserStore();

View File

@ -43,7 +43,8 @@ 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"; import {worldFullMessageStream} from "./WorldFullMessageStream";
import {worldFullWarningStream} from "./WorldFullWarningStream";
const manualPingDelay = 20000; const manualPingDelay = 20000;
@ -156,8 +157,8 @@ export class RoomConnection implements RoomConnection {
items items
} as RoomJoinedMessageInterface } as RoomJoinedMessageInterface
}); });
} else if (message.hasErrormessage()) { } else if (message.hasWorldfullmessage()) {
connectionManager._connexionMessageStream.next({type: ConnexionMessageEventTypes.worldFull}); //todo: generalize this behavior to all messages worldFullMessageStream.onMessage();
this.closed = true; 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());
@ -179,6 +180,8 @@ export class RoomConnection implements RoomConnection {
adminMessagesService.onSendusermessage(message.getSendusermessage() as SendUserMessage); adminMessagesService.onSendusermessage(message.getSendusermessage() as SendUserMessage);
} else if (message.hasBanusermessage()) { } else if (message.hasBanusermessage()) {
adminMessagesService.onSendusermessage(message.getSendusermessage() as BanUserMessage); adminMessagesService.onSendusermessage(message.getSendusermessage() as BanUserMessage);
} else if (message.hasWorldfullwarningmessage()) {
worldFullWarningStream.onMessage();
} else { } else {
throw new Error('Unknown message received'); throw new Error('Unknown message received');
} }

View File

@ -0,0 +1,14 @@
import {Subject} from "rxjs";
class WorldFullMessageStream {
private _stream:Subject<void> = new Subject();
public stream = this._stream.asObservable();
onMessage() {
this._stream.next();
}
}
export const worldFullMessageStream = new WorldFullMessageStream();

View File

@ -0,0 +1,14 @@
import {Subject} from "rxjs";
class WorldFullWarningStream {
private _stream:Subject<void> = new Subject();
public stream = this._stream.asObservable();
onMessage() {
this._stream.next();
}
}
export const worldFullWarningStream = new WorldFullWarningStream();

View File

@ -0,0 +1,14 @@
export const warningContainerKey = 'warningContainer';
export const warningContainerHtml = 'resources/html/warningContainer.html';
export class WarningContainer extends Phaser.GameObjects.DOMElement {
constructor(scene: Phaser.Scene) {
super(scene, 100, 0);
this.setOrigin(0, 0);
this.createFromCache(warningContainerKey);
this.scene.add.existing(this);
}
}

View File

@ -86,7 +86,10 @@ export class GameManager {
console.log('starting '+ (this.currentGameSceneName || this.startRoom.id)) console.log('starting '+ (this.currentGameSceneName || this.startRoom.id))
scenePlugin.start(this.currentGameSceneName || this.startRoom.id); scenePlugin.start(this.currentGameSceneName || this.startRoom.id);
scenePlugin.launch(MenuSceneName); scenePlugin.launch(MenuSceneName);
scenePlugin.launch(HelpCameraSettingsSceneName);//700
if (!localUserStore.getHelpCameraSettingsShown()) {
scenePlugin.launch(HelpCameraSettingsSceneName);//700
}
} }
public gameSceneIsCreated(scene: GameScene) { public gameSceneIsCreated(scene: GameScene) {

View File

@ -41,7 +41,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, ConnexionMessageEvent, ConnexionMessageEventTypes} from "../../Connexion/ConnectionManager"; import {connectionManager} 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";
@ -65,6 +65,7 @@ import CanvasTexture = Phaser.Textures.CanvasTexture;
import GameObject = Phaser.GameObjects.GameObject; import GameObject = Phaser.GameObjects.GameObject;
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {Subscription} from "rxjs"; import {Subscription} from "rxjs";
import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface|null, initPosition: PointInterface|null,
@ -306,7 +307,7 @@ export class GameScene extends ResizableScene implements CenterListener {
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)) this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError())
const playerName = gameManager.getPlayerName(); const playerName = gameManager.getPlayerName();
if (!playerName) { if (!playerName) {
@ -1230,7 +1231,7 @@ export class GameScene extends ResizableScene implements CenterListener {
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi'); mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
} }
//todo: into onConnexionMessage //todo: put this into an 'orchestrator' scene (EntryScene?)
private bannedUser(){ private bannedUser(){
this.cleanupClosingScene(); this.cleanupClosingScene();
this.userInputManager.clearAllKeys(); this.userInputManager.clearAllKeys();
@ -1241,16 +1242,15 @@ export class GameScene extends ResizableScene implements CenterListener {
}); });
} }
private onConnexionMessage(event: ConnexionMessageEvent) { //todo: put this into an 'orchestrator' scene (EntryScene?)
if (event.type === ConnexionMessageEventTypes.worldFull) { private showWorldFullError(): void {
this.cleanupClosingScene(); this.cleanupClosingScene();
this.scene.stop(ReconnectingSceneName); this.scene.stop(ReconnectingSceneName);
this.userInputManager.clearAllKeys(); this.userInputManager.clearAllKeys();
this.scene.start(ErrorSceneName, { this.scene.start(ErrorSceneName, {
title: 'Connection rejected', title: 'Connection rejected',
subTitle: 'The world you are trying to join is full. Try again later.', 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' message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
}); });
}
} }
} }

View File

@ -61,26 +61,22 @@ export class EnableCameraScene extends Phaser.Scene {
this.microphoneNameField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height - 40, ''); this.microphoneNameField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height - 40, '');
this.arrowRight = new Image(this, 0, 0, LoginTextures.arrowRight); this.arrowRight = new Image(this, 0, 0, LoginTextures.arrowRight);
this.arrowRight.setOrigin(0.5, 0.5);
this.arrowRight.setVisible(false); this.arrowRight.setVisible(false);
this.arrowRight.setInteractive().on('pointerdown', this.nextCam.bind(this)); this.arrowRight.setInteractive().on('pointerdown', this.nextCam.bind(this));
this.add.existing(this.arrowRight); this.add.existing(this.arrowRight);
this.arrowLeft = new Image(this, 0, 0, LoginTextures.arrowRight); this.arrowLeft = new Image(this, 0, 0, LoginTextures.arrowRight);
this.arrowLeft.setOrigin(0.5, 0.5);
this.arrowLeft.setVisible(false); this.arrowLeft.setVisible(false);
this.arrowLeft.flipX = true; this.arrowLeft.flipX = true;
this.arrowLeft.setInteractive().on('pointerdown', this.previousCam.bind(this)); this.arrowLeft.setInteractive().on('pointerdown', this.previousCam.bind(this));
this.add.existing(this.arrowLeft); this.add.existing(this.arrowLeft);
this.arrowUp = new Image(this, 0, 0, LoginTextures.arrowUp); this.arrowUp = new Image(this, 0, 0, LoginTextures.arrowUp);
this.arrowUp.setOrigin(0.5, 0.5);
this.arrowUp.setVisible(false); this.arrowUp.setVisible(false);
this.arrowUp.setInteractive().on('pointerdown', this.previousMic.bind(this)); this.arrowUp.setInteractive().on('pointerdown', this.previousMic.bind(this));
this.add.existing(this.arrowUp); this.add.existing(this.arrowUp);
this.arrowDown = new Image(this, 0, 0, LoginTextures.arrowUp); this.arrowDown = new Image(this, 0, 0, LoginTextures.arrowUp);
this.arrowDown.setOrigin(0.5, 0.5);
this.arrowDown.setVisible(false); this.arrowDown.setVisible(false);
this.arrowDown.flipY = true; this.arrowDown.flipY = true;
this.arrowDown.setInteractive().on('pointerdown', this.nextMic.bind(this)); this.arrowDown.setInteractive().on('pointerdown', this.nextMic.bind(this));
@ -164,8 +160,6 @@ export class EnableCameraScene extends Phaser.Scene {
private updateWebCamName(): void { private updateWebCamName(): void {
if (this.camerasList.length > 1) { if (this.camerasList.length > 1) {
const div = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('myCamVideoSetup');
let label = this.camerasList[this.cameraSelected].label; let label = this.camerasList[this.cameraSelected].label;
// remove text in parenthesis // remove text in parenthesis
label = label.replace(/\([^()]*\)/g, '').trim(); label = label.replace(/\([^()]*\)/g, '').trim();
@ -173,17 +167,8 @@ export class EnableCameraScene extends Phaser.Scene {
label = label.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); label = label.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
this.cameraNameField.text = label; this.cameraNameField.text = label;
if (this.cameraSelected < this.camerasList.length - 1) { this.arrowRight.setVisible(this.cameraSelected < this.camerasList.length - 1);
this.arrowRight.setVisible(true); this.arrowLeft.setVisible(this.cameraSelected > 0);
} else {
this.arrowRight.setVisible(false);
}
if (this.cameraSelected > 0) {
this.arrowLeft.setVisible(true);
} else {
this.arrowLeft.setVisible(false);
}
} }
if (this.microphonesList.length > 1) { if (this.microphonesList.length > 1) {
let label = this.microphonesList[this.microphoneSelected].label; let label = this.microphonesList[this.microphoneSelected].label;
@ -194,17 +179,8 @@ export class EnableCameraScene extends Phaser.Scene {
this.microphoneNameField.text = label; this.microphoneNameField.text = label;
if (this.microphoneSelected < this.microphonesList.length - 1) { this.arrowDown.setVisible(this.microphoneSelected < this.microphonesList.length - 1);
this.arrowDown.setVisible(true); this.arrowUp.setVisible(this.microphoneSelected > 0);
} else {
this.arrowDown.setVisible(false);
}
if (this.microphoneSelected > 0) {
this.arrowUp.setVisible(true);
} else {
this.arrowUp.setVisible(false);
}
} }
this.reposition(); this.reposition();

View File

@ -1,5 +1,6 @@
import {mediaManager} from "../../WebRtc/MediaManager"; import {mediaManager} from "../../WebRtc/MediaManager";
import {HtmlUtils} from "../../WebRtc/HtmlUtils"; import {HtmlUtils} from "../../WebRtc/HtmlUtils";
import {localUserStore} from "../../Connexion/LocalUserStore";
export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene'; export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene';
const helpCameraSettings = 'helpCameraSettings'; const helpCameraSettings = 'helpCameraSettings';
@ -19,6 +20,7 @@ export class HelpCameraSettingsScene extends Phaser.Scene {
} }
create(){ create(){
localUserStore.setHelpCameraSettingsShown();
this.createHelpCameraSettings(); this.createHelpCameraSettings();
} }

View File

@ -6,6 +6,8 @@ import {mediaManager} from "../../WebRtc/MediaManager";
import {gameReportKey, gameReportRessource, ReportMenu} from "./ReportMenu"; import {gameReportKey, gameReportRessource, ReportMenu} from "./ReportMenu";
import {connectionManager} from "../../Connexion/ConnectionManager"; import {connectionManager} from "../../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../../Url/UrlManager"; import {GameConnexionTypes} from "../../Url/UrlManager";
import {WarningContainer, warningContainerHtml, warningContainerKey} from "../Components/WarningContainer";
import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream";
export const MenuSceneName = 'MenuScene'; export const MenuSceneName = 'MenuScene';
const gameMenuKey = 'gameMenu'; const gameMenuKey = 'gameMenu';
@ -30,6 +32,8 @@ export class MenuScene extends Phaser.Scene {
private gameQualityValue: number; private gameQualityValue: number;
private videoQualityValue: number; private videoQualityValue: number;
private menuButton!: Phaser.GameObjects.DOMElement; private menuButton!: Phaser.GameObjects.DOMElement;
private warningContainer: WarningContainer | null = null;
private warningContainerTimeout: NodeJS.Timeout | null = null;
constructor() { constructor() {
super({key: MenuSceneName}); super({key: MenuSceneName});
@ -44,6 +48,7 @@ export class MenuScene extends Phaser.Scene {
this.load.html(gameSettingsMenuKey, 'resources/html/gameQualityMenu.html'); this.load.html(gameSettingsMenuKey, 'resources/html/gameQualityMenu.html');
this.load.html(gameShare, 'resources/html/gameShare.html'); this.load.html(gameShare, 'resources/html/gameShare.html');
this.load.html(gameReportKey, gameReportRessource); this.load.html(gameReportKey, gameReportRessource);
this.load.html(warningContainerKey, warningContainerHtml);
} }
create() { create() {
@ -85,6 +90,8 @@ export class MenuScene extends Phaser.Scene {
this.menuElement.addListener('click'); this.menuElement.addListener('click');
this.menuElement.on('click', this.onMenuClick.bind(this)); this.menuElement.on('click', this.onMenuClick.bind(this));
worldFullWarningStream.stream.subscribe(() => this.showWorldCapacityWarning());
} }
//todo put this method in a parent menuElement class //todo put this method in a parent menuElement class
@ -122,6 +129,21 @@ export class MenuScene extends Phaser.Scene {
}); });
} }
private showWorldCapacityWarning() {
if (!this.warningContainer) {
this.warningContainer = new WarningContainer(this);
}
if (this.warningContainerTimeout) {
clearTimeout(this.warningContainerTimeout);
}
this.warningContainerTimeout = setTimeout(() => {
this.warningContainer?.destroy();
this.warningContainer = null
this.warningContainerTimeout = null
}, 2000);
}
private closeSideMenu(): void { private closeSideMenu(): void {
if (!this.sideMenuOpened) return; if (!this.sideMenuOpened) return;
this.sideMenuOpened = false; this.sideMenuOpened = false;

View File

@ -53,7 +53,7 @@ class CoWebsiteManager {
} }
get isFullScreen(): boolean { get isFullScreen(): boolean {
return this.verticalMode ? this.height === this.cowebsiteDiv.clientHeight : this.width === this.cowebsiteDiv.clientWidth return this.verticalMode ? this.height === window.innerHeight : this.width === window.innerWidth;
} }
constructor() { constructor() {
@ -199,6 +199,7 @@ class CoWebsiteManager {
private fullscreen(): void { private fullscreen(): void {
if (this.isFullScreen) { if (this.isFullScreen) {
this.resetStyle(); this.resetStyle();
this.fire();
//we don't trigger a resize of the phaser game since it won't be visible anyway. //we don't trigger a resize of the phaser game since it won't be visible anyway.
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline'; HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none'; HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';

View File

@ -197,6 +197,15 @@ message SendUserMessage{
string message = 2; string message = 2;
} }
message WorldFullWarningMessage{
}
message WorldFullWarningToRoomMessage{
string roomId = 1;
}
message WorldFullMessage{
}
message BanUserMessage{ message BanUserMessage{
string type = 1; string type = 1;
string message = 2; string message = 2;
@ -218,6 +227,8 @@ message ServerToClientMessage {
SendUserMessage sendUserMessage = 12; SendUserMessage sendUserMessage = 12;
BanUserMessage banUserMessage = 13; BanUserMessage banUserMessage = 13;
AdminRoomMessage adminRoomMessage = 14; AdminRoomMessage adminRoomMessage = 14;
WorldFullWarningMessage worldFullWarningMessage = 15;
WorldFullMessage worldFullMessage = 16;
} }
} }
@ -383,4 +394,5 @@ service RoomManager {
rpc sendGlobalAdminMessage(AdminGlobalMessage) returns (EmptyMessage); rpc sendGlobalAdminMessage(AdminGlobalMessage) returns (EmptyMessage);
rpc ban(BanMessage) returns (EmptyMessage); rpc ban(BanMessage) returns (EmptyMessage);
rpc sendAdminMessageToRoom(AdminRoomMessage) returns (EmptyMessage); rpc sendAdminMessageToRoom(AdminRoomMessage) returns (EmptyMessage);
rpc sendWorldFullWarningToRoom(WorldFullWarningToRoomMessage) returns (EmptyMessage);
} }

View File

@ -2,7 +2,7 @@ import {BaseController} from "./BaseController";
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js"; import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable"; import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
import {apiClientRepository} from "../Services/ApiClientRepository"; import {apiClientRepository} from "../Services/ApiClientRepository";
import {AdminRoomMessage} from "../Messages/generated/messages_pb"; import {AdminRoomMessage, WorldFullWarningToRoomMessage} from "../Messages/generated/messages_pb";
export class AdminController extends BaseController{ export class AdminController extends BaseController{
@ -40,22 +40,36 @@ export class AdminController extends BaseController{
if (typeof body.text !== 'string') { if (typeof body.text !== 'string') {
throw 'Incorrect text parameter' throw 'Incorrect text parameter'
} }
if (body.type !== 'capacity' && body.type !== 'message') {
throw 'Incorrect type parameter'
}
if (!body.targets || typeof body.targets !== 'object') { if (!body.targets || typeof body.targets !== 'object') {
throw 'Incorrect targets parameter' throw 'Incorrect targets parameter'
} }
const text: string = body.text; const text: string = body.text;
const type: string = body.type;
const targets: string[] = body.targets; const targets: string[] = body.targets;
await Promise.all(targets.map((roomId) => { await Promise.all(targets.map((roomId) => {
return apiClientRepository.getClient(roomId).then((roomClient) =>{ return apiClientRepository.getClient(roomId).then((roomClient) =>{
return new Promise((res, rej) => { return new Promise((res, rej) => {
const roomMessage = new AdminRoomMessage(); if (type === 'message') {
roomMessage.setMessage(text); const roomMessage = new AdminRoomMessage();
roomMessage.setRoomid(roomId); roomMessage.setMessage(text);
roomMessage.setRoomid(roomId);
roomClient.sendAdminMessageToRoom(roomMessage, (err) => {
err ? rej(err) : res();
});
} else if (type === 'capacity') {
const roomMessage = new WorldFullWarningToRoomMessage();
roomMessage.setRoomid(roomId);
roomClient.sendWorldFullWarningToRoom(roomMessage, (err) => {
err ? rej(err) : res();
});
}
roomClient.sendAdminMessageToRoom(roomMessage, (err) => {
err ? rej(err) : res();
});
}); });
}); });
})); }));

View File

@ -258,12 +258,12 @@ export class IoSocketController {
/* Handlers */ /* Handlers */
open: (ws) => { open: (ws) => {
if(ws.rejected === true) { if(ws.rejected === true) {
emitError(ws, 'World is full'); socketManager.emitWorldFullMessage(ws);
ws.close(); 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);
socketManager.handleJoinRoom(client); socketManager.handleJoinRoom(client);
//get data information and show messages //get data information and show messages

View File

@ -19,15 +19,15 @@ import {
JoinRoomMessage, JoinRoomMessage,
CharacterLayerMessage, CharacterLayerMessage,
PusherToBackMessage, PusherToBackMessage,
WorldFullMessage,
AdminPusherToBackMessage, AdminPusherToBackMessage,
ServerToAdminClientMessage, ServerToAdminClientMessage,
SendUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage, AdminMessage, BanMessage
BanUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage, AdminMessage, BanMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils"; import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable"; import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
import {adminApi, CharacterTexture} from "./AdminApi"; import {adminApi, CharacterTexture} from "./AdminApi";
import {emitError, emitInBatch} from "./IoSocketHelpers"; import {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";
@ -36,6 +36,7 @@ import {apiClientRepository} from "./ApiClientRepository";
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";
import {WebSocket} from "uWebSockets.js";
const debug = Debug('socket'); const debug = Debug('socket');
@ -52,6 +53,7 @@ export interface AdminSocketData {
} }
export class SocketManager implements ZoneEventListener { export class SocketManager implements ZoneEventListener {
private Worlds: Map<string, PusherRoom> = new Map<string, PusherRoom>(); private Worlds: Map<string, PusherRoom> = new Map<string, PusherRoom>();
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>(); private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
@ -533,6 +535,15 @@ export class SocketManager implements ZoneEventListener {
emitInBatch(listener, subMessage); emitInBatch(listener, subMessage);
} }
public emitWorldFullMessage(client: WebSocket) {
const errorMessage = new WorldFullMessage();
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setWorldfullmessage(errorMessage);
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
} }
export const socketManager = new SocketManager(); export const socketManager = new SocketManager();