Merge branch 'develop' of https://github.com/thecodingmachine/workadventure into FTUEPopup
* 'develop' of https://github.com/thecodingmachine/workadventure: Trying to enable back connection on admin from develop, knowing that the develop certificate is broken. Fixing priority. Trying to enable back connection on admin from develop, knowing that the develop certificate is broken Revert "Adding back admin in develop branch CI" Adding back admin in develop branch CI Fixing GA tag not included in play domain FEATURE: better implementation of the admin global message Fix ci Update private access Allow URLs relative to map base in iframe / openWebsite # Conflicts: # front/src/Phaser/Game/GameScene.ts
This commit is contained in:
commit
b175b7164d
@ -1,5 +1,4 @@
|
|||||||
import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
import {HttpResponse} from "uWebSockets.js";
|
||||||
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
|
|
||||||
export class BaseController {
|
export class BaseController {
|
||||||
|
@ -4,7 +4,6 @@ import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
|||||||
import { parse } from 'query-string';
|
import { parse } from 'query-string';
|
||||||
import {App} from "../Server/sifrr.server";
|
import {App} from "../Server/sifrr.server";
|
||||||
import {socketManager} from "../Services/SocketManager";
|
import {socketManager} from "../Services/SocketManager";
|
||||||
import {ServerWritableStream} from "grpc";
|
|
||||||
|
|
||||||
export class DebugController {
|
export class DebugController {
|
||||||
constructor(private App : App) {
|
constructor(private App : App) {
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
AdminGlobalMessage,
|
AdminGlobalMessage,
|
||||||
AdminMessage,
|
AdminMessage,
|
||||||
AdminPusherToBackMessage,
|
AdminPusherToBackMessage,
|
||||||
|
AdminRoomMessage,
|
||||||
BanMessage,
|
BanMessage,
|
||||||
EmptyMessage,
|
EmptyMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
@ -51,12 +52,8 @@ const roomManager: IRoomManagerServer = {
|
|||||||
} else {
|
} else {
|
||||||
if (message.hasJoinroommessage()) {
|
if (message.hasJoinroommessage()) {
|
||||||
throw new Error('Cannot call JoinRoomMessage twice!');
|
throw new Error('Cannot call JoinRoomMessage twice!');
|
||||||
/*} else if (message.hasViewportmessage()) {
|
|
||||||
socketManager.handleViewport(client, message.getViewportmessage() as ViewportMessage);*/
|
|
||||||
} else if (message.hasUsermovesmessage()) {
|
} else if (message.hasUsermovesmessage()) {
|
||||||
socketManager.handleUserMovesMessage(room, user, message.getUsermovesmessage() as UserMovesMessage);
|
socketManager.handleUserMovesMessage(room, user, message.getUsermovesmessage() as UserMovesMessage);
|
||||||
/*} else if (message.hasSetplayerdetailsmessage()) {
|
|
||||||
socketManager.handleSetPlayerDetails(client, message.getSetplayerdetailsmessage() as SetPlayerDetailsMessage);*/
|
|
||||||
} else if (message.hasSilentmessage()) {
|
} else if (message.hasSilentmessage()) {
|
||||||
socketManager.handleSilentMessage(room, user, message.getSilentmessage() as SilentMessage);
|
socketManager.handleSilentMessage(room, user, message.getSilentmessage() as SilentMessage);
|
||||||
} else if (message.hasItemeventmessage()) {
|
} else if (message.hasItemeventmessage()) {
|
||||||
@ -67,8 +64,6 @@ const roomManager: IRoomManagerServer = {
|
|||||||
socketManager.emitScreenSharing(room, user, message.getWebrtcscreensharingsignaltoservermessage() as WebRtcSignalToServerMessage);
|
socketManager.emitScreenSharing(room, user, message.getWebrtcscreensharingsignaltoservermessage() as WebRtcSignalToServerMessage);
|
||||||
} else if (message.hasPlayglobalmessage()) {
|
} else if (message.hasPlayglobalmessage()) {
|
||||||
socketManager.emitPlayGlobalMessage(room, message.getPlayglobalmessage() as PlayGlobalMessage);
|
socketManager.emitPlayGlobalMessage(room, message.getPlayglobalmessage() as PlayGlobalMessage);
|
||||||
/*} else if (message.hasReportplayermessage()){
|
|
||||||
socketManager.handleReportMessage(client, message.getReportplayermessage() as ReportPlayerMessage);*/
|
|
||||||
} else if (message.hasQueryjitsijwtmessage()){
|
} else if (message.hasQueryjitsijwtmessage()){
|
||||||
socketManager.handleQueryJitsiJwtMessage(user, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
socketManager.handleQueryJitsiJwtMessage(user, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
||||||
}else if (message.hasSendusermessage()) {
|
}else if (message.hasSendusermessage()) {
|
||||||
@ -120,9 +115,6 @@ const roomManager: IRoomManagerServer = {
|
|||||||
call.end();
|
call.end();
|
||||||
})
|
})
|
||||||
|
|
||||||
/*call.on('finish', () => {
|
|
||||||
debug('listenZone finish');
|
|
||||||
})*/
|
|
||||||
call.on('close', () => {
|
call.on('close', () => {
|
||||||
debug('listenZone connection closed');
|
debug('listenZone connection closed');
|
||||||
socketManager.removeZoneListener(call, zoneMessage.getRoomid(), zoneMessage.getX(), zoneMessage.getY());
|
socketManager.removeZoneListener(call, zoneMessage.getRoomid(), zoneMessage.getX(), zoneMessage.getY());
|
||||||
@ -150,26 +142,6 @@ const roomManager: IRoomManagerServer = {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error('The first message sent MUST be of type JoinRoomMessage');
|
throw new Error('The first message sent MUST be of type JoinRoomMessage');
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/*if (message.hasJoinroommessage()) {
|
|
||||||
throw new Error('Cannot call JoinRoomMessage twice!');
|
|
||||||
} else if (message.hasUsermovesmessage()) {
|
|
||||||
socketManager.handleUserMovesMessage(room, user, message.getUsermovesmessage() as UserMovesMessage);
|
|
||||||
} else if (message.hasSilentmessage()) {
|
|
||||||
socketManager.handleSilentMessage(room, user, message.getSilentmessage() as SilentMessage);
|
|
||||||
} else if (message.hasItemeventmessage()) {
|
|
||||||
socketManager.handleItemEvent(room, user, message.getItemeventmessage() as ItemEventMessage);
|
|
||||||
} else if (message.hasWebrtcsignaltoservermessage()) {
|
|
||||||
socketManager.emitVideo(room, user, message.getWebrtcsignaltoservermessage() as WebRtcSignalToServerMessage);
|
|
||||||
} else if (message.hasWebrtcscreensharingsignaltoservermessage()) {
|
|
||||||
socketManager.emitScreenSharing(room, user, message.getWebrtcscreensharingsignaltoservermessage() as WebRtcSignalToServerMessage);
|
|
||||||
} else if (message.hasPlayglobalmessage()) {
|
|
||||||
socketManager.emitPlayGlobalMessage(room, message.getPlayglobalmessage() as PlayGlobalMessage);
|
|
||||||
} else if (message.hasQueryjitsijwtmessage()){
|
|
||||||
socketManager.handleQueryJitsiJwtMessage(user, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
|
||||||
} else {
|
|
||||||
throw new Error('Unhandled message type');
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emitError(call, e);
|
emitError(call, e);
|
||||||
@ -208,6 +180,10 @@ const roomManager: IRoomManagerServer = {
|
|||||||
|
|
||||||
callback(null, new EmptyMessage());
|
callback(null, new EmptyMessage());
|
||||||
},
|
},
|
||||||
|
sendAdminMessageToRoom(call: ServerUnaryCall<AdminRoomMessage>, callback: sendUnaryData<EmptyMessage>): void {
|
||||||
|
socketManager.sendAdminRoomMessage(call.request.getRoomid(), call.request.getMessage());
|
||||||
|
callback(null, new EmptyMessage());
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export {roomManager};
|
export {roomManager};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import {v4} from "uuid";
|
|
||||||
|
|
||||||
export interface AdminApiData {
|
export interface AdminApiData {
|
||||||
organizationSlug: string
|
organizationSlug: string
|
||||||
@ -21,13 +20,6 @@ export interface CharacterTexture {
|
|||||||
rights: string
|
rights: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchMemberDataByUuidResponse {
|
|
||||||
uuid: string;
|
|
||||||
tags: string[];
|
|
||||||
textures: CharacterTexture[];
|
|
||||||
messages: unknown[];
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminApi {
|
class AdminApi {
|
||||||
|
|
||||||
async fetchMapDetails(organizationSlug: string, worldSlug: string, roomSlug: string|undefined): Promise<AdminApiData> {
|
async fetchMapDetails(organizationSlug: string, worldSlug: string, roomSlug: string|undefined): Promise<AdminApiData> {
|
||||||
@ -52,65 +44,6 @@ class AdminApi {
|
|||||||
)
|
)
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMemberDataByUuid(uuid: string): Promise<FetchMemberDataByUuidResponse> {
|
|
||||||
if (!ADMIN_API_URL) {
|
|
||||||
return Promise.reject('No admin backoffice set!');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
|
||||||
)
|
|
||||||
return res.data;
|
|
||||||
} catch (e) {
|
|
||||||
if (e?.response?.status == 404) {
|
|
||||||
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
|
||||||
console.warn('Cannot find user with uuid "'+uuid+'". Performing an anonymous login instead.');
|
|
||||||
return {
|
|
||||||
uuid: v4(),
|
|
||||||
tags: [],
|
|
||||||
textures: [],
|
|
||||||
messages: [],
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
|
||||||
if (!ADMIN_API_URL) {
|
|
||||||
return Promise.reject('No admin backoffice set!');
|
|
||||||
}
|
|
||||||
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken,
|
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
|
||||||
)
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchCheckUserByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
|
||||||
if (!ADMIN_API_URL) {
|
|
||||||
return Promise.reject('No admin backoffice set!');
|
|
||||||
}
|
|
||||||
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/check-user/'+organizationMemberToken,
|
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
|
||||||
)
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
reportPlayer(reportedUserUuid: string, reportedUserComment: string, reporterUserUuid: string, reportWorldSlug: string) {
|
|
||||||
return Axios.post(`${ADMIN_API_URL}/api/report`, {
|
|
||||||
reportedUserUuid,
|
|
||||||
reportedUserComment,
|
|
||||||
reporterUserUuid,
|
|
||||||
reportWorldSlug,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {"Authorization": `${ADMIN_API_TOKEN}`}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const adminApi = new AdminApi();
|
export const adminApi = new AdminApi();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {GameRoom} from "../Model/GameRoom";
|
import {GameRoom} from "../Model/GameRoom";
|
||||||
import {CharacterLayer} from "_Model/Websocket/CharacterLayer";
|
|
||||||
import {
|
import {
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
ItemStateMessage,
|
ItemStateMessage,
|
||||||
@ -22,7 +21,11 @@ import {
|
|||||||
Zone as ProtoZone,
|
Zone as ProtoZone,
|
||||||
BatchToPusherMessage,
|
BatchToPusherMessage,
|
||||||
SubToPusherMessage,
|
SubToPusherMessage,
|
||||||
UserJoinedZoneMessage, GroupUpdateZoneMessage, GroupLeftZoneMessage, UserLeftZoneMessage, BanUserMessage
|
UserJoinedZoneMessage,
|
||||||
|
GroupUpdateZoneMessage,
|
||||||
|
GroupLeftZoneMessage,
|
||||||
|
UserLeftZoneMessage,
|
||||||
|
BanUserMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {User, UserSocket} from "../Model/User";
|
import {User, UserSocket} from "../Model/User";
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
@ -51,18 +54,6 @@ import crypto from "crypto";
|
|||||||
|
|
||||||
const debug = Debug('sockermanager');
|
const debug = Debug('sockermanager');
|
||||||
|
|
||||||
interface AdminSocketRoomsList {
|
|
||||||
[index: string]: number;
|
|
||||||
}
|
|
||||||
interface AdminSocketUsersList {
|
|
||||||
[index: string]: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminSocketData {
|
|
||||||
rooms: AdminSocketRoomsList,
|
|
||||||
users: AdminSocketUsersList,
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitZoneMessage(subMessage: SubToPusherMessage, socket: ZoneSocket): void {
|
function emitZoneMessage(subMessage: SubToPusherMessage, socket: ZoneSocket): void {
|
||||||
// TODO: should we batch those every 100ms?
|
// TODO: should we batch those every 100ms?
|
||||||
const batchMessage = new BatchToPusherMessage();
|
const batchMessage = new BatchToPusherMessage();
|
||||||
@ -83,68 +74,13 @@ export class SocketManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*getAdminSocketDataFor(roomId:string): AdminSocketData {
|
|
||||||
const data:AdminSocketData = {
|
|
||||||
rooms: {},
|
|
||||||
users: {},
|
|
||||||
}
|
|
||||||
const room = this.rooms.get(roomId);
|
|
||||||
if (room === undefined) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
const users = room.getUsers();
|
|
||||||
data.rooms[roomId] = users.size;
|
|
||||||
users.forEach(user => {
|
|
||||||
data.users[user.uuid] = true
|
|
||||||
})
|
|
||||||
return data;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public async handleJoinRoom(socket: UserSocket, joinRoomMessage: JoinRoomMessage): Promise<{ room: GameRoom; user: User }> {
|
public async handleJoinRoom(socket: UserSocket, joinRoomMessage: JoinRoomMessage): Promise<{ room: GameRoom; user: User }> {
|
||||||
/*const positionMessage = joinRoomMessage.getPositionmessage();
|
|
||||||
if (positionMessage === undefined) {
|
|
||||||
// TODO: send error message?
|
|
||||||
throw new Error('Empty pointMessage found in JoinRoomMessage');
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//const position = ProtobufUtils.toPointInterface(positionMessage);
|
|
||||||
//const viewport = client.viewport;
|
|
||||||
|
|
||||||
//this.sockets.set(client.userId, client); //todo: should this be at the end of the function?
|
|
||||||
|
|
||||||
//join new previous room
|
//join new previous room
|
||||||
const {room, user} = await this.joinRoom(socket, joinRoomMessage);
|
const {room, user} = await this.joinRoom(socket, joinRoomMessage);
|
||||||
|
|
||||||
//const things = room.setViewport(client, viewport);
|
|
||||||
|
|
||||||
const roomJoinedMessage = new RoomJoinedMessage();
|
const roomJoinedMessage = new RoomJoinedMessage();
|
||||||
roomJoinedMessage.setTagList(joinRoomMessage.getTagList());
|
roomJoinedMessage.setTagList(joinRoomMessage.getTagList());
|
||||||
/*for (const thing of things) {
|
|
||||||
if (thing instanceof User) {
|
|
||||||
const player: ExSocketInterface|undefined = this.sockets.get(thing.id);
|
|
||||||
if (player === undefined) {
|
|
||||||
console.warn('Something went wrong. The World contains a user "'+thing.id+"' but this user does not exist in the sockets list!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userJoinedMessage = new UserJoinedMessage();
|
|
||||||
userJoinedMessage.setUserid(thing.id);
|
|
||||||
userJoinedMessage.setName(player.name);
|
|
||||||
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(player.characterLayers));
|
|
||||||
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
|
||||||
|
|
||||||
roomJoinedMessage.addUser(userJoinedMessage);
|
|
||||||
roomJoinedMessage.setTagList(joinRoomMessage.getTagList());
|
|
||||||
} else if (thing instanceof Group) {
|
|
||||||
const groupUpdateMessage = new GroupUpdateMessage();
|
|
||||||
groupUpdateMessage.setGroupid(thing.getId());
|
|
||||||
groupUpdateMessage.setPosition(ProtobufUtils.toPointMessage(thing.getPosition()));
|
|
||||||
|
|
||||||
roomJoinedMessage.addGroup(groupUpdateMessage);
|
|
||||||
} else {
|
|
||||||
console.error("Unexpected type for Movable returned by setViewport");
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
for (const [itemId, item] of room.getItemsState().entries()) {
|
for (const [itemId, item] of room.getItemsState().entries()) {
|
||||||
const itemStateMessage = new ItemStateMessage();
|
const itemStateMessage = new ItemStateMessage();
|
||||||
@ -158,8 +94,6 @@ export class SocketManager {
|
|||||||
|
|
||||||
const serverToClientMessage = new ServerToClientMessage();
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
||||||
|
|
||||||
//user.socket.write(serverToClientMessage);
|
|
||||||
console.log('SENDING MESSAGE roomJoinedMessage');
|
console.log('SENDING MESSAGE roomJoinedMessage');
|
||||||
socket.write(serverToClientMessage);
|
socket.write(serverToClientMessage);
|
||||||
|
|
||||||
@ -168,13 +102,6 @@ export class SocketManager {
|
|||||||
user
|
user
|
||||||
};
|
};
|
||||||
|
|
||||||
/*const serverToClientMessage = new ServerToClientMessage();
|
|
||||||
serverToClientMessage.setRoomjoinedmessage(roomJoinedMessage);
|
|
||||||
|
|
||||||
if (!client.disconnecting) {
|
|
||||||
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUserMovesMessage(room: GameRoom, user: User, userMovesMessage: UserMovesMessage) {
|
handleUserMovesMessage(room: GameRoom, user: User, userMovesMessage: UserMovesMessage) {
|
||||||
@ -693,33 +620,6 @@ export class SocketManager {
|
|||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
|
|
||||||
*/
|
|
||||||
static mergeCharacterLayersAndCustomTextures(characterLayers: string[], memberTextures: CharacterTexture[]): CharacterLayer[] {
|
|
||||||
const characterLayerObjs: CharacterLayer[] = [];
|
|
||||||
for (const characterLayer of characterLayers) {
|
|
||||||
if (characterLayer.startsWith('customCharacterTexture')) {
|
|
||||||
const customCharacterLayerId: number = +characterLayer.substr(22);
|
|
||||||
for (const memberTexture of memberTextures) {
|
|
||||||
if (memberTexture.id == customCharacterLayerId) {
|
|
||||||
characterLayerObjs.push({
|
|
||||||
name: characterLayer,
|
|
||||||
url: memberTexture.url
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
characterLayerObjs.push({
|
|
||||||
name: characterLayer,
|
|
||||||
url: undefined
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return characterLayerObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addZoneListener(call: ZoneSocket, roomId: string, x: number, y: number): void {
|
public addZoneListener(call: ZoneSocket, roomId: string, x: number, y: number): void {
|
||||||
const room = this.rooms.get(roomId);
|
const room = this.rooms.get(roomId);
|
||||||
if (!room) {
|
if (!room) {
|
||||||
@ -773,11 +673,6 @@ export class SocketManager {
|
|||||||
public async handleJoinAdminRoom(admin: Admin, roomId: string): Promise<GameRoom> {
|
public async handleJoinAdminRoom(admin: Admin, roomId: string): Promise<GameRoom> {
|
||||||
const room = 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);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
room.adminJoin(admin);
|
room.adminJoin(admin);
|
||||||
|
|
||||||
return room;
|
return room;
|
||||||
@ -807,7 +702,7 @@ export class SocketManager {
|
|||||||
|
|
||||||
const sendUserMessage = new SendUserMessage();
|
const sendUserMessage = new SendUserMessage();
|
||||||
sendUserMessage.setMessage(message);
|
sendUserMessage.setMessage(message);
|
||||||
sendUserMessage.setType('ban');
|
sendUserMessage.setType('ban'); //todo: is the type correct?
|
||||||
|
|
||||||
const subToPusherMessage = new SubToPusherMessage();
|
const subToPusherMessage = new SubToPusherMessage();
|
||||||
subToPusherMessage.setSendusermessage(sendUserMessage);
|
subToPusherMessage.setSendusermessage(sendUserMessage);
|
||||||
@ -843,6 +738,27 @@ export class SocketManager {
|
|||||||
// Let's close the connection when the user is banned.
|
// Let's close the connection when the user is banned.
|
||||||
recipient.socket.end();
|
recipient.socket.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sendAdminRoomMessage(roomId: string, message: string) {
|
||||||
|
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 sendUserMessage = new SendUserMessage();
|
||||||
|
sendUserMessage.setMessage(message);
|
||||||
|
sendUserMessage.setType('message');
|
||||||
|
|
||||||
|
const clientMessage = new ServerToClientMessage();
|
||||||
|
clientMessage.setSendusermessage(sendUserMessage);
|
||||||
|
|
||||||
|
recipient.socket.write(clientMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
local tag = namespace,
|
local tag = namespace,
|
||||||
local url = if namespace == "master" then "workadventu.re" else namespace+".workadventure.test.thecodingmachine.com",
|
local url = if namespace == "master" then "workadventu.re" else namespace+".workadventure.test.thecodingmachine.com",
|
||||||
// develop branch does not use admin because of issue with SSL certificate of admin as of now.
|
// develop branch does not use admin because of issue with SSL certificate of admin as of now.
|
||||||
local adminUrl = if namespace == "master" /*|| namespace == "develop"*/ || std.startsWith(namespace, "admin") then "https://"+url else null,
|
local adminUrl = if namespace == "master" || namespace == "develop" || std.startsWith(namespace, "admin") then "https://"+url else null,
|
||||||
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"containers": {
|
"containers": {
|
||||||
@ -23,9 +23,12 @@
|
|||||||
"JITSI_URL": env.JITSI_URL,
|
"JITSI_URL": env.JITSI_URL,
|
||||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
"TURN_STATIC_AUTH_SECRET": env.TURN_STATIC_AUTH_SECRET,
|
"TURN_STATIC_AUTH_SECRET": env.TURN_STATIC_AUTH_SECRET,
|
||||||
} + if adminUrl != null then {
|
} + (if adminUrl != null then {
|
||||||
"ADMIN_API_URL": adminUrl,
|
"ADMIN_API_URL": adminUrl,
|
||||||
} else {}
|
} else {}) + if namespace != "master" then {
|
||||||
|
// Absolutely ugly WorkAround to circumvent broken certificates on the K8S test cluster. Don't do this in production kids!
|
||||||
|
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"back2": {
|
"back2": {
|
||||||
"image": "thecodingmachine/workadventure-back:"+tag,
|
"image": "thecodingmachine/workadventure-back:"+tag,
|
||||||
@ -42,9 +45,12 @@
|
|||||||
"JITSI_URL": env.JITSI_URL,
|
"JITSI_URL": env.JITSI_URL,
|
||||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
"TURN_STATIC_AUTH_SECRET": env.TURN_STATIC_AUTH_SECRET,
|
"TURN_STATIC_AUTH_SECRET": env.TURN_STATIC_AUTH_SECRET,
|
||||||
} + if adminUrl != null then {
|
} + (if adminUrl != null then {
|
||||||
"ADMIN_API_URL": adminUrl,
|
"ADMIN_API_URL": adminUrl,
|
||||||
} else {}
|
} else {}) + if namespace != "master" then {
|
||||||
|
// Absolutely ugly WorkAround to circumvent broken certificates on the K8S test cluster. Don't do this in production kids!
|
||||||
|
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pusher": {
|
"pusher": {
|
||||||
"replicas": 2,
|
"replicas": 2,
|
||||||
@ -61,9 +67,12 @@
|
|||||||
"JITSI_URL": env.JITSI_URL,
|
"JITSI_URL": env.JITSI_URL,
|
||||||
"API_URL": "back1:50051,back2:50051",
|
"API_URL": "back1:50051,back2:50051",
|
||||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
} + if adminUrl != null then {
|
} + (if adminUrl != null then {
|
||||||
"ADMIN_API_URL": adminUrl,
|
"ADMIN_API_URL": adminUrl,
|
||||||
} else {}
|
} else {}) + if namespace != "master" then {
|
||||||
|
// Absolutely ugly WorkAround to circumvent broken certificates on the K8S test cluster. Don't do this in production kids!
|
||||||
|
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"front": {
|
"front": {
|
||||||
"image": "thecodingmachine/workadventure-front:"+tag,
|
"image": "thecodingmachine/workadventure-front:"+tag,
|
||||||
|
1
front/dist/.gitignore
vendored
1
front/dist/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
index.html
|
index.html
|
||||||
|
index.tmpl.html.tmp
|
||||||
|
@ -3,6 +3,7 @@ import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
|||||||
import {RoomConnection} from "../Connexion/RoomConnection";
|
import {RoomConnection} from "../Connexion/RoomConnection";
|
||||||
import {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
import {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
||||||
import {ADMIN_URL} from "../Enum/EnvironmentVariable";
|
import {ADMIN_URL} from "../Enum/EnvironmentVariable";
|
||||||
|
import {AdminMessageEventTypes} from "../Connexion/AdminMessagesService";
|
||||||
|
|
||||||
export const CLASS_CONSOLE_MESSAGE = 'main-console';
|
export const CLASS_CONSOLE_MESSAGE = 'main-console';
|
||||||
export const INPUT_CONSOLE_MESSAGE = 'input-send-text';
|
export const INPUT_CONSOLE_MESSAGE = 'input-send-text';
|
||||||
@ -10,13 +11,16 @@ export const UPLOAD_CONSOLE_MESSAGE = 'input-upload-music';
|
|||||||
export const INPUT_TYPE_CONSOLE = 'input-type';
|
export const INPUT_TYPE_CONSOLE = 'input-type';
|
||||||
export const VIDEO_QUALITY_SELECT = 'select-video-quality';
|
export const VIDEO_QUALITY_SELECT = 'select-video-quality';
|
||||||
|
|
||||||
export const AUDIO_TYPE = 'audio';
|
export const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
||||||
export const MESSAGE_TYPE = 'message';
|
export const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
||||||
|
|
||||||
interface EventTargetFiles extends EventTarget {
|
interface EventTargetFiles extends EventTarget {
|
||||||
files: Array<File>;
|
files: Array<File>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
export class ConsoleGlobalMessageManager {
|
export class ConsoleGlobalMessageManager {
|
||||||
|
|
||||||
private readonly divMainConsole: HTMLDivElement;
|
private readonly divMainConsole: HTMLDivElement;
|
||||||
@ -372,23 +376,6 @@ export class ConsoleGlobalMessageManager {
|
|||||||
this.buttonSendMainConsole.classList.remove('active');
|
this.buttonSendMainConsole.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*activeSettingConsole(){
|
|
||||||
this.activeSetting = true;
|
|
||||||
if(this.activeMessage){
|
|
||||||
this.disabledSettingConsole();
|
|
||||||
}
|
|
||||||
this.active();
|
|
||||||
this.divSettingConsole.classList.add('active');
|
|
||||||
//this.buttonSettingsMainConsole.classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
disabledSettingConsole(){
|
|
||||||
this.activeSetting = false;
|
|
||||||
this.disabled();
|
|
||||||
this.divSettingConsole.classList.remove('active');
|
|
||||||
//this.buttonSettingsMainConsole.classList.remove('active');
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private getSectionId(id: string) : string {
|
private getSectionId(id: string) : string {
|
||||||
return `section-${id}`;
|
return `section-${id}`;
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,29 @@
|
|||||||
import {RoomConnection} from "../Connexion/RoomConnection";
|
|
||||||
import * as TypeMessages from "./TypeMessage";
|
import * as TypeMessages from "./TypeMessage";
|
||||||
import List = Phaser.Structs.List;
|
|
||||||
import {UpdatedLocalStreamCallback} from "../WebRtc/MediaManager";
|
|
||||||
import {Banned} from "./TypeMessage";
|
import {Banned} from "./TypeMessage";
|
||||||
|
import {adminMessagesService} from "../Connexion/AdminMessagesService";
|
||||||
|
|
||||||
export interface TypeMessageInterface {
|
export interface TypeMessageInterface {
|
||||||
showMessage(message: string): void;
|
showMessage(message: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserMessageManager {
|
class UserMessageManager {
|
||||||
|
|
||||||
typeMessages: Map<string, TypeMessageInterface> = new Map<string, TypeMessageInterface>();
|
typeMessages: Map<string, TypeMessageInterface> = new Map<string, TypeMessageInterface>();
|
||||||
receiveBannedMessageListener: Set<Function> = new Set<UpdatedLocalStreamCallback>();
|
receiveBannedMessageListener!: Function;
|
||||||
|
|
||||||
constructor(private Connection: RoomConnection) {
|
constructor() {
|
||||||
const valueTypeMessageTab = Object.values(TypeMessages);
|
const valueTypeMessageTab = Object.values(TypeMessages);
|
||||||
Object.keys(TypeMessages).forEach((value: string, index: number) => {
|
Object.keys(TypeMessages).forEach((value: string, index: number) => {
|
||||||
const typeMessageInstance: TypeMessageInterface = (new valueTypeMessageTab[index]() as TypeMessageInterface);
|
const typeMessageInstance: TypeMessageInterface = (new valueTypeMessageTab[index]() as TypeMessageInterface);
|
||||||
this.typeMessages.set(value.toLowerCase(), typeMessageInstance);
|
this.typeMessages.set(value.toLowerCase(), typeMessageInstance);
|
||||||
});
|
});
|
||||||
this.initialise();
|
|
||||||
}
|
|
||||||
|
|
||||||
initialise() {
|
adminMessagesService.messageStream.subscribe((event) => {
|
||||||
//receive signal to show message
|
const typeMessage = this.showMessage(event.type, event.text);
|
||||||
this.Connection.receiveUserMessage((type: string, message: string) => {
|
|
||||||
const typeMessage = this.showMessage(type, message);
|
|
||||||
|
|
||||||
//listener on banned receive message
|
|
||||||
if(typeMessage instanceof Banned) {
|
if(typeMessage instanceof Banned) {
|
||||||
for (const callback of this.receiveBannedMessageListener) {
|
this.receiveBannedMessageListener();
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(type: string, message: string) {
|
showMessage(type: string, message: string) {
|
||||||
@ -47,6 +37,7 @@ export class UserMessageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setReceiveBanListener(callback: Function){
|
setReceiveBanListener(callback: Function){
|
||||||
this.receiveBannedMessageListener.add(callback);
|
this.receiveBannedMessageListener = callback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const userMessageManager = new UserMessageManager()
|
34
front/src/Connexion/AdminMessagesService.ts
Normal file
34
front/src/Connexion/AdminMessagesService.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import {Subject} from "rxjs";
|
||||||
|
import {SendUserMessage} from "../Messages/generated/messages_pb";
|
||||||
|
|
||||||
|
export enum AdminMessageEventTypes {
|
||||||
|
admin = 'message',
|
||||||
|
audio = 'audio',
|
||||||
|
ban = 'ban',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AdminMessageEvent {
|
||||||
|
type: AdminMessageEventTypes,
|
||||||
|
text: string;
|
||||||
|
//todo add optional properties for other event types
|
||||||
|
}
|
||||||
|
|
||||||
|
//this class is designed to easily allow communication between the RoomConnection objects (that receive the message)
|
||||||
|
//and the various objects that may render the message on screen
|
||||||
|
class AdminMessagesService {
|
||||||
|
private _messageStream: Subject<AdminMessageEvent> = new Subject();
|
||||||
|
public messageStream = this._messageStream.asObservable();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.messageStream.subscribe((event) => console.log('message', event))
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendusermessage(message: SendUserMessage) {
|
||||||
|
this._messageStream.next({
|
||||||
|
type: message.getType() as unknown as AdminMessageEventTypes,
|
||||||
|
text: message.getMessage(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const adminMessagesService = new AdminMessagesService();
|
@ -42,6 +42,7 @@ import {
|
|||||||
WebRtcSignalReceivedMessageInterface,
|
WebRtcSignalReceivedMessageInterface,
|
||||||
} from "./ConnexionModels";
|
} from "./ConnexionModels";
|
||||||
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
||||||
|
import {adminMessagesService} from "./AdminMessagesService";
|
||||||
|
|
||||||
const manualPingDelay = 20000;
|
const manualPingDelay = 20000;
|
||||||
|
|
||||||
@ -140,8 +141,6 @@ export class RoomConnection implements RoomConnection {
|
|||||||
} else if (message.hasRoomjoinedmessage()) {
|
} else if (message.hasRoomjoinedmessage()) {
|
||||||
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
|
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
|
||||||
|
|
||||||
//const users: Array<MessageUserJoined> = roomJoinedMessage.getUserList().map(this.toMessageUserJoined.bind(this));
|
|
||||||
//const groups: Array<GroupCreatedUpdatedMessageInterface> = roomJoinedMessage.getGroupList().map(this.toGroupCreatedUpdatedMessage.bind(this));
|
|
||||||
const items: { [itemId: number] : unknown } = {};
|
const items: { [itemId: number] : unknown } = {};
|
||||||
for (const item of roomJoinedMessage.getItemList()) {
|
for (const item of roomJoinedMessage.getItemList()) {
|
||||||
items[item.getItemid()] = JSON.parse(item.getStatejson());
|
items[item.getItemid()] = JSON.parse(item.getStatejson());
|
||||||
@ -150,22 +149,12 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.userId = roomJoinedMessage.getCurrentuserid();
|
this.userId = roomJoinedMessage.getCurrentuserid();
|
||||||
this.tags = roomJoinedMessage.getTagList();
|
this.tags = roomJoinedMessage.getTagList();
|
||||||
|
|
||||||
//console.log('Dispatching CONNECT')
|
|
||||||
this.dispatch(EventMessage.CONNECT, {
|
this.dispatch(EventMessage.CONNECT, {
|
||||||
connection: this,
|
connection: this,
|
||||||
room: {
|
room: {
|
||||||
//users,
|
|
||||||
//groups,
|
|
||||||
items
|
items
|
||||||
} as RoomJoinedMessageInterface
|
} as RoomJoinedMessageInterface
|
||||||
});
|
});
|
||||||
|
|
||||||
/*console.log('Dispatching START_ROOM')
|
|
||||||
this.dispatch(EventMessage.START_ROOM, {
|
|
||||||
//users,
|
|
||||||
//groups,
|
|
||||||
items
|
|
||||||
});*/
|
|
||||||
} else if (message.hasErrormessage()) {
|
} else if (message.hasErrormessage()) {
|
||||||
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
|
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
|
||||||
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
||||||
@ -185,7 +174,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
} else if (message.hasSendjitsijwtmessage()) {
|
} else if (message.hasSendjitsijwtmessage()) {
|
||||||
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
||||||
} else if (message.hasSendusermessage()) {
|
} else if (message.hasSendusermessage()) {
|
||||||
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
|
adminMessagesService.onSendusermessage(message.getSendusermessage() as SendUserMessage);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown message received');
|
throw new Error('Unknown message received');
|
||||||
}
|
}
|
||||||
@ -539,12 +528,6 @@ export class RoomConnection implements RoomConnection {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public receiveUserMessage(callback: (type: string, message: string) => void) {
|
|
||||||
return this.onMessage(EventMessage.USER_MESSAGE, (message: SendUserMessage) => {
|
|
||||||
callback(message.getType(), message.getMessage());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public emitGlobalMessage(message: PlayGlobalMessageInterface){
|
public emitGlobalMessage(message: PlayGlobalMessageInterface){
|
||||||
const playGlobalMessage = new PlayGlobalMessage();
|
const playGlobalMessage = new PlayGlobalMessage();
|
||||||
playGlobalMessage.setId(message.id);
|
playGlobalMessage.setId(message.id);
|
||||||
|
@ -57,7 +57,7 @@ import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
|||||||
import {connectionManager} 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";
|
||||||
import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMessageManager";
|
import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMessageManager";
|
||||||
import {ResizableScene} from "../Login/ResizableScene";
|
import {ResizableScene} from "../Login/ResizableScene";
|
||||||
import {Room} from "../../Connexion/Room";
|
import {Room} from "../../Connexion/Room";
|
||||||
@ -72,7 +72,6 @@ import {TextureError} from "../../Exception/TextureError";
|
|||||||
import {addLoader} from "../Components/Loader";
|
import {addLoader} from "../Components/Loader";
|
||||||
import {ErrorSceneName} from "../Reconnecting/ErrorScene";
|
import {ErrorSceneName} from "../Reconnecting/ErrorScene";
|
||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
|
||||||
import DOMElement = Phaser.GameObjects.DOMElement;
|
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||||
import Tween = Phaser.Tweens.Tween;
|
import Tween = Phaser.Tweens.Tween;
|
||||||
|
|
||||||
@ -133,7 +132,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
public connection!: RoomConnection;
|
public connection!: RoomConnection;
|
||||||
private simplePeer!: SimplePeer;
|
private simplePeer!: SimplePeer;
|
||||||
private GlobalMessageManager!: GlobalMessageManager;
|
private GlobalMessageManager!: GlobalMessageManager;
|
||||||
private UserMessageManager!: UserMessageManager;
|
|
||||||
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
|
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
|
||||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||||
private connectionAnswerPromiseResolve!: (value?: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
private connectionAnswerPromiseResolve!: (value?: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
||||||
@ -540,8 +538,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
// When connection is performed, let's connect SimplePeer
|
// When connection is performed, let's connect SimplePeer
|
||||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
|
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
|
||||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||||
this.UserMessageManager = new UserMessageManager(this.connection);
|
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
||||||
this.UserMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
this.simplePeer.registerPeerConnectionListener({
|
this.simplePeer.registerPeerConnectionListener({
|
||||||
@ -687,7 +684,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
coWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsite();
|
||||||
}else{
|
}else{
|
||||||
const openWebsiteFunction = () => {
|
const openWebsiteFunction = () => {
|
||||||
coWebsiteManager.loadCoWebsite(newValue as string, allProps.get('openWebsitePolicy') as string | undefined);
|
coWebsiteManager.loadCoWebsite(newValue as string, this.MapUrlFile, allProps.get('openWebsitePolicy') as string | undefined);
|
||||||
layoutManager.removeActionButton('openWebsite', this.userInputManager);
|
layoutManager.removeActionButton('openWebsite', this.userInputManager);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class CoWebsiteManager {
|
|||||||
this.opened = iframeStates.opened;
|
this.opened = iframeStates.opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadCoWebsite(url: string, allowPolicy?: string): void {
|
public loadCoWebsite(url: string, base: string, allowPolicy?: string): void {
|
||||||
this.load();
|
this.load();
|
||||||
this.cowebsiteDiv.innerHTML = `<button class="close-btn" id="cowebsite-close">
|
this.cowebsiteDiv.innerHTML = `<button class="close-btn" id="cowebsite-close">
|
||||||
<img src="resources/logos/close.svg">
|
<img src="resources/logos/close.svg">
|
||||||
@ -55,7 +55,7 @@ class CoWebsiteManager {
|
|||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.id = 'cowebsite-iframe';
|
iframe.id = 'cowebsite-iframe';
|
||||||
iframe.src = url;
|
iframe.src = (new URL(url, base)).toString();
|
||||||
if (allowPolicy) {
|
if (allowPolicy) {
|
||||||
iframe.allow = allowPolicy;
|
iframe.allow = allowPolicy;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
set -x
|
set -x
|
||||||
set -o nounset errexit
|
set -o nounset errexit
|
||||||
template_file_index=dist/index.tmpl.html
|
template_file_index=dist/index.tmpl.html
|
||||||
generated_file_index=dist/index.html
|
generated_file_index=dist/index.tmpl.html.tmp
|
||||||
tmp_trackcodefile=/tmp/trackcode
|
tmp_trackcodefile=/tmp/trackcode
|
||||||
|
|
||||||
# To inject tracking code, you have two choices:
|
# To inject tracking code, you have two choices:
|
||||||
|
@ -39,7 +39,7 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin(
|
new HtmlWebpackPlugin(
|
||||||
{
|
{
|
||||||
template: './dist/index.tmpl.html',
|
template: './dist/index.tmpl.html.tmp',
|
||||||
minify: {
|
minify: {
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
keepClosingSlash: true,
|
keepClosingSlash: true,
|
||||||
|
@ -217,6 +217,7 @@ message ServerToClientMessage {
|
|||||||
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
||||||
SendUserMessage sendUserMessage = 12;
|
SendUserMessage sendUserMessage = 12;
|
||||||
BanUserMessage banUserMessage = 13;
|
BanUserMessage banUserMessage = 13;
|
||||||
|
AdminRoomMessage adminRoomMessage = 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +352,12 @@ message AdminMessage {
|
|||||||
string roomId = 3;
|
string roomId = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A message sent by an administrator to everyone in a specific room
|
||||||
|
message AdminRoomMessage {
|
||||||
|
string message = 1;
|
||||||
|
string roomId = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// A message sent by an administrator to absolutely everybody
|
// A message sent by an administrator to absolutely everybody
|
||||||
message AdminGlobalMessage {
|
message AdminGlobalMessage {
|
||||||
string message = 1;
|
string message = 1;
|
||||||
@ -372,4 +379,5 @@ service RoomManager {
|
|||||||
rpc sendAdminMessage(AdminMessage) returns (EmptyMessage);
|
rpc sendAdminMessage(AdminMessage) returns (EmptyMessage);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import {MapController} from "./Controller/MapController";
|
|||||||
import {PrometheusController} from "./Controller/PrometheusController";
|
import {PrometheusController} from "./Controller/PrometheusController";
|
||||||
import {DebugController} from "./Controller/DebugController";
|
import {DebugController} from "./Controller/DebugController";
|
||||||
import {App as uwsApp} from "./Server/sifrr.server";
|
import {App as uwsApp} from "./Server/sifrr.server";
|
||||||
|
import {AdminController} from "./Controller/AdminController";
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
public app: uwsApp;
|
public app: uwsApp;
|
||||||
@ -13,6 +14,7 @@ class App {
|
|||||||
public mapController: MapController;
|
public mapController: MapController;
|
||||||
public prometheusController: PrometheusController;
|
public prometheusController: PrometheusController;
|
||||||
private debugController: DebugController;
|
private debugController: DebugController;
|
||||||
|
private adminController: AdminController;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = new uwsApp();
|
this.app = new uwsApp();
|
||||||
@ -23,6 +25,7 @@ class App {
|
|||||||
this.mapController = new MapController(this.app);
|
this.mapController = new MapController(this.app);
|
||||||
this.prometheusController = new PrometheusController(this.app);
|
this.prometheusController = new PrometheusController(this.app);
|
||||||
this.debugController = new DebugController(this.app);
|
this.debugController = new DebugController(this.app);
|
||||||
|
this.adminController = new AdminController(this.app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
73
pusher/src/Controller/AdminController.ts
Normal file
73
pusher/src/Controller/AdminController.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import {BaseController} from "./BaseController";
|
||||||
|
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
|
||||||
|
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
|
||||||
|
import {apiClientRepository} from "../Services/ApiClientRepository";
|
||||||
|
import {AdminRoomMessage} from "../Messages/generated/messages_pb";
|
||||||
|
|
||||||
|
|
||||||
|
export class AdminController extends BaseController{
|
||||||
|
|
||||||
|
constructor(private App : TemplatedApp) {
|
||||||
|
super();
|
||||||
|
this.App = App;
|
||||||
|
this.receiveGlobalMessagePrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveGlobalMessagePrompt() {
|
||||||
|
this.App.options("/message", (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
this.addCorsHeaders(res);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
this.App.post("/message", async (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
|
||||||
|
res.onAborted(() => {
|
||||||
|
console.warn('/message request was aborted');
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const token = req.getHeader('admin-token');
|
||||||
|
const body = await res.json();
|
||||||
|
|
||||||
|
if (token !== ADMIN_API_TOKEN) {
|
||||||
|
console.error('Admin access refused for token: '+token)
|
||||||
|
res.writeStatus("401 Unauthorized").end('Incorrect token');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof body.text !== 'string') {
|
||||||
|
throw 'Incorrect text parameter'
|
||||||
|
}
|
||||||
|
if (!body.targets || typeof body.targets !== 'object') {
|
||||||
|
throw 'Incorrect targets parameter'
|
||||||
|
}
|
||||||
|
const text: string = body.text;
|
||||||
|
const targets: string[] = body.targets;
|
||||||
|
|
||||||
|
await Promise.all(targets.map((roomId) => {
|
||||||
|
return apiClientRepository.getClient(roomId).then((roomClient) =>{
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
const roomMessage = new AdminRoomMessage();
|
||||||
|
roomMessage.setMessage(text);
|
||||||
|
roomMessage.setRoomid(roomId);
|
||||||
|
|
||||||
|
roomClient.sendAdminMessageToRoom(roomMessage, (err) => {
|
||||||
|
err ? rej(err) : res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
this.errorToResponse(err, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.writeStatus("200");
|
||||||
|
this.addCorsHeaders(res);
|
||||||
|
res.end('ok');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
worldSlug,
|
worldSlug,
|
||||||
roomSlug,
|
roomSlug,
|
||||||
mapUrlStart,
|
mapUrlStart,
|
||||||
|
organizationMemberToken,
|
||||||
textures
|
textures
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -21,10 +21,10 @@ import {jwtTokenManager} from "../Services/JWTTokenManager";
|
|||||||
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
||||||
import {SocketManager, socketManager} from "../Services/SocketManager";
|
import {SocketManager, socketManager} from "../Services/SocketManager";
|
||||||
import {emitInBatch} from "../Services/IoSocketHelpers";
|
import {emitInBatch} from "../Services/IoSocketHelpers";
|
||||||
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
|
||||||
import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
|
||||||
import {Zone} from "_Model/Zone";
|
import {Zone} from "_Model/Zone";
|
||||||
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
|
import {v4} from "uuid";
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
private nextUserId: number = 1;
|
private nextUserId: number = 1;
|
||||||
@ -64,22 +64,6 @@ export class IoSocketController {
|
|||||||
ws.disconnecting = false;
|
ws.disconnecting = false;
|
||||||
|
|
||||||
socketManager.handleAdminRoom(ws as ExAdminSocketInterface, ws.roomId as string);
|
socketManager.handleAdminRoom(ws as ExAdminSocketInterface, ws.roomId as string);
|
||||||
|
|
||||||
/*ws.send('Data:'+JSON.stringify(socketManager.getAdminSocketDataFor(ws.roomId as string)));
|
|
||||||
ws.clientJoinCallback = (clientUUid: string, roomId: string) => {
|
|
||||||
const wsroomId = ws.roomId as string;
|
|
||||||
if(wsroomId === roomId) {
|
|
||||||
ws.send('MemberJoin:'+clientUUid+';'+roomId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ws.clientLeaveCallback = (clientUUid: string, roomId: string) => {
|
|
||||||
const wsroomId = ws.roomId as string;
|
|
||||||
if(wsroomId === roomId) {
|
|
||||||
ws.send('MemberLeave:'+clientUUid+';'+roomId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
clientEventsEmitter.registerToClientJoin(ws.clientJoinCallback);
|
|
||||||
clientEventsEmitter.registerToClientLeave(ws.clientLeaveCallback);*/
|
|
||||||
},
|
},
|
||||||
message: (ws, arrayBuffer, isBinary): void => {
|
message: (ws, arrayBuffer, isBinary): void => {
|
||||||
try {
|
try {
|
||||||
@ -106,7 +90,6 @@ export class IoSocketController {
|
|||||||
const Client = (ws as ExAdminSocketInterface);
|
const Client = (ws as ExAdminSocketInterface);
|
||||||
try {
|
try {
|
||||||
Client.disconnecting = true;
|
Client.disconnecting = true;
|
||||||
//leave room
|
|
||||||
socketManager.leaveAdminRoom(Client);
|
socketManager.leaveAdminRoom(Client);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('An error occurred on admin "disconnect"');
|
console.error('An error occurred on admin "disconnect"');
|
||||||
@ -181,14 +164,31 @@ export class IoSocketController {
|
|||||||
}*/
|
}*/
|
||||||
if (ADMIN_API_URL) {
|
if (ADMIN_API_URL) {
|
||||||
try {
|
try {
|
||||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
let userData : FetchMemberDataByUuidResponse = {
|
||||||
//console.log('USERDATA', userData)
|
uuid: v4(),
|
||||||
|
tags: [],
|
||||||
|
textures: [],
|
||||||
|
messages: [],
|
||||||
|
anonymous: true
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||||
|
}catch (err){
|
||||||
|
if (err?.response?.status == 404) {
|
||||||
|
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
||||||
|
console.warn('Cannot find user with uuid "'+userUuid+'". Performing an anonymous login instead.');
|
||||||
|
}else{
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
memberTags = userData.tags;
|
memberTags = userData.tags;
|
||||||
memberTextures = userData.textures;
|
memberTextures = userData.textures;
|
||||||
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && (userData.anonymous === true || !room.canAccess(memberTags))) {
|
||||||
throw new Error('No correct tags')
|
throw new Error('No correct tags')
|
||||||
}
|
}
|
||||||
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.MEMBERS_ONLY_POLICY && userData.anonymous === true) {
|
||||||
|
throw new Error('No correct member')
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import {v4} from "uuid";
|
|
||||||
|
|
||||||
export interface AdminApiData {
|
export interface AdminApiData {
|
||||||
organizationSlug: string
|
organizationSlug: string
|
||||||
@ -31,6 +30,7 @@ export interface FetchMemberDataByUuidResponse {
|
|||||||
tags: string[];
|
tags: string[];
|
||||||
textures: CharacterTexture[];
|
textures: CharacterTexture[];
|
||||||
messages: unknown[];
|
messages: unknown[];
|
||||||
|
anonymous?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdminApi {
|
class AdminApi {
|
||||||
@ -62,25 +62,10 @@ class AdminApi {
|
|||||||
if (!ADMIN_API_URL) {
|
if (!ADMIN_API_URL) {
|
||||||
return Promise.reject('No admin backoffice set!');
|
return Promise.reject('No admin backoffice set!');
|
||||||
}
|
}
|
||||||
try {
|
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
)
|
||||||
)
|
return res.data;
|
||||||
return res.data;
|
|
||||||
} catch (e) {
|
|
||||||
if (e?.response?.status == 404) {
|
|
||||||
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
|
||||||
console.warn('Cannot find user with uuid "'+uuid+'". Performing an anonymous login instead.');
|
|
||||||
return {
|
|
||||||
uuid: v4(),
|
|
||||||
tags: [],
|
|
||||||
textures: [],
|
|
||||||
messages: [],
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
||||||
|
@ -13,8 +13,7 @@ const debug = Debug('apiClientRespository');
|
|||||||
class ApiClientRepository {
|
class ApiClientRepository {
|
||||||
private roomManagerClients: RoomManagerClient[] = [];
|
private roomManagerClients: RoomManagerClient[] = [];
|
||||||
|
|
||||||
public constructor(private apiUrls: string[]) {
|
public constructor(private apiUrls: string[]) {}
|
||||||
}
|
|
||||||
|
|
||||||
public async getClient(roomId: string): Promise<RoomManagerClient> {
|
public async getClient(roomId: string): Promise<RoomManagerClient> {
|
||||||
const array = new Uint32Array(crypto.createHash('md5').update(roomId).digest());
|
const array = new Uint32Array(crypto.createHash('md5').update(roomId).digest());
|
||||||
|
@ -494,10 +494,6 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
return this.Worlds;
|
return this.Worlds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
*/
|
|
||||||
searchClientByUuid(uuid: string): ExSocketInterface | null {
|
searchClientByUuid(uuid: string): ExSocketInterface | null {
|
||||||
for(const socket of this.sockets.values()){
|
for(const socket of this.sockets.values()){
|
||||||
if(socket.userUuid === uuid){
|
if(socket.userUuid === uuid){
|
||||||
|
Loading…
Reference in New Issue
Block a user