Merge branch 'develop' of github.com:thecodingmachine/workadventure into scripting_api_room_metadata
This commit is contained in:
commit
5c7ea7b258
66 changed files with 1296 additions and 967 deletions
|
@ -39,9 +39,7 @@ export class AuthenticateController extends BaseController {
|
|||
if (typeof organizationMemberToken != "string") throw new Error("No organization token");
|
||||
const data = await adminApi.fetchMemberDataByToken(organizationMemberToken);
|
||||
const userUuid = data.userUuid;
|
||||
const organizationSlug = data.organizationSlug;
|
||||
const worldSlug = data.worldSlug;
|
||||
const roomSlug = data.roomSlug;
|
||||
const roomUrl = data.roomUrl;
|
||||
const mapUrlStart = data.mapUrlStart;
|
||||
const textures = data.textures;
|
||||
|
||||
|
@ -52,9 +50,7 @@ export class AuthenticateController extends BaseController {
|
|||
JSON.stringify({
|
||||
authToken,
|
||||
userUuid,
|
||||
organizationSlug,
|
||||
worldSlug,
|
||||
roomSlug,
|
||||
roomUrl,
|
||||
mapUrlStart,
|
||||
organizationMemberToken,
|
||||
textures,
|
||||
|
|
|
@ -16,19 +16,21 @@ import {
|
|||
SendUserMessage,
|
||||
ServerToClientMessage,
|
||||
CompanionMessage,
|
||||
EmotePromptMessage, VariableMessage,
|
||||
EmotePromptMessage,
|
||||
VariableMessage,
|
||||
} from "../Messages/generated/messages_pb";
|
||||
import { UserMovesMessage } from "../Messages/generated/messages_pb";
|
||||
import { TemplatedApp } from "uWebSockets.js";
|
||||
import { parse } from "query-string";
|
||||
import { jwtTokenManager } from "../Services/JWTTokenManager";
|
||||
import { adminApi, CharacterTexture, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
||||
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
||||
import { SocketManager, socketManager } from "../Services/SocketManager";
|
||||
import { emitInBatch } from "../Services/IoSocketHelpers";
|
||||
import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
||||
import { Zone } from "_Model/Zone";
|
||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||
import { v4 } from "uuid";
|
||||
import { CharacterTexture } from "../Services/AdminApi/CharacterTexture";
|
||||
|
||||
export class IoSocketController {
|
||||
private nextUserId: number = 1;
|
||||
|
@ -221,14 +223,12 @@ export class IoSocketController {
|
|||
memberVisitCardUrl = userData.visitCardUrl;
|
||||
memberTextures = userData.textures;
|
||||
if (
|
||||
!room.public &&
|
||||
room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY &&
|
||||
(userData.anonymous === true || !room.canAccess(memberTags))
|
||||
) {
|
||||
throw new Error("Insufficient privileges to access this room");
|
||||
}
|
||||
if (
|
||||
!room.public &&
|
||||
room.policyType === GameRoomPolicyTypes.MEMBERS_ONLY_POLICY &&
|
||||
userData.anonymous === true
|
||||
) {
|
||||
|
|
|
@ -2,6 +2,9 @@ import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
|
|||
import { BaseController } from "./BaseController";
|
||||
import { parse } from "query-string";
|
||||
import { adminApi } from "../Services/AdminApi";
|
||||
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
||||
import { MapDetailsData } from "../Services/AdminApi/MapDetailsData";
|
||||
|
||||
export class MapController extends BaseController {
|
||||
constructor(private App: TemplatedApp) {
|
||||
|
@ -25,35 +28,46 @@ export class MapController extends BaseController {
|
|||
|
||||
const query = parse(req.getQuery());
|
||||
|
||||
if (typeof query.organizationSlug !== "string") {
|
||||
console.error("Expected organizationSlug parameter");
|
||||
if (typeof query.playUri !== "string") {
|
||||
console.error("Expected playUri parameter in /map endpoint");
|
||||
res.writeStatus("400 Bad request");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected organizationSlug parameter");
|
||||
res.end("Expected playUri parameter");
|
||||
return;
|
||||
}
|
||||
if (typeof query.worldSlug !== "string") {
|
||||
console.error("Expected worldSlug parameter");
|
||||
res.writeStatus("400 Bad request");
|
||||
|
||||
// If no admin URL is set, let's react on '/_/[instance]/[map url]' URLs
|
||||
if (!ADMIN_API_URL) {
|
||||
const roomUrl = new URL(query.playUri);
|
||||
|
||||
const match = /\/_\/[^/]+\/(.+)/.exec(roomUrl.pathname);
|
||||
if (!match) {
|
||||
res.writeStatus("404 Not Found");
|
||||
this.addCorsHeaders(res);
|
||||
res.end(JSON.stringify({}));
|
||||
return;
|
||||
}
|
||||
|
||||
const mapUrl = roomUrl.protocol + "//" + match[1];
|
||||
|
||||
res.writeStatus("200 OK");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected worldSlug parameter");
|
||||
return;
|
||||
}
|
||||
if (typeof query.roomSlug !== "string" && query.roomSlug !== undefined) {
|
||||
console.error("Expected only one roomSlug parameter");
|
||||
res.writeStatus("400 Bad request");
|
||||
this.addCorsHeaders(res);
|
||||
res.end("Expected only one roomSlug parameter");
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
mapUrl,
|
||||
policy_type: GameRoomPolicyTypes.ANONYMOUS_POLICY,
|
||||
roomSlug: "", // Deprecated
|
||||
tags: [],
|
||||
textures: [],
|
||||
} as MapDetailsData)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const mapDetails = await adminApi.fetchMapDetails(
|
||||
query.organizationSlug as string,
|
||||
query.worldSlug as string,
|
||||
query.roomSlug as string | undefined
|
||||
);
|
||||
const mapDetails = await adminApi.fetchMapDetails(query.playUri as string);
|
||||
|
||||
res.writeStatus("200 OK");
|
||||
this.addCorsHeaders(res);
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
import { ExSocketInterface } from "_Model/Websocket/ExSocketInterface";
|
||||
import { PositionDispatcher } from "./PositionDispatcher";
|
||||
import { ViewportInterface } from "_Model/Websocket/ViewportMessage";
|
||||
import { extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous } from "./RoomIdentifier";
|
||||
import { arrayIntersect } from "../Services/ArrayHelper";
|
||||
import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone";
|
||||
import {apiClientRepository} from "../Services/ApiClientRepository";
|
||||
import { GroupDescriptor, UserDescriptor, ZoneEventListener } from "_Model/Zone";
|
||||
import { apiClientRepository } from "../Services/ApiClientRepository";
|
||||
import {
|
||||
BatchToPusherMessage, BatchToPusherRoomMessage, EmoteEventMessage, GroupLeftZoneMessage,
|
||||
GroupUpdateZoneMessage, RoomMessage, SubMessage,
|
||||
UserJoinedZoneMessage, UserLeftZoneMessage, UserMovedMessage, VariableMessage,
|
||||
ZoneMessage
|
||||
BatchToPusherMessage,
|
||||
BatchToPusherRoomMessage,
|
||||
EmoteEventMessage,
|
||||
GroupLeftZoneMessage,
|
||||
GroupUpdateZoneMessage,
|
||||
RoomMessage,
|
||||
SubMessage,
|
||||
UserJoinedZoneMessage,
|
||||
UserLeftZoneMessage,
|
||||
UserMovedMessage,
|
||||
VariableMessage,
|
||||
ZoneMessage,
|
||||
} from "../Messages/generated/messages_pb";
|
||||
import Debug from "debug";
|
||||
import {ClientReadableStream} from "grpc";
|
||||
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
||||
import { ClientReadableStream } from "grpc";
|
||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||
|
||||
const debug = Debug("room");
|
||||
|
||||
|
@ -25,20 +32,15 @@ export enum GameRoomPolicyTypes {
|
|||
|
||||
export class PusherRoom {
|
||||
private readonly positionNotifier: PositionDispatcher;
|
||||
public readonly public: boolean;
|
||||
public tags: string[];
|
||||
public policyType: GameRoomPolicyTypes;
|
||||
public readonly roomSlug: string;
|
||||
public readonly worldSlug: string = "";
|
||||
public readonly organizationSlug: string = "";
|
||||
private versionNumber: number = 1;
|
||||
private backConnection!: ClientReadableStream<BatchToPusherRoomMessage>;
|
||||
private isClosing: boolean = false;
|
||||
private listeners: Set<ExSocketInterface> = new Set<ExSocketInterface>();
|
||||
public readonly variables = new Map<string, string>();
|
||||
|
||||
constructor(public readonly roomId: string, private socketListener: ZoneEventListener) {
|
||||
this.public = isRoomAnonymous(roomId);
|
||||
constructor(public readonly roomUrl: string, private socketListener: ZoneEventListener) {
|
||||
this.tags = [];
|
||||
this.policyType = GameRoomPolicyTypes.ANONYMOUS_POLICY;
|
||||
|
||||
|
@ -52,7 +54,7 @@ export class PusherRoom {
|
|||
}
|
||||
|
||||
// A zone is 10 sprites wide.
|
||||
this.positionNotifier = new PositionDispatcher(this.roomId, 320, 320, this.socketListener);
|
||||
this.positionNotifier = new PositionDispatcher(this.roomUrl, 320, 320, this.socketListener);
|
||||
}
|
||||
|
||||
public setViewport(socket: ExSocketInterface, viewport: ViewportInterface): void {
|
||||
|
@ -121,7 +123,7 @@ export class PusherRoom {
|
|||
// Let's close all connections linked to that room
|
||||
for (const listener of this.listeners) {
|
||||
listener.disconnecting = true;
|
||||
listener.end(1011, "Connection error between pusher and back server")
|
||||
listener.end(1011, "Connection error between pusher and back server");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -132,7 +134,7 @@ export class PusherRoom {
|
|||
// Let's close all connections linked to that room
|
||||
for (const listener of this.listeners) {
|
||||
listener.disconnecting = true;
|
||||
listener.end(1011, "Connection closed between pusher and back server")
|
||||
listener.end(1011, "Connection closed between pusher and back server");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
//helper functions to parse room IDs
|
||||
|
||||
export const isRoomAnonymous = (roomID: string): boolean => {
|
||||
if (roomID.startsWith("_/")) {
|
||||
return true;
|
||||
} else if (roomID.startsWith("@/")) {
|
||||
return false;
|
||||
} else {
|
||||
throw new Error("Incorrect room ID: " + roomID);
|
||||
}
|
||||
};
|
||||
|
||||
export const extractRoomSlugPublicRoomId = (roomId: string): string => {
|
||||
const idParts = roomId.split("/");
|
||||
if (idParts.length < 3) throw new Error("Incorrect roomId: " + roomId);
|
||||
return idParts.slice(2).join("/");
|
||||
};
|
||||
export interface extractDataFromPrivateRoomIdResponse {
|
||||
organizationSlug: string;
|
||||
worldSlug: string;
|
||||
roomSlug: string;
|
||||
}
|
||||
export const extractDataFromPrivateRoomId = (roomId: string): extractDataFromPrivateRoomIdResponse => {
|
||||
const idParts = roomId.split("/");
|
||||
if (idParts.length < 4) throw new Error("Incorrect roomId: " + roomId);
|
||||
const organizationSlug = idParts[1];
|
||||
const worldSlug = idParts[2];
|
||||
const roomSlug = idParts[3];
|
||||
return { organizationSlug, worldSlug, roomSlug };
|
||||
};
|
|
@ -10,7 +10,6 @@ import {
|
|||
SubMessage,
|
||||
} from "../../Messages/generated/messages_pb";
|
||||
import { WebSocket } from "uWebSockets.js";
|
||||
import { CharacterTexture } from "../../Services/AdminApi";
|
||||
import { ClientDuplexStream } from "grpc";
|
||||
import { Zone } from "_Model/Zone";
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ import {
|
|||
SubMessage,
|
||||
} from "../../Messages/generated/messages_pb";
|
||||
import { WebSocket } from "uWebSockets.js";
|
||||
import { CharacterTexture } from "../../Services/AdminApi";
|
||||
import { ClientDuplexStream } from "grpc";
|
||||
import { Zone } from "_Model/Zone";
|
||||
import { CharacterTexture } from "../../Services/AdminApi/CharacterTexture";
|
||||
|
||||
export type BackConnection = ClientDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||
import Axios from "axios";
|
||||
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
||||
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
||||
import { MapDetailsData } from "./AdminApi/MapDetailsData";
|
||||
import { RoomRedirect } from "./AdminApi/RoomRedirect";
|
||||
|
||||
export interface AdminApiData {
|
||||
organizationSlug: string;
|
||||
worldSlug: string;
|
||||
roomSlug: string;
|
||||
roomUrl: string;
|
||||
mapUrlStart: string;
|
||||
tags: string[];
|
||||
policy_type: number;
|
||||
|
@ -14,25 +15,11 @@ export interface AdminApiData {
|
|||
textures: CharacterTexture[];
|
||||
}
|
||||
|
||||
export interface MapDetailsData {
|
||||
roomSlug: string;
|
||||
mapUrl: string;
|
||||
policy_type: GameRoomPolicyTypes;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export interface AdminBannedData {
|
||||
is_banned: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface CharacterTexture {
|
||||
id: number;
|
||||
level: number;
|
||||
url: string;
|
||||
rights: string;
|
||||
}
|
||||
|
||||
export interface FetchMemberDataByUuidResponse {
|
||||
uuid: string;
|
||||
tags: string[];
|
||||
|
@ -43,24 +30,15 @@ export interface FetchMemberDataByUuidResponse {
|
|||
}
|
||||
|
||||
class AdminApi {
|
||||
async fetchMapDetails(
|
||||
organizationSlug: string,
|
||||
worldSlug: string,
|
||||
roomSlug: string | undefined
|
||||
): Promise<MapDetailsData> {
|
||||
async fetchMapDetails(playUri: string): Promise<MapDetailsData | RoomRedirect> {
|
||||
if (!ADMIN_API_URL) {
|
||||
return Promise.reject(new Error("No admin backoffice set!"));
|
||||
}
|
||||
|
||||
const params: { organizationSlug: string; worldSlug: string; roomSlug?: string } = {
|
||||
organizationSlug,
|
||||
worldSlug,
|
||||
const params: { playUri: string } = {
|
||||
playUri,
|
||||
};
|
||||
|
||||
if (roomSlug) {
|
||||
params.roomSlug = roomSlug;
|
||||
}
|
||||
|
||||
const res = await Axios.get(ADMIN_API_URL + "/api/map", {
|
||||
headers: { Authorization: `${ADMIN_API_TOKEN}` },
|
||||
params,
|
||||
|
@ -121,26 +99,20 @@ class AdminApi {
|
|||
);
|
||||
}
|
||||
|
||||
async verifyBanUser(
|
||||
organizationMemberToken: string,
|
||||
ipAddress: string,
|
||||
organization: string,
|
||||
world: string
|
||||
): Promise<AdminBannedData> {
|
||||
async verifyBanUser(userUuid: string, ipAddress: string, roomUrl: string): Promise<AdminBannedData> {
|
||||
if (!ADMIN_API_URL) {
|
||||
return Promise.reject(new Error("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.
|
||||
return Axios.get(
|
||||
ADMIN_API_URL +
|
||||
"/api/check-moderate-user/" +
|
||||
organization +
|
||||
"/" +
|
||||
world +
|
||||
"/api/ban" +
|
||||
"?ipAddress=" +
|
||||
ipAddress +
|
||||
encodeURIComponent(ipAddress) +
|
||||
"&token=" +
|
||||
organizationMemberToken,
|
||||
encodeURIComponent(userUuid) +
|
||||
"&roomUrl=" +
|
||||
encodeURIComponent(roomUrl),
|
||||
{ headers: { Authorization: `${ADMIN_API_TOKEN}` } }
|
||||
).then((data) => {
|
||||
return data.data;
|
||||
|
|
11
pusher/src/Services/AdminApi/CharacterTexture.ts
Normal file
11
pusher/src/Services/AdminApi/CharacterTexture.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isCharacterTexture = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
level: tg.isNumber,
|
||||
url: tg.isString,
|
||||
rights: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export type CharacterTexture = tg.GuardedType<typeof isCharacterTexture>;
|
20
pusher/src/Services/AdminApi/MapDetailsData.ts
Normal file
20
pusher/src/Services/AdminApi/MapDetailsData.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import * as tg from "generic-type-guard";
|
||||
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
||||
import { isCharacterTexture } from "./CharacterTexture";
|
||||
import { isAny, isNumber } from "generic-type-guard";
|
||||
|
||||
/*const isNumericEnum =
|
||||
<T extends { [n: number]: string }>(vs: T) =>
|
||||
(v: any): v is T =>
|
||||
typeof v === "number" && v in vs;*/
|
||||
|
||||
export const isMapDetailsData = new tg.IsInterface()
|
||||
.withProperties({
|
||||
roomSlug: tg.isOptional(tg.isString), // deprecated
|
||||
mapUrl: tg.isString,
|
||||
policy_type: isNumber, //isNumericEnum(GameRoomPolicyTypes),
|
||||
tags: tg.isArray(tg.isString),
|
||||
textures: tg.isArray(isCharacterTexture),
|
||||
})
|
||||
.get();
|
||||
export type MapDetailsData = tg.GuardedType<typeof isMapDetailsData>;
|
8
pusher/src/Services/AdminApi/RoomRedirect.ts
Normal file
8
pusher/src/Services/AdminApi/RoomRedirect.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isRoomRedirect = new tg.IsInterface()
|
||||
.withProperties({
|
||||
redirectUrl: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export type RoomRedirect = tg.GuardedType<typeof isRoomRedirect>;
|
|
@ -9,7 +9,7 @@ class JWTTokenManager {
|
|||
return Jwt.sign({ userUuid: userUuid }, SECRET_KEY, { expiresIn: "200d" }); //todo: add a mechanic to refresh or recreate token
|
||||
}
|
||||
|
||||
public async getUserUuidFromToken(token: unknown, ipAddress?: string, room?: string): Promise<string> {
|
||||
public async getUserUuidFromToken(token: unknown, ipAddress?: string, roomUrl?: string): Promise<string> {
|
||||
if (!token) {
|
||||
throw new Error("An authentication error happened, a user tried to connect without a token.");
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ class JWTTokenManager {
|
|||
if (ADMIN_API_URL) {
|
||||
//verify user in admin
|
||||
let promise = new Promise((resolve) => resolve());
|
||||
if (ipAddress && room) {
|
||||
promise = this.verifyBanUser(tokenInterface.userUuid, ipAddress, room);
|
||||
if (ipAddress && roomUrl) {
|
||||
promise = this.verifyBanUser(tokenInterface.userUuid, ipAddress, roomUrl);
|
||||
}
|
||||
promise
|
||||
.then(() => {
|
||||
|
@ -79,19 +79,9 @@ class JWTTokenManager {
|
|||
});
|
||||
}
|
||||
|
||||
private verifyBanUser(userUuid: string, ipAddress: string, room: string): Promise<AdminBannedData> {
|
||||
const parts = room.split("/");
|
||||
if (parts.length < 3 || parts[0] !== "@") {
|
||||
return Promise.resolve({
|
||||
is_banned: false,
|
||||
message: "",
|
||||
});
|
||||
}
|
||||
|
||||
const organization = parts[1];
|
||||
const world = parts[2];
|
||||
private verifyBanUser(userUuid: string, ipAddress: string, roomUrl: string): Promise<AdminBannedData> {
|
||||
return adminApi
|
||||
.verifyBanUser(userUuid, ipAddress, organization, world)
|
||||
.verifyBanUser(userUuid, ipAddress, roomUrl)
|
||||
.then((data: AdminBannedData) => {
|
||||
if (data && data.is_banned) {
|
||||
throw new Error("User was banned");
|
||||
|
|
|
@ -33,8 +33,8 @@ import {
|
|||
VariableMessage,
|
||||
} from "../Messages/generated/messages_pb";
|
||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||
import { JITSI_ISS, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
||||
import { adminApi, CharacterTexture } from "./AdminApi";
|
||||
import { ADMIN_API_URL, JITSI_ISS, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
||||
import { adminApi } from "./AdminApi";
|
||||
import { emitInBatch } from "./IoSocketHelpers";
|
||||
import Jwt from "jsonwebtoken";
|
||||
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
||||
|
@ -45,6 +45,8 @@ import { GroupDescriptor, UserDescriptor, ZoneEventListener } from "_Model/Zone"
|
|||
import Debug from "debug";
|
||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||
import { WebSocket } from "uWebSockets.js";
|
||||
import { isRoomRedirect } from "./AdminApi/RoomRedirect";
|
||||
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
||||
|
||||
const debug = Debug("socket");
|
||||
|
||||
|
@ -370,24 +372,30 @@ export class SocketManager implements ZoneEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
async getOrCreateRoom(roomId: string): Promise<PusherRoom> {
|
||||
async getOrCreateRoom(roomUrl: string): Promise<PusherRoom> {
|
||||
//check and create new world for a room
|
||||
let world = this.rooms.get(roomId);
|
||||
if (world === undefined) {
|
||||
world = new PusherRoom(roomId, this);
|
||||
if (!world.public) {
|
||||
await this.updateRoomWithAdminData(world);
|
||||
let room = this.rooms.get(roomUrl);
|
||||
if (room === undefined) {
|
||||
room = new PusherRoom(roomUrl, this);
|
||||
if (ADMIN_API_URL) {
|
||||
await this.updateRoomWithAdminData(room);
|
||||
}
|
||||
await world.init();
|
||||
this.rooms.set(roomId, world);
|
||||
this.rooms.set(roomUrl, room);
|
||||
}
|
||||
return world;
|
||||
return room;
|
||||
}
|
||||
|
||||
public async updateRoomWithAdminData(world: PusherRoom): Promise<void> {
|
||||
const data = await adminApi.fetchMapDetails(world.organizationSlug, world.worldSlug, world.roomSlug);
|
||||
world.tags = data.tags;
|
||||
world.policyType = Number(data.policy_type);
|
||||
public async updateRoomWithAdminData(room: PusherRoom): Promise<void> {
|
||||
const data = await adminApi.fetchMapDetails(room.roomUrl);
|
||||
|
||||
if (isRoomRedirect(data)) {
|
||||
// TODO: if the updated room data is actually a redirect, we need to take everybody on the map
|
||||
// and redirect everybody to the new location (so we need to close the connection for everybody)
|
||||
} else {
|
||||
room.tags = data.tags;
|
||||
room.policyType = Number(data.policy_type);
|
||||
}
|
||||
}
|
||||
|
||||
emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) {
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "../src/Model/RoomIdentifier";
|
||||
|
||||
describe("RoomIdentifier", () => {
|
||||
it("should flag public id as anonymous", () => {
|
||||
expect(isRoomAnonymous('_/global/test')).toBe(true);
|
||||
});
|
||||
it("should flag public id as not anonymous", () => {
|
||||
expect(isRoomAnonymous('@/afup/afup2020/1floor')).toBe(false);
|
||||
});
|
||||
it("should extract roomSlug from public ID", () => {
|
||||
expect(extractRoomSlugPublicRoomId('_/global/npeguin/test.json')).toBe('npeguin/test.json');
|
||||
});
|
||||
it("should extract correct from private ID", () => {
|
||||
const {organizationSlug, worldSlug, roomSlug} = extractDataFromPrivateRoomId('@/afup/afup2020/1floor');
|
||||
expect(organizationSlug).toBe('afup');
|
||||
expect(worldSlug).toBe('afup2020');
|
||||
expect(roomSlug).toBe('1floor');
|
||||
});
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue