2021-06-24 10:09:10 +02:00
import { PusherRoom } from "../Model/PusherRoom" ;
import { CharacterLayer , ExSocketInterface } from "../Model/Websocket/ExSocketInterface" ;
2020-11-13 18:00:22 +01:00
import {
2021-07-20 15:16:51 +02:00
AdminMessage ,
AdminPusherToBackMessage ,
AdminRoomMessage ,
BanMessage ,
CharacterLayerMessage ,
EmoteEventMessage ,
EmotePromptMessage ,
2020-11-13 18:00:22 +01:00
GroupDeleteMessage ,
ItemEventMessage ,
2021-07-20 15:16:51 +02:00
JoinRoomMessage ,
2020-11-13 18:00:22 +01:00
PlayGlobalMessage ,
2021-07-20 15:16:51 +02:00
PusherToBackMessage ,
QueryJitsiJwtMessage ,
RefreshRoomMessage ,
ReportPlayerMessage ,
2020-11-13 18:00:22 +01:00
RoomJoinedMessage ,
2021-07-20 15:16:51 +02:00
SendJitsiJwtMessage ,
ServerToAdminClientMessage ,
2020-11-13 18:00:22 +01:00
ServerToClientMessage ,
SetPlayerDetailsMessage ,
SilentMessage ,
SubMessage ,
2021-07-20 15:16:51 +02:00
UserJoinedRoomMessage ,
2020-12-10 17:46:15 +01:00
UserLeftMessage ,
2021-07-20 15:16:51 +02:00
UserLeftRoomMessage ,
2020-11-13 18:00:22 +01:00
UserMovesMessage ,
2020-12-10 17:46:15 +01:00
ViewportMessage ,
2020-11-13 18:00:22 +01:00
WebRtcSignalToServerMessage ,
2021-04-29 23:47:30 +02:00
WorldConnexionMessage ,
2021-07-27 16:37:01 +02:00
TokenExpiredMessage ,
2021-07-19 15:57:50 +02:00
VariableMessage ,
ErrorMessage ,
2021-07-20 15:16:51 +02:00
WorldFullMessage ,
2020-11-13 18:00:22 +01:00
} from "../Messages/generated/messages_pb" ;
2021-06-24 10:09:10 +02:00
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils" ;
2021-07-20 15:16:51 +02:00
import { ADMIN_API_URL , JITSI_ISS , JITSI_URL , SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable" ;
2021-07-16 09:52:51 +02:00
import { adminApi } from "./AdminApi" ;
2021-06-24 10:09:10 +02:00
import { emitInBatch } from "./IoSocketHelpers" ;
2020-11-13 18:00:22 +01:00
import Jwt from "jsonwebtoken" ;
2021-06-24 10:09:10 +02:00
import { clientEventsEmitter } from "./ClientEventsEmitter" ;
import { gaugeManager } from "./GaugeManager" ;
import { apiClientRepository } from "./ApiClientRepository" ;
import { GroupDescriptor , UserDescriptor , ZoneEventListener } from "_Model/Zone" ;
2020-11-13 18:00:22 +01:00
import Debug from "debug" ;
2021-06-24 10:09:10 +02:00
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface" ;
import { WebSocket } from "uWebSockets.js" ;
2021-07-16 09:52:51 +02:00
import { isRoomRedirect } from "./AdminApi/RoomRedirect" ;
import { CharacterTexture } from "./AdminApi/CharacterTexture" ;
2020-11-13 18:00:22 +01:00
2021-06-24 10:09:10 +02:00
const debug = Debug ( "socket" ) ;
2020-11-13 18:00:22 +01:00
interface AdminSocketRoomsList {
[ index : string ] : number ;
}
interface AdminSocketUsersList {
[ index : string ] : boolean ;
}
export interface AdminSocketData {
2021-06-24 10:09:10 +02:00
rooms : AdminSocketRoomsList ;
users : AdminSocketUsersList ;
2020-11-13 18:00:22 +01:00
}
export class SocketManager implements ZoneEventListener {
2021-04-01 16:43:12 +02:00
private rooms : Map < string , PusherRoom > = new Map < string , PusherRoom > ( ) ;
2020-11-13 18:00:22 +01:00
constructor ( ) {
clientEventsEmitter . registerToClientJoin ( ( clientUUid : string , roomId : string ) = > {
gaugeManager . incNbClientPerRoomGauge ( roomId ) ;
} ) ;
clientEventsEmitter . registerToClientLeave ( ( clientUUid : string , roomId : string ) = > {
gaugeManager . decNbClientPerRoomGauge ( roomId ) ;
} ) ;
}
2020-12-10 17:46:15 +01:00
async handleAdminRoom ( client : ExAdminSocketInterface , roomId : string ) : Promise < void > {
const apiClient = await apiClientRepository . getClient ( roomId ) ;
const adminRoomStream = apiClient . adminRoom ( ) ;
client . adminConnection = adminRoomStream ;
2021-06-24 10:09:10 +02:00
adminRoomStream
. on ( "data" , ( message : ServerToAdminClientMessage ) = > {
if ( message . hasUserjoinedroom ( ) ) {
const userJoinedRoomMessage = message . getUserjoinedroom ( ) as UserJoinedRoomMessage ;
if ( ! client . disconnecting ) {
client . send (
JSON . stringify ( {
type : "MemberJoin" ,
data : {
uuid : userJoinedRoomMessage.getUuid ( ) ,
name : userJoinedRoomMessage.getName ( ) ,
ipAddress : userJoinedRoomMessage.getIpaddress ( ) ,
roomId : roomId ,
} ,
} )
) ;
}
} else if ( message . hasUserleftroom ( ) ) {
const userLeftRoomMessage = message . getUserleftroom ( ) as UserLeftRoomMessage ;
if ( ! client . disconnecting ) {
client . send (
JSON . stringify ( {
type : "MemberLeave" ,
data : {
uuid : userLeftRoomMessage.getUuid ( ) ,
} ,
} )
) ;
}
} else {
throw new Error ( "Unexpected admin message" ) ;
}
} )
. on ( "end" , ( ) = > {
console . warn ( "Admin connection lost to back server" ) ;
// Let's close the front connection if the back connection is closed. This way, we can retry connecting from the start.
2020-12-10 17:46:15 +01:00
if ( ! client . disconnecting ) {
2021-07-27 16:37:01 +02:00
this . closeWebsocketConnection ( client , 1011 , "Admin Connection lost to back server" ) ;
2020-12-10 17:46:15 +01:00
}
2021-06-24 10:09:10 +02:00
console . log ( "A user left" ) ;
} )
. on ( "error" , ( err : Error ) = > {
console . error ( "Error in connection to back server:" , err ) ;
2020-12-10 17:46:15 +01:00
if ( ! client . disconnecting ) {
2021-06-24 10:09:10 +02:00
this . closeWebsocketConnection ( client , 1011 , "Error while connecting to back server" ) ;
2020-12-10 17:46:15 +01:00
}
2021-06-24 10:09:10 +02:00
} ) ;
2020-12-10 17:46:15 +01:00
const message = new AdminPusherToBackMessage ( ) ;
message . setSubscribetoroom ( roomId ) ;
adminRoomStream . write ( message ) ;
}
2021-06-24 10:09:10 +02:00
leaveAdminRoom ( socket : ExAdminSocketInterface ) {
2020-12-10 17:46:15 +01:00
if ( socket . adminConnection ) {
socket . adminConnection . end ( ) ;
}
}
2020-11-13 18:00:22 +01:00
async handleJoinRoom ( client : ExSocketInterface ) : Promise < void > {
const viewport = client . viewport ;
try {
const joinRoomMessage = new JoinRoomMessage ( ) ;
2020-12-02 17:51:46 +01:00
joinRoomMessage . setUseruuid ( client . userUuid ) ;
2021-01-15 03:19:58 +01:00
joinRoomMessage . setIpaddress ( client . IPAddress ) ;
2020-11-13 18:00:22 +01:00
joinRoomMessage . setRoomid ( client . roomId ) ;
joinRoomMessage . setName ( client . name ) ;
joinRoomMessage . setPositionmessage ( ProtobufUtils . toPositionMessage ( client . position ) ) ;
2021-01-17 03:07:46 +01:00
joinRoomMessage . setTagList ( client . tags ) ;
2021-06-08 16:30:58 +02:00
if ( client . visitCardUrl ) {
joinRoomMessage . setVisitcardurl ( client . visitCardUrl ) ;
}
2021-04-02 21:21:11 +02:00
joinRoomMessage . setCompanion ( client . companion ) ;
2020-11-13 18:00:22 +01:00
for ( const characterLayer of client . characterLayers ) {
const characterLayerMessage = new CharacterLayerMessage ( ) ;
characterLayerMessage . setName ( characterLayer . name ) ;
if ( characterLayer . url !== undefined ) {
characterLayerMessage . setUrl ( characterLayer . url ) ;
}
joinRoomMessage . addCharacterlayer ( characterLayerMessage ) ;
}
2021-06-24 10:09:10 +02:00
console . log ( "Calling joinRoom" ) ;
2020-11-13 18:00:22 +01:00
const apiClient = await apiClientRepository . getClient ( client . roomId ) ;
const streamToPusher = apiClient . joinRoom ( ) ;
2021-02-09 23:21:11 +01:00
clientEventsEmitter . emitClientJoin ( client . userUuid , client . roomId ) ;
2020-11-13 18:00:22 +01:00
client . backConnection = streamToPusher ;
2021-06-24 10:09:10 +02:00
streamToPusher
. on ( "data" , ( message : ServerToClientMessage ) = > {
if ( message . hasRoomjoinedmessage ( ) ) {
client . userId = ( message . getRoomjoinedmessage ( ) as RoomJoinedMessage ) . getCurrentuserid ( ) ;
2020-12-02 17:51:46 +01:00
2021-06-24 10:09:10 +02:00
// If this is the first message sent, send back the viewport.
this . handleViewport ( client , viewport ) ;
}
2020-11-13 18:00:22 +01:00
2021-06-24 10:09:10 +02:00
if ( message . hasRefreshroommessage ( ) ) {
const refreshMessage : RefreshRoomMessage =
message . getRefreshroommessage ( ) as unknown as RefreshRoomMessage ;
this . refreshRoomData ( refreshMessage . getRoomid ( ) , refreshMessage . getVersionnumber ( ) ) ;
}
// Let's pass data over from the back to the client.
if ( ! client . disconnecting ) {
client . send ( message . serializeBinary ( ) . buffer , true ) ;
}
} )
. on ( "end" , ( ) = > {
console . warn ( "Connection lost to back server" ) ;
// Let's close the front connection if the back connection is closed. This way, we can retry connecting from the start.
if ( ! client . disconnecting ) {
this . closeWebsocketConnection ( client , 1011 , "Connection lost to back server" ) ;
}
console . log ( "A user left" ) ;
} )
. on ( "error" , ( err : Error ) = > {
console . error ( "Error in connection to back server:" , err ) ;
if ( ! client . disconnecting ) {
this . closeWebsocketConnection ( client , 1011 , "Error while connecting to back server" ) ;
}
} ) ;
2020-11-13 18:00:22 +01:00
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setJoinroommessage ( joinRoomMessage ) ;
streamToPusher . write ( pusherToBackMessage ) ;
2021-07-06 15:30:49 +02:00
const pusherRoom = await this . getOrCreateRoom ( client . roomId ) ;
pusherRoom . join ( client ) ;
2020-11-13 18:00:22 +01:00
} catch ( e ) {
console . error ( 'An error occurred on "join_room" event' ) ;
console . error ( e ) ;
}
}
2021-06-24 10:09:10 +02:00
private closeWebsocketConnection ( client : ExSocketInterface | ExAdminSocketInterface , code : number , reason : string ) {
2020-11-13 18:00:22 +01:00
client . disconnecting = true ;
//this.leaveRoom(client);
2020-12-03 16:39:44 +01:00
//client.close();
client . end ( code , reason ) ;
2020-11-13 18:00:22 +01:00
}
handleViewport ( client : ExSocketInterface , viewport : ViewportMessage.AsObject ) {
try {
client . viewport = viewport ;
2021-10-29 16:44:51 +02:00
const room = this . rooms . get ( client . roomId ) ;
if ( ! room ) {
2020-11-13 18:00:22 +01:00
console . error ( "In SET_VIEWPORT, could not find world with id '" , client . roomId , "'" ) ;
return ;
}
2021-10-29 16:44:51 +02:00
room . setViewport ( client , client . viewport ) ;
2020-11-13 18:00:22 +01:00
} catch ( e ) {
console . error ( 'An error occurred on "SET_VIEWPORT" event' ) ;
console . error ( e ) ;
}
}
handleUserMovesMessage ( client : ExSocketInterface , userMovesMessage : UserMovesMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setUsermovesmessage ( userMovesMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
const viewport = userMovesMessage . getViewport ( ) ;
if ( viewport === undefined ) {
2021-06-24 10:09:10 +02:00
throw new Error ( "Missing viewport in UserMovesMessage" ) ;
2020-11-13 18:00:22 +01:00
}
// Now, we need to listen to the correct viewport.
2021-06-24 10:09:10 +02:00
this . handleViewport ( client , viewport . toObject ( ) ) ;
2020-11-13 18:00:22 +01:00
}
2021-03-31 11:21:06 +02:00
onEmote ( emoteMessage : EmoteEventMessage , listener : ExSocketInterface ) : void {
const subMessage = new SubMessage ( ) ;
subMessage . setEmoteeventmessage ( emoteMessage ) ;
emitInBatch ( listener , subMessage ) ;
}
2021-07-19 10:16:43 +02:00
onError ( errorMessage : ErrorMessage , listener : ExSocketInterface ) : void {
const subMessage = new SubMessage ( ) ;
subMessage . setErrormessage ( errorMessage ) ;
emitInBatch ( listener , subMessage ) ;
}
2020-11-13 18:00:22 +01:00
// Useless now, will be useful again if we allow editing details in game
handleSetPlayerDetails ( client : ExSocketInterface , playerDetailsMessage : SetPlayerDetailsMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setSetplayerdetailsmessage ( playerDetailsMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
}
handleSilentMessage ( client : ExSocketInterface , silentMessage : SilentMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setSilentmessage ( silentMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
}
handleItemEvent ( client : ExSocketInterface , itemEventMessage : ItemEventMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setItemeventmessage ( itemEventMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
}
2021-07-06 15:30:49 +02:00
handleVariableEvent ( client : ExSocketInterface , variableMessage : VariableMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setVariablemessage ( variableMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
}
2020-11-13 18:00:22 +01:00
async handleReportMessage ( client : ExSocketInterface , reportPlayerMessage : ReportPlayerMessage ) {
try {
2021-06-24 10:09:10 +02:00
await adminApi . reportPlayer (
2021-07-07 11:24:51 +02:00
reportPlayerMessage . getReporteduseruuid ( ) ,
2021-06-24 10:09:10 +02:00
reportPlayerMessage . getReportcomment ( ) ,
client . userUuid ,
2021-08-06 18:28:18 +02:00
client . roomId
2021-06-24 10:09:10 +02:00
) ;
2020-11-13 18:00:22 +01:00
} catch ( e ) {
console . error ( 'An error occurred on "handleReportMessage"' ) ;
console . error ( e ) ;
}
}
emitVideo ( socket : ExSocketInterface , data : WebRtcSignalToServerMessage ) : void {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setWebrtcsignaltoservermessage ( data ) ;
socket . backConnection . write ( pusherToBackMessage ) ;
}
emitScreenSharing ( socket : ExSocketInterface , data : WebRtcSignalToServerMessage ) : void {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setWebrtcscreensharingsignaltoservermessage ( data ) ;
socket . backConnection . write ( pusherToBackMessage ) ;
}
2021-06-24 10:09:10 +02:00
leaveRoom ( socket : ExSocketInterface ) {
2020-11-13 18:00:22 +01:00
// leave previous room and world
try {
if ( socket . roomId ) {
try {
//user leaves room
2021-04-01 16:43:12 +02:00
const room : PusherRoom | undefined = this . rooms . get ( socket . roomId ) ;
2020-11-13 18:00:22 +01:00
if ( room ) {
2021-06-24 10:09:10 +02:00
debug ( "Leaving room %s." , socket . roomId ) ;
2020-11-13 18:00:22 +01:00
room . leave ( socket ) ;
if ( room . isEmpty ( ) ) {
2021-07-06 15:30:49 +02:00
room . close ( ) ;
2021-04-01 16:43:12 +02:00
this . rooms . delete ( socket . roomId ) ;
2021-06-24 10:09:10 +02:00
debug ( "Room %s is empty. Deleting." , socket . roomId ) ;
2020-11-13 18:00:22 +01:00
}
} else {
2021-06-24 10:09:10 +02:00
console . error ( "Could not find the GameRoom the user is leaving!" ) ;
2020-11-13 18:00:22 +01:00
}
//user leave previous room
//Client.leave(Client.roomId);
} finally {
//delete Client.roomId;
clientEventsEmitter . emitClientLeave ( socket . userUuid , socket . roomId ) ;
2021-07-07 11:24:51 +02:00
console . log ( "A user left" ) ;
2020-11-13 18:00:22 +01:00
}
}
} finally {
if ( socket . backConnection ) {
socket . backConnection . end ( ) ;
}
}
}
2021-07-13 19:09:07 +02:00
async getOrCreateRoom ( roomUrl : string ) : Promise < PusherRoom > {
2020-11-13 18:00:22 +01:00
//check and create new world for a room
2021-07-13 19:09:07 +02:00
let room = this . rooms . get ( roomUrl ) ;
if ( room === undefined ) {
room = new PusherRoom ( roomUrl , this ) ;
if ( ADMIN_API_URL ) {
await this . updateRoomWithAdminData ( room ) ;
2020-11-13 18:00:22 +01:00
}
2021-07-16 11:37:44 +02:00
await room . init ( ) ;
2021-07-13 19:09:07 +02:00
this . rooms . set ( roomUrl , room ) ;
2020-11-13 18:00:22 +01:00
}
2021-07-13 19:09:07 +02:00
return room ;
2020-11-13 18:00:22 +01:00
}
2021-07-13 19:09:07 +02:00
public async updateRoomWithAdminData ( room : PusherRoom ) : Promise < void > {
const data = await adminApi . fetchMapDetails ( room . roomUrl ) ;
2021-07-16 09:52:51 +02:00
if ( isRoomRedirect ( data ) ) {
// TODO: if the updated room data is actually a redirect, we need to take everybody on the map
// and redirect everybody to the new location (so we need to close the connection for everybody)
} else {
room . tags = data . tags ;
room . policyType = Number ( data . policy_type ) ;
}
2021-04-01 16:43:12 +02:00
}
2020-11-13 18:00:22 +01:00
public getWorlds ( ) : Map < string , PusherRoom > {
2021-04-01 16:43:12 +02:00
return this . rooms ;
2020-11-13 18:00:22 +01:00
}
2021-06-24 10:09:10 +02:00
2020-11-13 18:00:22 +01:00
public handleQueryJitsiJwtMessage ( client : ExSocketInterface , queryJitsiJwtMessage : QueryJitsiJwtMessage ) {
2021-03-10 09:41:54 +01:00
try {
const room = queryJitsiJwtMessage . getJitsiroom ( ) ;
const tag = queryJitsiJwtMessage . getTag ( ) ; // FIXME: this is not secure. We should load the JSON for the current room and check rights associated to room instead.
2020-11-13 18:00:22 +01:00
2021-06-24 10:09:10 +02:00
if ( SECRET_JITSI_KEY === "" ) {
throw new Error (
"You must set the SECRET_JITSI_KEY key to the secret to generate JWT tokens for Jitsi."
) ;
2021-03-10 09:41:54 +01:00
}
2020-11-13 18:00:22 +01:00
2021-03-10 09:41:54 +01:00
// Let's see if the current client has
const isAdmin = client . tags . includes ( tag ) ;
2021-06-24 10:09:10 +02:00
const jwt = Jwt . sign (
{
aud : "jitsi" ,
iss : JITSI_ISS ,
sub : JITSI_URL ,
room : room ,
moderator : isAdmin ,
} ,
SECRET_JITSI_KEY ,
{
expiresIn : "1d" ,
algorithm : "HS256" ,
header : {
alg : "HS256" ,
typ : "JWT" ,
} ,
}
) ;
2020-11-13 18:00:22 +01:00
2021-03-10 09:41:54 +01:00
const sendJitsiJwtMessage = new SendJitsiJwtMessage ( ) ;
sendJitsiJwtMessage . setJitsiroom ( room ) ;
sendJitsiJwtMessage . setJwt ( jwt ) ;
2020-11-13 18:00:22 +01:00
2021-03-10 09:41:54 +01:00
const serverToClientMessage = new ServerToClientMessage ( ) ;
serverToClientMessage . setSendjitsijwtmessage ( sendJitsiJwtMessage ) ;
2020-11-13 18:00:22 +01:00
2021-03-10 09:41:54 +01:00
client . send ( serverToClientMessage . serializeBinary ( ) . buffer , true ) ;
} catch ( e ) {
2021-07-27 14:29:09 +02:00
console . error ( "An error occurred while generating the Jitsi JWT token: " , e ) ;
2021-03-10 09:41:54 +01:00
}
2020-11-13 18:00:22 +01:00
}
2021-03-11 01:25:36 +01:00
public async emitSendUserMessage ( userUuid : string , message : string , type : string , roomId : string ) {
2021-03-11 12:17:37 +01:00
/ * c o n s t c l i e n t = t h i s . s e a r c h C l i e n t B y U u i d ( u s e r U u i d ) ;
2021-03-11 01:25:36 +01:00
if ( client ) {
const adminMessage = new SendUserMessage ( ) ;
adminMessage . setMessage ( message ) ;
adminMessage . setType ( type ) ;
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setSendusermessage ( adminMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
return ;
2021-03-11 12:17:37 +01:00
} * /
2020-12-11 12:23:50 +01:00
2021-03-11 01:25:36 +01:00
const backConnection = await apiClientRepository . getClient ( roomId ) ;
const backAdminMessage = new AdminMessage ( ) ;
backAdminMessage . setMessage ( message ) ;
backAdminMessage . setRoomid ( roomId ) ;
backAdminMessage . setRecipientuuid ( userUuid ) ;
backAdminMessage . setType ( type ) ;
backConnection . sendAdminMessage ( backAdminMessage , ( error ) = > {
2020-12-11 12:23:50 +01:00
if ( error !== null ) {
2021-06-24 10:09:10 +02:00
console . error ( "Error while sending admin message" , error ) ;
2020-12-11 12:23:50 +01:00
}
2021-03-11 01:25:36 +01:00
} ) ;
2020-12-11 12:23:50 +01:00
}
2021-03-11 01:25:36 +01:00
public async emitBan ( userUuid : string , message : string , type : string , roomId : string ) {
2021-03-11 12:17:37 +01:00
/ * c o n s t c l i e n t = t h i s . s e a r c h C l i e n t B y U u i d ( u s e r U u i d ) ;
2021-03-11 01:25:36 +01:00
if ( client ) {
const banUserMessage = new BanUserMessage ( ) ;
banUserMessage . setMessage ( message ) ;
banUserMessage . setType ( type ) ;
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setBanusermessage ( banUserMessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
return ;
2021-03-11 12:17:37 +01:00
} * /
2020-12-11 12:23:50 +01:00
2021-03-11 01:25:36 +01:00
const backConnection = await apiClientRepository . getClient ( roomId ) ;
const banMessage = new BanMessage ( ) ;
banMessage . setMessage ( message ) ;
banMessage . setRoomid ( roomId ) ;
banMessage . setRecipientuuid ( userUuid ) ;
banMessage . setType ( type ) ;
backConnection . ban ( banMessage , ( error ) = > {
2020-12-11 12:23:50 +01:00
if ( error !== null ) {
2021-06-24 10:09:10 +02:00
console . error ( "Error while sending admin message" , error ) ;
2020-12-11 12:23:50 +01:00
}
2021-03-11 01:25:36 +01:00
} ) ;
2020-11-13 18:00:22 +01:00
}
/ * *
* Merges the characterLayers received from the front ( as an array of string ) with the custom textures from the back .
* /
2021-06-24 10:09:10 +02:00
static mergeCharacterLayersAndCustomTextures (
characterLayers : string [ ] ,
memberTextures : CharacterTexture [ ]
) : CharacterLayer [ ] {
2020-11-13 18:00:22 +01:00
const characterLayerObjs : CharacterLayer [ ] = [ ] ;
for ( const characterLayer of characterLayers ) {
2021-06-24 10:09:10 +02:00
if ( characterLayer . startsWith ( "customCharacterTexture" ) ) {
2020-11-13 18:00:22 +01:00
const customCharacterLayerId : number = + characterLayer . substr ( 22 ) ;
for ( const memberTexture of memberTextures ) {
if ( memberTexture . id == customCharacterLayerId ) {
characterLayerObjs . push ( {
name : characterLayer ,
2021-06-24 10:09:10 +02:00
url : memberTexture.url ,
} ) ;
2020-11-13 18:00:22 +01:00
break ;
}
}
} else {
characterLayerObjs . push ( {
name : characterLayer ,
2021-06-24 10:09:10 +02:00
url : undefined ,
} ) ;
2020-11-13 18:00:22 +01:00
}
}
return characterLayerObjs ;
}
public onUserEnters ( user : UserDescriptor , listener : ExSocketInterface ) : void {
const subMessage = new SubMessage ( ) ;
subMessage . setUserjoinedmessage ( user . toUserJoinedMessage ( ) ) ;
emitInBatch ( listener , subMessage ) ;
}
public onUserMoves ( user : UserDescriptor , listener : ExSocketInterface ) : void {
const subMessage = new SubMessage ( ) ;
subMessage . setUsermovedmessage ( user . toUserMovedMessage ( ) ) ;
emitInBatch ( listener , subMessage ) ;
}
public onUserLeaves ( userId : number , listener : ExSocketInterface ) : void {
const userLeftMessage = new UserLeftMessage ( ) ;
userLeftMessage . setUserid ( userId ) ;
const subMessage = new SubMessage ( ) ;
subMessage . setUserleftmessage ( userLeftMessage ) ;
emitInBatch ( listener , subMessage ) ;
}
public onGroupEnters ( group : GroupDescriptor , listener : ExSocketInterface ) : void {
const subMessage = new SubMessage ( ) ;
subMessage . setGroupupdatemessage ( group . toGroupUpdateMessage ( ) ) ;
emitInBatch ( listener , subMessage ) ;
}
public onGroupMoves ( group : GroupDescriptor , listener : ExSocketInterface ) : void {
this . onGroupEnters ( group , listener ) ;
}
public onGroupLeaves ( groupId : number , listener : ExSocketInterface ) : void {
const groupDeleteMessage = new GroupDeleteMessage ( ) ;
groupDeleteMessage . setGroupid ( groupId ) ;
const subMessage = new SubMessage ( ) ;
subMessage . setGroupdeletemessage ( groupDeleteMessage ) ;
emitInBatch ( listener , subMessage ) ;
}
2021-06-24 10:09:10 +02:00
2021-03-11 16:14:34 +01:00
public emitWorldFullMessage ( client : WebSocket ) {
const errorMessage = new WorldFullMessage ( ) ;
const serverToClientMessage = new ServerToClientMessage ( ) ;
serverToClientMessage . setWorldfullmessage ( errorMessage ) ;
2021-07-27 16:37:01 +02:00
if ( ! client . disconnecting ) {
client . send ( serverToClientMessage . serializeBinary ( ) . buffer , true ) ;
}
}
2021-08-02 23:07:39 +02:00
2021-07-27 16:37:01 +02:00
public emitTokenExpiredMessage ( client : WebSocket ) {
const errorMessage = new TokenExpiredMessage ( ) ;
const serverToClientMessage = new ServerToClientMessage ( ) ;
serverToClientMessage . setTokenexpiredmessage ( errorMessage ) ;
if ( ! client . disconnecting ) {
client . send ( serverToClientMessage . serializeBinary ( ) . buffer , true ) ;
}
2021-03-11 16:14:34 +01:00
}
2021-04-01 16:43:12 +02:00
2021-04-29 23:47:30 +02:00
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 ) ;
}
2021-04-01 16:43:12 +02:00
private refreshRoomData ( roomId : string , versionNumber : number ) : void {
const room = this . rooms . get ( roomId ) ;
2021-06-24 10:09:10 +02:00
//this function is run for every users connected to the room, so we need to make sure the room wasn't already refreshed.
2021-04-01 16:43:12 +02:00
if ( ! room || ! room . needsUpdate ( versionNumber ) ) return ;
2021-06-24 10:09:10 +02:00
2021-04-01 16:43:12 +02:00
this . updateRoomWithAdminData ( room ) ;
}
2021-03-31 11:21:06 +02:00
handleEmotePromptMessage ( client : ExSocketInterface , emoteEventmessage : EmotePromptMessage ) {
const pusherToBackMessage = new PusherToBackMessage ( ) ;
pusherToBackMessage . setEmotepromptmessage ( emoteEventmessage ) ;
client . backConnection . write ( pusherToBackMessage ) ;
}
2021-07-20 15:16:51 +02:00
2021-07-22 16:14:27 +02:00
public async emitPlayGlobalMessage (
2021-07-20 15:16:51 +02:00
client : ExSocketInterface ,
2021-07-22 16:14:27 +02:00
playGlobalMessageEvent : PlayGlobalMessage
2021-07-20 15:16:51 +02:00
) : Promise < void > {
if ( ! client . tags . includes ( "admin" ) ) {
throw "Client is not an admin!" ;
}
const clientRoomUrl = client . roomId ;
let tabUrlRooms : string [ ] ;
2021-07-22 16:14:27 +02:00
if ( playGlobalMessageEvent . getBroadcasttoworld ( ) ) {
2021-07-20 15:16:51 +02:00
tabUrlRooms = await adminApi . getUrlRoomsFromSameWorld ( clientRoomUrl ) ;
} else {
tabUrlRooms = [ clientRoomUrl ] ;
}
2021-07-22 17:17:25 +02:00
const roomMessage = new AdminRoomMessage ( ) ;
2021-07-22 16:14:27 +02:00
roomMessage . setMessage ( playGlobalMessageEvent . getContent ( ) ) ;
roomMessage . setType ( playGlobalMessageEvent . getType ( ) ) ;
2021-07-20 15:16:51 +02:00
2021-07-22 17:17:25 +02:00
for ( const roomUrl of tabUrlRooms ) {
const apiRoom = await apiClientRepository . getClient ( roomUrl ) ;
2021-07-20 15:16:51 +02:00
roomMessage . setRoomid ( roomUrl ) ;
apiRoom . sendAdminMessageToRoom ( roomMessage , ( response ) = > {
return ;
} ) ;
}
}
2020-11-13 18:00:22 +01:00
}
export const socketManager = new SocketManager ( ) ;