partey_workadventure/front/src/Connexion/RoomConnection.ts

801 lines
32 KiB
TypeScript
Raw Normal View History

import { PUSHER_URL, UPLOADER_URL } from "../Enum/EnvironmentVariable";
import Axios from "axios";
import {
2020-09-29 16:01:22 +02:00
BatchMessage,
ClientToServerMessage,
GroupDeleteMessage,
GroupUpdateMessage,
ItemEventMessage,
PlayGlobalMessage,
2020-09-29 16:01:22 +02:00
PositionMessage,
RoomJoinedMessage,
ServerToClientMessage,
SetPlayerDetailsMessage,
SilentMessage,
StopGlobalMessage,
2020-09-29 16:01:22 +02:00
UserJoinedMessage,
UserLeftMessage,
UserMovedMessage,
UserMovesMessage,
2020-09-29 16:01:22 +02:00
ViewportMessage,
WebRtcDisconnectMessage,
WebRtcSignalToClientMessage,
WebRtcSignalToServerMessage,
2020-10-12 11:22:41 +02:00
WebRtcStartMessage,
ReportPlayerMessage,
2020-10-20 16:39:23 +02:00
TeleportMessageMessage,
QueryJitsiJwtMessage,
SendJitsiJwtMessage,
CharacterLayerMessage,
PingMessage,
EmoteEventMessage,
EmotePromptMessage,
FollowRequestMessage,
FollowConfirmationMessage,
FollowAbortMessage,
SendUserMessage,
BanUserMessage,
VariableMessage,
ErrorMessage,
} from "../Messages/generated/messages_pb";
import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer";
import Direction = PositionMessage.Direction;
import { ProtobufClientUtils } from "../Network/ProtobufClientUtils";
2020-09-25 18:29:22 +02:00
import {
EventMessage,
GroupCreatedUpdatedMessageInterface,
ItemEventMessageInterface,
MessageUserJoined,
OnConnectInterface,
PlayGlobalMessageInterface,
PositionInterface,
2020-09-25 18:29:22 +02:00
RoomJoinedMessageInterface,
ViewportInterface,
WebRtcDisconnectMessageInterface,
2020-09-25 18:29:22 +02:00
WebRtcSignalReceivedMessageInterface,
} from "./ConnexionModels";
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
import { adminMessagesService } from "./AdminMessagesService";
import { worldFullMessageStream } from "./WorldFullMessageStream";
import { connectionManager } from "./ConnectionManager";
import { emoteEventStream } from "./EmoteEventStream";
import { get } from "svelte/store";
import { warningContainerStore } from "../Stores/MenuStore";
import {
followStateStore,
followRoleStore,
followUsersStore,
followRoles,
followStates,
} from "../Stores/InteractStore";
2020-09-25 18:29:22 +02:00
const manualPingDelay = 20000;
2020-09-25 18:29:22 +02:00
export class RoomConnection implements RoomConnection {
2020-09-28 18:52:54 +02:00
private readonly socket: WebSocket;
private userId: number | null = null;
2020-09-29 16:01:22 +02:00
private listeners: Map<string, Function[]> = new Map<string, Function[]>();
private static websocketFactory: null | ((url: string) => any) = null; // eslint-disable-line @typescript-eslint/no-explicit-any
2020-10-01 17:16:49 +02:00
private closed: boolean = false;
private tags: string[] = [];
private _userRoomToken: string | undefined;
2020-04-07 20:41:35 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public static setWebsocketFactory(websocketFactory: (url: string) => any): void {
RoomConnection.websocketFactory = websocketFactory;
2020-09-28 18:52:54 +02:00
}
/**
*
* @param token A JWT token containing the email of the user
* @param roomUrl The URL of the room in the form "https://example.com/_/[instance]/[map_url]" or "https://example.com/@/[org]/[event]/[map]"
Active authentication Oauth (#1377) * Active authentication Oauth - Google authentication - GitHub authentication - Linkedin authentication Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Finish connexion et get user info connexion Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Fix lint error Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Change the expires token for 30 days Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update connexion stratgey - Set last room when it will be created and not when connexion is openned - Add '/login' end point permit to logout and open iframe to log user - Add logout feature permit to logout in front Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Implement logout and revoke token with hydra Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Fix pull develop conflict Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Profile url (#1399) * Create function that permit to get profile URL Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Continue profil user Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Add menu and logout button Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update last room use Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Profile callback permit to get url profile setting from admin Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Finish profile show Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Delete profileUrl will be not use today Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Correct lint Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update size of iframe Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Delete console log Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update feedback ARP Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>
2021-09-05 18:17:49 +02:00
* @param name
* @param characterLayers
* @param position
* @param viewport
* @param companion
*/
public constructor(
token: string | null,
roomUrl: string,
name: string,
characterLayers: string[],
position: PositionInterface,
viewport: ViewportInterface,
companion: string | null
) {
let url = new URL(PUSHER_URL, window.location.toString()).toString();
url = url.replace("http://", "ws://").replace("https://", "wss://");
if (!url.endsWith("/")) {
url += "/";
}
url += "room";
2021-07-15 17:12:54 +02:00
url += "?roomId=" + encodeURIComponent(roomUrl);
url += "&token=" + (token ? encodeURIComponent(token) : "");
url += "&name=" + encodeURIComponent(name);
2020-10-09 17:14:03 +02:00
for (const layer of characterLayers) {
url += "&characterLayers=" + encodeURIComponent(layer);
}
url += "&x=" + Math.floor(position.x);
url += "&y=" + Math.floor(position.y);
url += "&top=" + Math.floor(viewport.top);
url += "&bottom=" + Math.floor(viewport.bottom);
url += "&left=" + Math.floor(viewport.left);
url += "&right=" + Math.floor(viewport.right);
if (typeof companion === "string") {
url += "&companion=" + encodeURIComponent(companion);
2021-04-02 21:21:11 +02:00
}
if (RoomConnection.websocketFactory) {
this.socket = RoomConnection.websocketFactory(url);
2020-09-28 18:52:54 +02:00
} else {
this.socket = new WebSocket(url);
}
this.socket.binaryType = "arraybuffer";
2020-09-28 18:52:54 +02:00
let interval: ReturnType<typeof setInterval> | undefined = undefined;
2020-09-28 18:52:54 +02:00
this.socket.onopen = (ev) => {
//we manually ping every 20s to not be logged out by the server, even when the game is in background.
const pingMessage = new PingMessage();
interval = setInterval(() => this.socket.send(pingMessage.serializeBinary().buffer), manualPingDelay);
2020-09-28 18:52:54 +02:00
};
this.socket.addEventListener("close", (event) => {
if (interval) {
clearInterval(interval);
}
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
if (this.userId === null && !this.closed) {
this.dispatch(EventMessage.CONNECTING_ERROR, event);
}
});
2020-09-28 18:52:54 +02:00
this.socket.onmessage = (messageEvent) => {
const arrayBuffer: ArrayBuffer = messageEvent.data;
const message = ServerToClientMessage.deserializeBinary(new Uint8Array(arrayBuffer));
if (message.hasBatchmessage()) {
for (const subMessage of (message.getBatchmessage() as BatchMessage).getPayloadList()) {
let event: string | null = null;
2020-09-28 18:52:54 +02:00
let payload;
if (subMessage.hasUsermovedmessage()) {
event = EventMessage.USER_MOVED;
payload = subMessage.getUsermovedmessage();
} else if (subMessage.hasGroupupdatemessage()) {
event = EventMessage.GROUP_CREATE_UPDATE;
payload = subMessage.getGroupupdatemessage();
} else if (subMessage.hasGroupdeletemessage()) {
event = EventMessage.GROUP_DELETE;
payload = subMessage.getGroupdeletemessage();
} else if (subMessage.hasUserjoinedmessage()) {
event = EventMessage.JOIN_ROOM;
payload = subMessage.getUserjoinedmessage();
} else if (subMessage.hasUserleftmessage()) {
event = EventMessage.USER_LEFT;
payload = subMessage.getUserleftmessage();
} else if (subMessage.hasItemeventmessage()) {
event = EventMessage.ITEM_EVENT;
payload = subMessage.getItemeventmessage();
} else if (subMessage.hasEmoteeventmessage()) {
const emoteMessage = subMessage.getEmoteeventmessage() as EmoteEventMessage;
emoteEventStream.fire(emoteMessage.getActoruserid(), emoteMessage.getEmote());
} else if (subMessage.hasErrormessage()) {
const errorMessage = subMessage.getErrormessage() as ErrorMessage;
console.error("An error occurred server side: " + errorMessage.getMessage());
} else if (subMessage.hasVariablemessage()) {
event = EventMessage.SET_VARIABLE;
payload = subMessage.getVariablemessage();
2020-09-28 18:52:54 +02:00
} else {
throw new Error("Unexpected batch message type");
2020-09-28 18:52:54 +02:00
}
if (event) {
this.dispatch(event, payload);
}
}
2020-09-28 18:52:54 +02:00
} else if (message.hasRoomjoinedmessage()) {
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
const items: { [itemId: number]: unknown } = {};
2020-09-28 18:52:54 +02:00
for (const item of roomJoinedMessage.getItemList()) {
items[item.getItemid()] = JSON.parse(item.getStatejson());
}
2020-09-28 18:52:54 +02:00
const variables = new Map<string, unknown>();
for (const variable of roomJoinedMessage.getVariableList()) {
try {
variables.set(variable.getName(), JSON.parse(variable.getValue()));
} catch (e) {
console.error(
'Unable to unserialize value received from server for variable "' +
variable.getName() +
'". Value received: "' +
variable.getValue() +
'". Error: ',
e
);
}
}
this.userId = roomJoinedMessage.getCurrentuserid();
this.tags = roomJoinedMessage.getTagList();
this._userRoomToken = roomJoinedMessage.getUserroomtoken();
this.dispatch(EventMessage.CONNECT, {
connection: this,
room: {
items,
variables,
} as RoomJoinedMessageInterface,
});
} else if (message.hasWorldfullmessage()) {
worldFullMessageStream.onMessage();
this.closed = true;
} else if (message.hasTokenexpiredmessage()) {
Active authentication Oauth (#1377) * Active authentication Oauth - Google authentication - GitHub authentication - Linkedin authentication Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Finish connexion et get user info connexion Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Fix lint error Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Change the expires token for 30 days Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update connexion stratgey - Set last room when it will be created and not when connexion is openned - Add '/login' end point permit to logout and open iframe to log user - Add logout feature permit to logout in front Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Implement logout and revoke token with hydra Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Fix pull develop conflict Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Profile url (#1399) * Create function that permit to get profile URL Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Continue profil user Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Add menu and logout button Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update last room use Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Profile callback permit to get url profile setting from admin Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Finish profile show Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Delete profileUrl will be not use today Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Correct lint Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update size of iframe Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Delete console log Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com> * Update feedback ARP Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>
2021-09-05 18:17:49 +02:00
connectionManager.logout();
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
} else if (message.hasWorldconnexionmessage()) {
worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage());
this.closed = true;
} else if (message.hasWebrtcsignaltoclientmessage()) {
2020-09-29 16:01:22 +02:00
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
this.dispatch(
EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL,
message.getWebrtcscreensharingsignaltoclientmessage()
);
2020-09-29 16:01:22 +02:00
} else if (message.hasWebrtcstartmessage()) {
this.dispatch(EventMessage.WEBRTC_START, message.getWebrtcstartmessage());
} else if (message.hasWebrtcdisconnectmessage()) {
this.dispatch(EventMessage.WEBRTC_DISCONNECT, message.getWebrtcdisconnectmessage());
} else if (message.hasPlayglobalmessage()) {
this.dispatch(EventMessage.PLAY_GLOBAL_MESSAGE, message.getPlayglobalmessage());
} else if (message.hasStopglobalmessage()) {
this.dispatch(EventMessage.STOP_GLOBAL_MESSAGE, message.getStopglobalmessage());
} else if (message.hasTeleportmessagemessage()) {
this.dispatch(EventMessage.TELEPORT, message.getTeleportmessagemessage());
2020-10-16 19:13:26 +02:00
} else if (message.hasSendjitsijwtmessage()) {
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
} else if (message.hasSendusermessage()) {
adminMessagesService.onSendusermessage(message.getSendusermessage() as SendUserMessage);
2021-03-11 01:25:36 +01:00
} else if (message.hasBanusermessage()) {
adminMessagesService.onSendusermessage(message.getBanusermessage() as BanUserMessage);
} else if (message.hasWorldfullwarningmessage()) {
warningContainerStore.activateWarningContainer();
} else if (message.hasRefreshroommessage()) {
//todo: implement a way to notify the user the room was refreshed.
} else if (message.hasFollowrequestmessage()) {
const requestMessage = message.getFollowrequestmessage() as FollowRequestMessage;
console.log("Got follow request from " + requestMessage.getLeader());
followStateStore.set(followStates.requesting);
followRoleStore.set(followRoles.follower);
followUsersStore.set([requestMessage.getLeader()]);
} else if (message.hasFollowconfirmationmessage()) {
const responseMessage = message.getFollowconfirmationmessage() as FollowConfirmationMessage;
console.log("Got follow response from " + responseMessage.getFollower());
followUsersStore.set([...get(followUsersStore), responseMessage.getFollower()]);
} else if (message.hasFollowabortmessage()) {
const abortMessage = message.getFollowabortmessage() as FollowAbortMessage;
console.log("Got follow abort message");
if (get(followRoleStore) === followRoles.follower) {
followStateStore.set(followStates.off);
followRoleStore.set(followRoles.leader);
followUsersStore.set([]);
} else {
let followers = get(followUsersStore);
const oldFollowerCount = followers.length;
followers = followers.filter((name) => name !== abortMessage.getFollower());
followUsersStore.set(followers);
if (followers.length === 0 && oldFollowerCount > 0) {
followStateStore.set(followStates.off);
followRoleStore.set(followRoles.leader);
}
}
} else if (message.hasErrormessage()) {
const errorMessage = message.getErrormessage() as ErrorMessage;
console.error("An error occurred server side: " + errorMessage.getMessage());
2020-09-29 16:01:22 +02:00
} else {
throw new Error("Unknown message received");
}
};
}
2020-09-29 16:01:22 +02:00
private dispatch(event: string, payload: unknown): void {
const listeners = this.listeners.get(event);
if (listeners === undefined) {
return;
}
for (const listener of listeners) {
listener(payload);
}
}
2020-10-20 16:39:23 +02:00
public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) {
2020-09-25 18:29:22 +02:00
const message = new SetPlayerDetailsMessage();
2020-09-29 17:24:16 +02:00
message.setName(userName);
2020-10-20 16:39:23 +02:00
message.setCharacterlayersList(characterLayersSelected.map((characterLayer) => characterLayer.name));
2020-06-22 16:10:18 +02:00
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setSetplayerdetailsmessage(message);
2020-09-28 18:52:54 +02:00
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public closeConnection(): void {
this.socket?.close();
2020-10-01 17:16:49 +02:00
this.closed = true;
2020-06-03 11:55:31 +02:00
}
private toPositionMessage(x: number, y: number, direction: string, moving: boolean): PositionMessage {
const positionMessage = new PositionMessage();
positionMessage.setX(Math.floor(x));
positionMessage.setY(Math.floor(y));
let directionEnum: Direction;
switch (direction) {
case "up":
directionEnum = Direction.UP;
break;
case "down":
directionEnum = Direction.DOWN;
break;
case "left":
directionEnum = Direction.LEFT;
break;
case "right":
directionEnum = Direction.RIGHT;
break;
default:
throw new Error("Unexpected direction");
}
positionMessage.setDirection(directionEnum);
positionMessage.setMoving(moving);
2020-09-28 18:52:54 +02:00
return positionMessage;
}
private toViewportMessage(viewport: ViewportInterface): ViewportMessage {
const viewportMessage = new ViewportMessage();
viewportMessage.setLeft(Math.floor(viewport.left));
viewportMessage.setRight(Math.floor(viewport.right));
viewportMessage.setTop(Math.floor(viewport.top));
viewportMessage.setBottom(Math.floor(viewport.bottom));
2020-09-28 18:52:54 +02:00
return viewportMessage;
}
public sharePosition(x: number, y: number, direction: string, moving: boolean, viewport: ViewportInterface): void {
if (!this.socket) {
2020-09-28 18:52:54 +02:00
return;
}
const positionMessage = this.toPositionMessage(x, y, direction, moving);
const viewportMessage = this.toViewportMessage(viewport);
const userMovesMessage = new UserMovesMessage();
userMovesMessage.setPosition(positionMessage);
userMovesMessage.setViewport(viewportMessage);
2020-09-24 10:05:16 +02:00
//console.log('Sending position ', positionMessage.getX(), positionMessage.getY());
2020-09-28 18:52:54 +02:00
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setUsermovesmessage(userMovesMessage);
2020-09-24 10:05:16 +02:00
2020-09-28 18:52:54 +02:00
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public setSilent(silent: boolean): void {
2020-09-28 18:52:54 +02:00
const silentMessage = new SilentMessage();
silentMessage.setSilent(silent);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setSilentmessage(silentMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public setViewport(viewport: ViewportInterface): void {
2020-09-24 17:36:10 +02:00
const viewportMessage = new ViewportMessage();
viewportMessage.setTop(Math.round(viewport.top));
viewportMessage.setBottom(Math.round(viewport.bottom));
viewportMessage.setLeft(Math.round(viewport.left));
viewportMessage.setRight(Math.round(viewport.right));
2020-09-28 18:52:54 +02:00
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setViewportmessage(viewportMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public onUserJoins(callback: (message: MessageUserJoined) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
2020-09-28 18:52:54 +02:00
callback(this.toMessageUserJoined(message));
2020-09-24 14:50:28 +02:00
});
}
2020-09-28 18:52:54 +02:00
// TODO: move this to protobuf utils
private toMessageUserJoined(message: UserJoinedMessage): MessageUserJoined {
const position = message.getPosition();
if (position === undefined) {
throw new Error("Invalid JOIN_ROOM message");
2020-09-28 18:52:54 +02:00
}
2020-10-20 16:39:23 +02:00
const characterLayers = message
.getCharacterlayersList()
.map((characterLayer: CharacterLayerMessage): BodyResourceDescriptionInterface => {
return {
name: characterLayer.getName(),
img: characterLayer.getUrl(),
};
});
2020-10-20 16:39:23 +02:00
2021-04-02 21:21:11 +02:00
const companion = message.getCompanion();
2020-09-28 18:52:54 +02:00
return {
userId: message.getUserid(),
name: message.getName(),
2020-10-20 16:39:23 +02:00
characterLayers,
visitCardUrl: message.getVisitcardurl(),
2021-04-02 21:21:11 +02:00
position: ProtobufClientUtils.toPointInterface(position),
companion: companion ? companion.getName() : null,
userUuid: message.getUseruuid(),
};
2020-09-28 18:52:54 +02:00
}
public onUserMoved(callback: (message: UserMovedMessage) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.USER_MOVED, callback);
//this.socket.on(EventMessage.USER_MOVED, callback);
}
/**
* Registers a listener on a message that is part of a batch
*/
2020-09-29 16:01:22 +02:00
private onMessage(eventName: string, callback: Function): void {
let callbacks = this.listeners.get(eventName);
if (callbacks === undefined) {
callbacks = new Array<Function>();
2020-09-29 16:01:22 +02:00
this.listeners.set(eventName, callbacks);
}
callbacks.push(callback);
}
public onUserLeft(callback: (userId: number) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.USER_LEFT, (message: UserLeftMessage) => {
2020-09-24 16:11:47 +02:00
callback(message.getUserid());
});
}
public onGroupUpdatedOrCreated(
callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void
): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
2020-09-28 18:52:54 +02:00
callback(this.toGroupCreatedUpdatedMessage(message));
});
}
2020-09-21 11:24:03 +02:00
2020-09-28 18:52:54 +02:00
private toGroupCreatedUpdatedMessage(message: GroupUpdateMessage): GroupCreatedUpdatedMessageInterface {
const position = message.getPosition();
if (position === undefined) {
throw new Error("Missing position in GROUP_CREATE_UPDATE");
2020-09-28 18:52:54 +02:00
}
2020-09-21 11:24:03 +02:00
2020-09-28 18:52:54 +02:00
return {
groupId: message.getGroupid(),
position: position.toObject(),
groupSize: message.getGroupsize(),
};
}
2020-09-21 11:24:03 +02:00
public onGroupDeleted(callback: (groupId: number) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
2020-09-24 10:05:16 +02:00
callback(message.getGroupid());
});
}
public onConnectingError(callback: (event: CloseEvent) => void): void {
this.onMessage(EventMessage.CONNECTING_ERROR, (event: CloseEvent) => {
callback(event);
});
}
2020-09-28 18:52:54 +02:00
public onConnectError(callback: (error: Event) => void): void {
this.socket.addEventListener("error", callback);
2020-09-28 18:52:54 +02:00
}
public onConnect(callback: (roomConnection: OnConnectInterface) => void): void {
//this.socket.addEventListener('open', callback)
this.onMessage(EventMessage.CONNECT, callback);
2020-06-22 16:10:18 +02:00
}
/**
* Triggered when we receive all the details of a room (users, groups, ...)
*/
/*public onStartRoom(callback: (event: RoomJoinedMessageInterface) => void): void {
this.onMessage(EventMessage.START_ROOM, callback);
}*/
public sendWebrtcSignal(signal: unknown, receiverId: number) {
2020-09-29 16:01:22 +02:00
const webRtcSignal = new WebRtcSignalToServerMessage();
webRtcSignal.setReceiverid(receiverId);
webRtcSignal.setSignal(JSON.stringify(signal));
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
2020-04-25 16:05:33 +02:00
}
public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) {
2020-09-29 16:01:22 +02:00
const webRtcSignal = new WebRtcSignalToServerMessage();
webRtcSignal.setReceiverid(receiverId);
webRtcSignal.setSignal(JSON.stringify(signal));
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcscreensharingsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
2020-04-25 16:05:33 +02:00
}
2020-09-29 16:01:22 +02:00
public receiveWebrtcStart(callback: (message: UserSimplePeerInterface) => void) {
this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => {
callback({
userId: message.getUserid(),
initiator: message.getInitiator(),
webRtcUser: message.getWebrtcusername() ?? undefined,
webRtcPassword: message.getWebrtcpassword() ?? undefined,
2020-09-29 16:01:22 +02:00
});
});
2020-04-25 16:05:33 +02:00
}
public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.WEBRTC_SIGNAL, (message: WebRtcSignalToClientMessage) => {
callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal()),
webRtcUser: message.getWebrtcusername() ?? undefined,
webRtcPassword: message.getWebrtcpassword() ?? undefined,
2020-09-29 16:01:22 +02:00
});
});
2020-04-25 16:05:33 +02:00
}
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, (message: WebRtcSignalToClientMessage) => {
callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal()),
webRtcUser: message.getWebrtcusername() ?? undefined,
webRtcPassword: message.getWebrtcpassword() ?? undefined,
2020-09-29 16:01:22 +02:00
});
});
2020-04-25 16:05:33 +02:00
}
public onServerDisconnected(callback: () => void): void {
this.socket.addEventListener("close", (event) => {
if (this.closed === true || connectionManager.unloading) {
2020-10-01 17:16:49 +02:00
return;
}
console.log("Socket closed with code " + event.code + ". Reason: " + event.reason);
2020-09-28 18:52:54 +02:00
if (event.code === 1000) {
// Normal closure case
return;
}
callback();
2020-05-13 20:22:42 +02:00
});
}
public getUserId(): number {
if (this.userId === null) throw "UserId cannot be null!";
return this.userId;
2020-05-13 20:22:42 +02:00
}
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.WEBRTC_DISCONNECT, (message: WebRtcDisconnectMessage) => {
callback({
userId: message.getUserid(),
2020-09-29 16:01:22 +02:00
});
});
2020-05-02 20:46:02 +02:00
}
2020-07-27 22:36:07 +02:00
2020-09-24 17:24:37 +02:00
emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void {
const itemEventMessage = new ItemEventMessage();
itemEventMessage.setItemid(itemId);
itemEventMessage.setEvent(event);
itemEventMessage.setStatejson(JSON.stringify(state));
itemEventMessage.setParametersjson(JSON.stringify(parameters));
2020-09-28 18:52:54 +02:00
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setItemeventmessage(itemEventMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
2020-07-27 22:36:07 +02:00
}
emitSetVariableEvent(name: string, value: unknown): void {
const variableMessage = new VariableMessage();
variableMessage.setName(name);
variableMessage.setValue(JSON.stringify(value));
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setVariablemessage(variableMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
2020-07-27 22:36:07 +02:00
onActionableEvent(callback: (message: ItemEventMessageInterface) => void): void {
2020-09-29 16:01:22 +02:00
this.onMessage(EventMessage.ITEM_EVENT, (message: ItemEventMessage) => {
2020-09-24 17:24:37 +02:00
callback({
itemId: message.getItemid(),
event: message.getEvent(),
parameters: JSON.parse(message.getParametersjson()),
state: JSON.parse(message.getStatejson()),
2020-09-24 17:24:37 +02:00
});
});
2020-07-27 22:36:07 +02:00
}
public uploadAudio(file: FormData) {
return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file)
.then((res: { data: {} }) => {
return res.data;
})
.catch((err) => {
console.error(err);
throw err;
});
}
/* public receivePlayGlobalMessage(callback: (message: PlayGlobalMessageInterface) => void) {
return this.onMessage(EventMessage.PLAY_GLOBAL_MESSAGE, (message: PlayGlobalMessage) => {
callback({
id: message.getId(),
type: message.getType(),
message: message.getMessage(),
});
});
}*/
public receiveStopGlobalMessage(callback: (messageId: string) => void) {
return this.onMessage(EventMessage.STOP_GLOBAL_MESSAGE, (message: StopGlobalMessage) => {
callback(message.getId());
});
}
public receiveTeleportMessage(callback: (messageId: string) => void) {
return this.onMessage(EventMessage.TELEPORT, (message: TeleportMessageMessage) => {
callback(message.getMap());
});
}
public emitGlobalMessage(message: PlayGlobalMessageInterface): void {
const playGlobalMessage = new PlayGlobalMessage();
playGlobalMessage.setType(message.type);
playGlobalMessage.setContent(message.content);
playGlobalMessage.setBroadcasttoworld(message.broadcastToWorld);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setPlayglobalmessage(playGlobalMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
2020-10-12 11:22:41 +02:00
public emitReportPlayerMessage(reportedUserUuid: string, reportComment: string): void {
2020-10-12 11:22:41 +02:00
const reportPlayerMessage = new ReportPlayerMessage();
reportPlayerMessage.setReporteduseruuid(reportedUserUuid);
2020-10-12 11:22:41 +02:00
reportPlayerMessage.setReportcomment(reportComment);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setReportplayermessage(reportPlayerMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public emitQueryJitsiJwtMessage(jitsiRoom: string, tag: string | undefined): void {
2020-10-16 19:13:26 +02:00
const queryJitsiJwtMessage = new QueryJitsiJwtMessage();
queryJitsiJwtMessage.setJitsiroom(jitsiRoom);
if (tag !== undefined) {
queryJitsiJwtMessage.setTag(tag);
}
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setQueryjitsijwtmessage(queryJitsiJwtMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public onStartJitsiRoom(callback: (jwt: string, room: string) => void): void {
this.onMessage(EventMessage.START_JITSI_ROOM, (message: SendJitsiJwtMessage) => {
callback(message.getJwt(), message.getJitsiroom());
});
}
public onSetVariable(callback: (name: string, value: unknown) => void): void {
this.onMessage(EventMessage.SET_VARIABLE, (message: VariableMessage) => {
const name = message.getName();
const serializedValue = message.getValue();
let value: unknown = undefined;
if (serializedValue) {
try {
value = JSON.parse(serializedValue);
} catch (e) {
console.error(
'Unable to unserialize value received from server for variable "' +
name +
'". Value received: "' +
serializedValue +
'". Error: ',
e
);
}
}
callback(name, value);
});
}
public hasTag(tag: string): boolean {
2020-10-14 11:48:34 +02:00
return this.tags.includes(tag);
}
public isAdmin(): boolean {
return this.hasTag("admin");
}
public emitEmoteEvent(emoteName: string): void {
const emoteMessage = new EmotePromptMessage();
emoteMessage.setEmote(emoteName);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setEmotepromptmessage(emoteMessage);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
2021-12-15 14:48:45 +01:00
public emitFollowRequest(): void {
if (!this.userId) {
return;
}
console.log("Emitting follow request");
const message = new FollowRequestMessage();
2021-12-15 14:48:45 +01:00
message.setLeader(this.userId);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setFollowrequestmessage(message);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
2021-12-15 14:48:45 +01:00
public emitFollowConfirmation(): void {
if (!this.userId) {
return;
}
console.log("Emitting follow confirmation");
const message = new FollowConfirmationMessage();
2021-12-15 14:48:45 +01:00
message.setLeader(get(followUsersStore)[0]);
message.setFollower(this.userId);
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setFollowconfirmationmessage(message);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
2021-12-15 14:48:45 +01:00
public emitFollowAbort(): void {
const isLeader = get(followRoleStore) === followRoles.leader;
const hasFollowers = get(followUsersStore).length > 0;
if (!this.userId || (isLeader && !hasFollowers)) {
return;
}
console.log("Emitting follow abort");
const message = new FollowAbortMessage();
2021-12-15 14:48:45 +01:00
message.setLeader(isLeader ? this.userId : get(followUsersStore)[0]);
message.setFollower(isLeader ? 0 : this.userId);
2021-12-12 00:24:39 +01:00
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setFollowabortmessage(message);
2021-12-12 00:24:39 +01:00
this.socket.send(clientToServerMessage.serializeBinary().buffer);
}
public getAllTags(): string[] {
return this.tags;
}
public get userRoomToken(): string | undefined {
return this._userRoomToken;
}
}