[match] add developer tachyon override

This commit is contained in:
Devin Zuczek
2026-09-18 13:08:43 -04:00
parent fd4264d982
commit 04554b0826
3 changed files with 114 additions and 9 deletions
+47 -5
View File
@@ -229,6 +229,40 @@ function tachyonServerFor(env: Env, roomInstanceId: number): TachyonServer {
return pool[roomInstanceId % pool.length] ?? NO_TACHYON_SERVER
}
/**
* The Tachyon port a DEVELOPER is handed, in place of the port on the pool entry their
* instance resolved to. Developers connect to a separate Tachyon build running beside the
* live one on the same box, so only the PORT moves: the HOST stays whichever one
* {@link tachyonServerFor} picked, rather than scattering developers off the pool.
*/
const DEVELOPER_TACHYON_PORT = '7778'
/**
* The id displayed for that dev server. Not `tachyon-N` — the generated ids are positional
* names for entries in the pool ({@link tachyonPool}), and the dev build is not one of
* them: it is a different server that happens to share a host. The id is cosmetic (the
* client displays it and never sends it anywhere), so it only has to say which server the
* player is on, and "dev" is that.
*/
const DEVELOPER_TACHYON_SERVER_ID = 'dev'
/**
* `server` with its port replaced by {@link DEVELOPER_TACHYON_PORT} and its id by
* {@link DEVELOPER_TACHYON_SERVER_ID}. An empty address is left alone — the pool is unset or
* the caller is in no instance, so there is no server to point at another port, and writing
* a bare `:7778` would hand the client an address that answers nothing (and name a server
* that isn't there). Splits on the LAST colon so a bracketed IPv6 host survives.
*/
function developerTachyonServer(server: TachyonServer): TachyonServer {
if (server.hostPort === '') return server
const colon = server.hostPort.lastIndexOf(':')
const host = colon === -1 ? server.hostPort : server.hostPort.slice(0, colon)
return {
hostPort: `${host}:${DEVELOPER_TACHYON_PORT}`,
serverId: DEVELOPER_TACHYON_SERVER_ID,
}
}
/**
* Networking feature flags the client reads off its connection info. Verbatim from
* the reference server — the client changes how it replicates based on these, so they
@@ -2872,7 +2906,9 @@ const app = new Hono<App>()
'fields name the Tachyon server that instance was assigned — one entry out of the',
'`TACHYON_HOST_PORT` pool, chosen by instance id so every player in a session is',
'handed the same one, with a generated `voiceServerId` (`tachyon-1`, `tachyon-2`,',
'…). Both are empty when the pool is unset or the caller is in no instance.',
'…). Both are empty when the pool is unset or the caller is in no instance. A',
'caller holding the DEVELOPER role gets that same host on port 7778, the dev',
'Tachyon build, with a `voiceServerId` of `dev`.',
'`experiments` carries the client’s networking flags.',
].join(' '),
security: AUTHED,
@@ -2911,8 +2947,13 @@ const app = new Hono<App>()
photonRoomId = instance?.photonRoomId ?? ''
}
}
// The instance's server, the same one every other player in it is handed.
const tachyon = tachyonServerFor(c.env, roomInstanceId)
const account = await getAccount(c.env.DB, id)
// The instance's server, the same one every other player in it is handed — except
// for a DEVELOPER, who is sent to the same host on the dev port, under the id
// `dev` rather than the pool entry's positional name.
const assigned = tachyonServerFor(c.env, roomInstanceId)
const tachyon =
account?.isDeveloper === true ? developerTachyonServer(assigned) : assigned
// Identifies the player to Photon. Signed with the shared JWT secret; the token's
// `aud` is the realtime app it's for. Nothing verifies it while Photon is
@@ -2920,7 +2961,7 @@ const app = new Hono<App>()
const photonAuthToken = await generatePhotonAuthToken(
id,
{
platformId: (await getAccount(c.env.DB, id))?.platformId ?? '',
platformId: account?.platformId ?? '',
platform: presence?.platform ?? 0,
deviceClass: presence?.deviceClass ?? 0,
audience: apps.photonRealtimeAppId,
@@ -2936,7 +2977,8 @@ const app = new Hono<App>()
photonRoomId,
// The Tachyon server this instance runs on, picked out of the operator's
// pool by {@link tachyonServerFor} — empty strings when the pool is empty
// or the caller is in no instance. Empty rather than null: the client's
// or the caller is in no instance, and on the dev port (id `dev`) for a
// developer. Empty rather than null: the client's
// decoder is likelier to accept a missing-value string than a null on a
// string field. The presence payload's NULL_CONNECTION_INFO keeps its
// nulls — that one never carries credentials.