mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
move presence to d1
This commit is contained in:
@@ -9,12 +9,10 @@ export type Env = SharedHonoEnv & {
|
||||
// with `await env.JWT_SECRET.get()`; all workers bind the same store so tokens
|
||||
// signed by `auth` verify here.
|
||||
JWT_SECRET: SecretsStoreSecret
|
||||
// D1 database holding rooms (JSON blob + generated columns). See rooms-db.ts.
|
||||
// Shared `recflare` D1. Owns the rooms tables (JSON blob + generated columns,
|
||||
// see rooms-db.ts) and migrates the shared `presence` table, which is read here
|
||||
// to resolve the caller's current room instance for the photon access token.
|
||||
DB: D1Database
|
||||
// Shared player-presence KV (owned by the `match` worker). Read here to resolve
|
||||
// the caller's current room instance for the photon access token — the
|
||||
// equivalent of the reference server's HeartbeatDB.GetPlayerHeartbeat.
|
||||
RECFLARE_MATCH_PRESENCE: KVNamespace
|
||||
// SignalR notifications hub (DO owned by the `notify` worker). Bound here to
|
||||
// push RoomUpdate notifications when a room is mutated.
|
||||
RECFLARE_NOTIFICATIONS_HUB: DurableObjectNamespace<NotificationsHub>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
getFeaturedRooms,
|
||||
getHotRooms,
|
||||
getInteraction,
|
||||
getPresence,
|
||||
getPublicRoomsByCreator,
|
||||
getRecommendedRooms,
|
||||
getRoomById,
|
||||
@@ -66,13 +67,9 @@ function allIds(idParam: string): number[] {
|
||||
* hardcoded moderator/dev accounts. */
|
||||
const MAKER_PEN_ACCOUNT_IDS = new Set([1, 2, 3])
|
||||
|
||||
/** Presence KV key (owned by the `match` worker); keep in sync with match's `presenceKey`. */
|
||||
const presenceKey = (id: number) => `presence:${id}`
|
||||
|
||||
/** The slice of the match worker's presence record we read — the caller's current
|
||||
* room instance. Mirrors the reference server's HeartbeatDB row. */
|
||||
/** The slice of the shared presence row we read — the caller's current room instance. */
|
||||
interface PresenceView {
|
||||
roomInstance?: { roomInstanceId?: number } | null
|
||||
roomInstanceId?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,15 +114,12 @@ function photonAccessToken(accountId: number, roomInstanceId: number | null) {
|
||||
/**
|
||||
* Photon access-token handler (served bare and under `/roomserver`). Auth-gated:
|
||||
* resolves the caller, reads their current room instance from the shared
|
||||
* presence KV, and returns the permissions + token.
|
||||
* `presence` table (see @repo/domain), and returns the permissions + token.
|
||||
*/
|
||||
async function handlePhotonAccessToken(c: Context<App>) {
|
||||
const accountId = await authedAccountId(c)
|
||||
if (accountId === null) return unauthorized(c)
|
||||
const presence = await c.env.RECFLARE_MATCH_PRESENCE.get<PresenceView>(
|
||||
presenceKey(accountId),
|
||||
'json'
|
||||
)
|
||||
const presence = await getPresence<PresenceView>(c.env.DB, accountId)
|
||||
const roomInstanceId = presence?.roomInstance?.roomInstanceId ?? null
|
||||
return c.json(photonAccessToken(accountId, roomInstanceId))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import '../../rooms.app'
|
||||
import {
|
||||
createRoomInstance,
|
||||
getRoomInstance,
|
||||
PRESENCE_SCHEMA_DDL,
|
||||
ROOM_INSTANCE_SCHEMA_DDL,
|
||||
ROOM_SCHEMA_DDL,
|
||||
} from '@repo/domain'
|
||||
@@ -50,6 +51,8 @@ beforeAll(async () => {
|
||||
await adminSecretsStore(env.JWT_SECRET).create('test-signing-key')
|
||||
for (const stmt of ROOM_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
for (const stmt of ROOM_INSTANCE_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
// Presence table (read by the photon access-token handler).
|
||||
for (const stmt of PRESENCE_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
const insert = env.DB.prepare('INSERT OR IGNORE INTO room (data) VALUES (?1)')
|
||||
await env.DB.batch(importRooms.map((r) => insert.bind(JSON.stringify(r))))
|
||||
})
|
||||
@@ -785,10 +788,15 @@ describe('rooms endpoints', () => {
|
||||
|
||||
it('GET /photon_access_token (bare + /roomserver) returns permissions + presence instance', async () => {
|
||||
// Seed the caller's presence so RoomInstanceId reflects their current instance.
|
||||
await env.RECFLARE_MATCH_PRESENCE.put(
|
||||
'presence:777',
|
||||
JSON.stringify({ roomInstance: { roomInstanceId: 1000042 } })
|
||||
)
|
||||
await env.DB.prepare('INSERT OR REPLACE INTO presence (data) VALUES (?1)')
|
||||
.bind(
|
||||
JSON.stringify({
|
||||
accountId: 777,
|
||||
roomInstance: { roomInstanceId: 1000042 },
|
||||
expiresAt: Math.floor(Date.now() / 1000) + 900,
|
||||
})
|
||||
)
|
||||
.run()
|
||||
const headers = await bearer('777')
|
||||
for (const path of ['/photon_access_token', '/roomserver/photon_access_token']) {
|
||||
const res = await SELF.fetch(`${ORIGIN}${path}`, { headers })
|
||||
|
||||
Reference in New Issue
Block a user