Changes the prefix added in front of the jitsiRoomName
Previously, the prefix was computed using the org/world (in SAAS) or the instance part of public URLs. Neither was guaranteeing the Jitsi Room would be unique accross rooms. The new system computes a hash of the room URL and prepends it to the jitsi room name. BREAKING CHANGE: this means the URL of the Jitsi room will change for all maps. Users having bookmarked the Jitsi room (for instance in the Jitsi mobile app) will need to update their bookmarks.
This commit is contained in:
parent
184aeb354a
commit
b89997c9f1
@ -562,14 +562,13 @@ export class GameRoom {
|
||||
if (!ADMIN_API_URL) {
|
||||
const roomUrlObj = new URL(roomUrl);
|
||||
|
||||
const match = /\/_\/([^/]+)\/(.+)/.exec(roomUrlObj.pathname);
|
||||
const match = /\/_\/[^/]+\/(.+)/.exec(roomUrlObj.pathname);
|
||||
if (!match) {
|
||||
console.error("Unexpected room URL", roomUrl);
|
||||
throw new Error('Unexpected room URL "' + roomUrl + '"');
|
||||
}
|
||||
|
||||
const instance = match[1];
|
||||
const mapUrl = roomUrlObj.protocol + "//" + match[2];
|
||||
const mapUrl = roomUrlObj.protocol + "//" + match[1];
|
||||
|
||||
return {
|
||||
mapUrl,
|
||||
@ -579,7 +578,6 @@ export class GameRoom {
|
||||
roomSlug: null,
|
||||
contactPage: null,
|
||||
group: null,
|
||||
instance,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@ export class Room {
|
||||
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
|
||||
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
||||
private _mapUrl: string | undefined;
|
||||
private _instance: string | undefined;
|
||||
private readonly _search: URLSearchParams;
|
||||
private _contactPage: string | undefined;
|
||||
private _group: string | null = null;
|
||||
@ -121,7 +120,6 @@ export class Room {
|
||||
this._canReport = data.canReport ?? false;
|
||||
this._loadingLogo = data.loadingLogo ?? undefined;
|
||||
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
|
||||
this._instance = data.instance;
|
||||
return new MapDetail(data.mapUrl);
|
||||
} else {
|
||||
console.log(data);
|
||||
@ -200,13 +198,6 @@ export class Room {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
get instance(): string {
|
||||
if (!this._instance) {
|
||||
throw new Error("Instance not fetched yet");
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
get expireOn(): Date | undefined {
|
||||
return this._expireOn;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ export class GameMapPropertiesListener {
|
||||
});
|
||||
} else {
|
||||
const openJitsiRoomFunction = () => {
|
||||
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.scene.instance);
|
||||
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.scene.roomUrl);
|
||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||
|
||||
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
|
||||
|
@ -185,7 +185,6 @@ export class GameScene extends DirtyScene {
|
||||
private biggestAvailableAreaStoreUnsubscribe!: () => void;
|
||||
MapUrlFile: string;
|
||||
roomUrl: string;
|
||||
instance: string;
|
||||
|
||||
currentTick!: number;
|
||||
lastSentTick!: number; // The last tick at which a position was sent.
|
||||
@ -234,7 +233,6 @@ export class GameScene extends DirtyScene {
|
||||
});
|
||||
this.Terrains = [];
|
||||
this.groups = new Map<number, Sprite>();
|
||||
this.instance = room.instance;
|
||||
|
||||
this.MapUrlFile = MapUrlFile;
|
||||
this.roomUrl = room.key;
|
||||
|
@ -9,4 +9,21 @@ export class StringUtils {
|
||||
}
|
||||
return { x: values[0], y: values[1] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a "short URL" hash of the string passed in parameter.
|
||||
*/
|
||||
public static shortHash = function (s: string): string {
|
||||
let hash = 0;
|
||||
const strLength = s.length;
|
||||
if (strLength === 0) {
|
||||
return "";
|
||||
}
|
||||
for (let i = 0; i < strLength; i++) {
|
||||
const c = s.charCodeAt(i);
|
||||
hash = (hash << 5) - hash + c;
|
||||
hash = hash & hash; // Convert to 32bit integer
|
||||
}
|
||||
return Math.abs(hash).toString(36);
|
||||
};
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { get } from "svelte/store";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { gameManager } from "../Phaser/Game/GameManager";
|
||||
import { jitsiParticipantsCountStore, userIsJitsiDominantSpeakerStore } from "../Stores/GameStore";
|
||||
import { StringUtils } from "../Utils/StringUtils";
|
||||
|
||||
interface jitsiConfigInterface {
|
||||
startWithAudioMuted: boolean;
|
||||
@ -120,7 +121,7 @@ const slugify = (...args: (string | number)[]): string => {
|
||||
.replace(/[\u0300-\u036f]/g, "") // remove all previously split accents
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^a-z0-9 ]/g, "") // remove all chars not letters, numbers and spaces (to be replaced)
|
||||
.replace(/[^a-z0-9-_ ]/g, "") // remove all chars not letters, numbers, dash, underscores and spaces (to be replaced)
|
||||
.replace(/\s+/g, "-"); // separator
|
||||
};
|
||||
|
||||
@ -135,8 +136,8 @@ class JitsiFactory {
|
||||
/**
|
||||
* Slugifies the room name and prepends the room name with the instance
|
||||
*/
|
||||
public getRoomName(roomName: string, instance: string): string {
|
||||
return slugify(instance.replace("/", "-") + "-" + roomName);
|
||||
public getRoomName(roomName: string, roomId: string): string {
|
||||
return slugify(StringUtils.shortHash(roomId) + "-" + roomName);
|
||||
}
|
||||
|
||||
public start(
|
||||
|
@ -13,7 +13,6 @@ export const isMapDetailsData = z.object({
|
||||
roomSlug: z.nullable(z.string()), // deprecated
|
||||
contactPage: z.nullable(z.string()),
|
||||
group: z.nullable(z.string()),
|
||||
instance: z.string(),
|
||||
|
||||
iframeAuthentication: z.optional(z.nullable(z.string())),
|
||||
// The date (in ISO 8601 format) at which the room will expire
|
||||
|
@ -76,10 +76,6 @@ export class MapController extends BaseHttpController {
|
||||
* type: string|null
|
||||
* description: The group this room is part of (maps the notion of "world" in WorkAdventure SAAS)
|
||||
* example: myorg/myworld
|
||||
* instance:
|
||||
* type: string
|
||||
* description: The instance of this map. In a public URL: the second part of the URL (_/[instance]/map.json)
|
||||
* example: global
|
||||
* iframeAuthentication:
|
||||
* type: string|null
|
||||
* description: The URL of the authentication Iframe
|
||||
@ -115,15 +111,14 @@ export class MapController extends BaseHttpController {
|
||||
if (!ADMIN_API_URL) {
|
||||
const roomUrl = new URL(query.playUri);
|
||||
|
||||
const match = /\/_\/([^/]+)\/(.+)/.exec(roomUrl.pathname);
|
||||
const match = /\/_\/[^/]+\/(.+)/.exec(roomUrl.pathname);
|
||||
if (!match) {
|
||||
res.status(404);
|
||||
res.json({});
|
||||
return;
|
||||
}
|
||||
|
||||
const instance = match[1];
|
||||
const mapUrl = roomUrl.protocol + "//" + match[2];
|
||||
const mapUrl = roomUrl.protocol + "//" + match[1];
|
||||
|
||||
res.json({
|
||||
mapUrl,
|
||||
@ -133,7 +128,6 @@ export class MapController extends BaseHttpController {
|
||||
tags: [],
|
||||
contactPage: null,
|
||||
authenticationMandatory: DISABLE_ANONYMOUS,
|
||||
instance,
|
||||
} as MapDetailsData);
|
||||
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user