Merging with develop

This commit is contained in:
David Négrier
2021-07-23 16:41:38 +02:00
parent 3d5c222957
commit cdd61bdb2c
135 changed files with 4313 additions and 2128 deletions
+100 -66
View File
@@ -6,18 +6,20 @@ export class MapDetail {
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
}
export interface RoomRedirect {
redirectUrl: string;
}
export class Room {
public readonly id: string;
public readonly isPublic: boolean;
private mapUrl: string | undefined;
private textures: CharacterTexture[] | undefined;
private _mapUrl: string | undefined;
private _textures: CharacterTexture[] | undefined;
private instance: string | undefined;
private _search: URLSearchParams;
private readonly _search: URLSearchParams;
constructor(id: string) {
const url = new URL(id, "https://example.com");
this.id = url.pathname;
private constructor(private roomUrl: URL) {
this.id = roomUrl.pathname;
if (this.id.startsWith("/")) {
this.id = this.id.substr(1);
@@ -30,74 +32,74 @@ export class Room {
throw new Error("Invalid room ID");
}
this._search = new URLSearchParams(url.search);
this._search = new URLSearchParams(roomUrl.search);
}
public static getIdFromIdentifier(
identifier: string,
baseUrl: string,
currentInstance: string
): { roomId: string; hash: string | null } {
let roomId = "";
let hash = null;
if (!identifier.startsWith("/_/") && !identifier.startsWith("/@/")) {
//relative file link
//Relative identifier can be deep enough to rewrite the base domain, so we cannot use the variable 'baseUrl' as the actual base url for the URL objects.
//We instead use 'workadventure' as a dummy base value.
const baseUrlObject = new URL(baseUrl);
const absoluteExitSceneUrl = new URL(
identifier,
"http://workadventure/_/" + currentInstance + "/" + baseUrlObject.hostname + baseUrlObject.pathname
);
roomId = absoluteExitSceneUrl.pathname; //in case of a relative url, we need to create a public roomId
roomId = roomId.substring(1); //remove the leading slash
hash = absoluteExitSceneUrl.hash;
hash = hash.substring(1); //remove the leading diese
if (!hash.length) {
hash = null;
}
} else {
//absolute room Id
const parts = identifier.split("#");
roomId = parts[0];
roomId = roomId.substring(1); //remove the leading slash
if (parts.length > 1) {
hash = parts[1];
/**
* Creates a "Room" object representing the room.
* This method will follow room redirects if necessary, so the instance returned is a "real" room.
*/
public static async createRoom(roomUrl: URL): Promise<Room> {
let redirectCount = 0;
while (redirectCount < 32) {
const room = new Room(roomUrl);
const result = await room.getMapDetail();
if (result instanceof MapDetail) {
return room;
}
redirectCount++;
roomUrl = new URL(result.redirectUrl);
}
return { roomId, hash };
throw new Error("Room resolving seems stuck in a redirect loop after 32 redirect attempts");
}
public async getMapDetail(): Promise<MapDetail> {
return new Promise<MapDetail>((resolve, reject) => {
if (this.mapUrl !== undefined && this.textures != undefined) {
resolve(new MapDetail(this.mapUrl, this.textures));
return;
}
public static getRoomPathFromExitUrl(exitUrl: string, currentRoomUrl: string): URL {
const url = new URL(exitUrl, currentRoomUrl);
return url;
}
if (this.isPublic) {
const match = /_\/[^/]+\/(.+)/.exec(this.id);
if (!match) throw new Error('Could not extract url from "' + this.id + '"');
this.mapUrl = window.location.protocol + "//" + match[1];
resolve(new MapDetail(this.mapUrl, this.textures));
return;
} else {
// We have a private ID, we need to query the map URL from the server.
const urlParts = this.parsePrivateUrl(this.id);
/**
* @deprecated USage of exitSceneUrl is deprecated and therefore, this method is deprecated too.
*/
public static getRoomPathFromExitSceneUrl(
exitSceneUrl: string,
currentRoomUrl: string,
currentMapUrl: string
): URL {
const absoluteExitSceneUrl = new URL(exitSceneUrl, currentMapUrl);
const baseUrl = new URL(currentRoomUrl);
Axios.get(`${PUSHER_URL}/map`, {
params: urlParts,
})
.then(({ data }) => {
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
resolve(data);
return;
})
.catch((reason) => {
reject(reason);
});
}
const currentRoom = new Room(baseUrl);
let instance: string = "global";
if (currentRoom.isPublic) {
instance = currentRoom.instance as string;
}
baseUrl.pathname = "/_/" + instance + "/" + absoluteExitSceneUrl.host + absoluteExitSceneUrl.pathname;
if (absoluteExitSceneUrl.hash) {
baseUrl.hash = absoluteExitSceneUrl.hash;
}
return baseUrl;
}
private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
const result = await Axios.get(`${PUSHER_URL}/map`, {
params: {
playUri: this.roomUrl.toString(),
},
});
const data = result.data;
if (data.redirectUrl) {
return {
redirectUrl: data.redirectUrl as string,
};
}
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
this._mapUrl = data.mapUrl;
this._textures = data.textures;
return new MapDetail(data.mapUrl, data.textures);
}
/**
@@ -123,6 +125,9 @@ export class Room {
}
}
/**
* @deprecated
*/
private parsePrivateUrl(url: string): { organizationSlug: string; worldSlug: string; roomSlug?: string } {
const regex = /@\/([^/]+)\/([^/]+)(?:\/([^/]*))?/gm;
const match = regex.exec(url);
@@ -150,4 +155,33 @@ export class Room {
public get search(): URLSearchParams {
return this._search;
}
/**
* 2 rooms are equal if they share the same path (but not necessarily the same hash)
* @param room
*/
public isEqual(room: Room): boolean {
return room.key === this.key;
}
/**
* A key representing this room
*/
public get key(): string {
const newUrl = new URL(this.roomUrl.toString());
newUrl.search = "";
newUrl.hash = "";
return newUrl.toString();
}
get textures(): CharacterTexture[] | undefined {
return this._textures;
}
get mapUrl(): string {
if (!this._mapUrl) {
throw new Error("Map URL not fetched yet");
}
return this._mapUrl;
}
}