diff --git a/package-lock.json b/package-lock.json index ae1968b..92fd6bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "colyseus.js", - "version": "0.15.19", + "version": "0.15.24", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "colyseus.js", - "version": "0.15.19", + "version": "0.15.24", "license": "MIT", "dependencies": { "@colyseus/schema": "^2.0.4", diff --git a/package.json b/package.json index a100aa4..4b6283b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.24", + "version": "0.15.25", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/3rd_party/discord.ts b/src/3rd_party/discord.ts new file mode 100644 index 0000000..320e99b --- /dev/null +++ b/src/3rd_party/discord.ts @@ -0,0 +1,24 @@ +/** + * Discord Embedded App SDK + * https://github.com/colyseus/colyseus/issues/707 + * + * All URLs must go through the local proxy from + * https://.discordsays.com//... + * + * You must configure your URL Mappings with: + * - /colyseus/{subdomain} -> {subdomain}.colyseus.cloud + * + * Example: + * const client = new Client("https://xxxx.colyseus.cloud"); + * + */ + export function discordURLBuilder (url: URL): string { + const localHostname = window?.location?.hostname || "localhost"; + + const remoteHostnameSplitted = url.hostname.split('.'); + const subdomain = (remoteHostnameSplitted.length > 2) + ? `/${remoteHostnameSplitted[0]}` + : ''; + + return `${url.protocol}//${localHostname}/colyseus${subdomain}${url.pathname}${url.search}`; + } \ No newline at end of file diff --git a/src/Client.ts b/src/Client.ts index e280d3e..e4e8668 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -3,6 +3,7 @@ import { Room, RoomAvailable } from './Room'; import { SchemaConstructor } from './serializer/SchemaSerializer'; import { HTTP } from "./HTTP"; import { Auth } from './Auth'; +import { discordURLBuilder } from './3rd_party/discord'; export type JoinOptions = any; @@ -33,8 +34,12 @@ export class Client { public auth: Auth; protected settings: EndpointSettings; + protected urlBuilder: (url: URL) => string; - constructor(settings: string | EndpointSettings = DEFAULT_ENDPOINT) { + constructor( + settings: string | EndpointSettings = DEFAULT_ENDPOINT, + customURLBuilder?: (url: URL) => string + ) { if (typeof (settings) === "string") { // @@ -74,6 +79,20 @@ export class Client { this.http = new HTTP(this); this.auth = new Auth(this.http); + + this.urlBuilder = customURLBuilder; + + // + // Discord Embedded SDK requires a custom URL builder + // + if ( + !this.urlBuilder && + typeof (window) !== "undefined" && + window?.location?.hostname?.includes("discordsays.com") + ) { + this.urlBuilder = discordURLBuilder; + console.log("Colyseus SDK: Discord Embedded SDK detected. Using custom URL builder."); + } } public async joinOrCreate(roomName: string, options: JoinOptions = {}, rootSchema?: SchemaConstructor) { @@ -231,12 +250,18 @@ export class Client { endpoint += `${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}`; } - return `${endpoint}/${room.processId}/${room.roomId}?${params.join('&')}`; + const endpointURL = `${endpoint}/${room.processId}/${room.roomId}?${params.join('&')}`; + return (this.urlBuilder) + ? this.urlBuilder(new URL(endpointURL)) + : endpointURL; } protected getHttpEndpoint(segments: string = '') { const path = segments.startsWith("/") ? segments : `/${segments}`; - return `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}${path}`; + const endpointURL = `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}${path}`; + return (this.urlBuilder) + ? this.urlBuilder(new URL(endpointURL)) + : endpointURL; } protected getEndpointPort() { diff --git a/test/client_test.ts b/test/client_test.ts index df003b7..1f4122b 100644 --- a/test/client_test.ts +++ b/test/client_test.ts @@ -2,6 +2,7 @@ import './util'; import { assert } from "chai"; import { Client } from "../src"; import { Schema, type } from '@colyseus/schema'; +import { discordURLBuilder } from '../src/3rd_party/discord'; describe("Client", function () { let client: Client; @@ -68,6 +69,42 @@ describe("Client", function () { assert.strictEqual(expected.wsEndpointPublicAddress, clientWithSettings['buildEndpoint'](roomWithPublicAddress)); } }); + + it("discord url builder", () => { + const room = { roomId: "roomId", processId: "processId", sessionId: "sessionId", }; + const roomWithPublicAddress = { publicAddress: "node-1.colyseus.cloud", roomId: "roomId", processId: "processId", sessionId: "sessionId", }; + + const settingsByUrl = { + 'ws://example.com': { + httpEndpoint: "http://localhost/colyseus/", + wsEndpoint: "ws://localhost/colyseus/processId/roomId", + wsEndpointPublicAddress: "ws://localhost/colyseus/node-1/processId/roomId" + }, + 'ws://subdomain.colyseus.cloud': { + httpEndpoint: "http://localhost/colyseus/subdomain/", + wsEndpoint: "ws://localhost/colyseus/subdomain/processId/roomId", + wsEndpointPublicAddress: "ws://localhost/colyseus/node-1/processId/roomId" + }, + 'https://subdomain.colyseus.cloud/custom/path': { + httpEndpoint: "https://localhost/colyseus/subdomain/custom/path/", + wsEndpoint: "wss://localhost/colyseus/subdomain/custom/path/processId/roomId", + wsEndpointPublicAddress: "wss://localhost/colyseus/node-1/processId/roomId" + }, + // '/api': { + // httpEndpoint: "http://127.0.0.1:2567/api/", + // wsEndpoint: "ws://127.0.0.1:2567/api/processId/roomId", + // wsEndpointPublicAddress: "ws://node-1.colyseus.cloud/processId/roomId" + // }, + }; + + for (const url in settingsByUrl) { + const expected = settingsByUrl[url]; + const client = new Client(url, discordURLBuilder); + assert.strictEqual(expected.httpEndpoint, client['getHttpEndpoint']()); + assert.strictEqual(expected.wsEndpoint, client['buildEndpoint'](room)); + assert.strictEqual(expected.wsEndpointPublicAddress, client['buildEndpoint'](roomWithPublicAddress)); + } + }); }); xit("join", function () {