diff --git a/apps/match/src/match.app.ts b/apps/match/src/match.app.ts index 3a0e6e2..6dd3295 100644 --- a/apps/match/src/match.app.ts +++ b/apps/match/src/match.app.ts @@ -4,7 +4,12 @@ import { useWorkersLogger } from 'workers-tagged-logger' import { withNotFound, withOnError } from '@repo/hono-helpers' import { validateAndGetAccountId } from './jwt' -import { createRoomInstance, getJoinableInstance, getRoomInstancesByRoom } from './room-instance-db' +import { + createRoomInstance, + getJoinableInstance, + getRoomInstancesByRoom, + setRoomInstanceInProgress, +} from './room-instance-db' import { getOrCreateDormRoom, getRoomById, getRoomByName } from './rooms-db' import type { Context } from 'hono' @@ -488,6 +493,24 @@ const app = new Hono() // ---- Room instance ------------------------------------------------------- .post('/roominstance/:id/reportjoinresult', (c) => c.body(null, 200)) + // The room owner flips the instance's in-progress flag once the session starts + // (e.g. a game round begins). Body is a form post: `inProgress=True|False`. + .put('/roominstance/:id/inprogress', async (c) => { + const id = await authedId(c) + if (id === null) return unauthorized(c) + + const instanceId = Number.parseInt(c.req.param('id'), 10) + if (Number.isNaN(instanceId)) return c.body(null, 404) + + const body = await c.req.parseBody().catch(() => ({}) as Record) + const inProgress = + typeof body.inProgress === 'string' && body.inProgress.toLowerCase() === 'true' + + const instance = await setRoomInstanceInProgress(c.env.DB, instanceId, inProgress) + if (!instance) return c.body(null, 404) + return c.body(null, 200) + }) + // Rooms flagged as needing a developer/moderator to spawn in. No such queue // yet → empty list. .get('/rooms/requiring/developer', (c) => c.json([])) diff --git a/apps/match/src/room-instance-db.ts b/apps/match/src/room-instance-db.ts index 116778b..3b1fc6a 100644 --- a/apps/match/src/room-instance-db.ts +++ b/apps/match/src/room-instance-db.ts @@ -176,10 +176,34 @@ export async function getRoomInstance(db: D1Database, id: number): Promise { + const row = await db + .prepare('SELECT data FROM room_instance WHERE id = ?1') + .bind(id) + .first<{ data: string }>() + if (!row) return null + const stored = parse(row.data) + stored.isInProgress = isInProgress + await db + .prepare('UPDATE room_instance SET data = ?1 WHERE id = ?2') + .bind(JSON.stringify(stored), id) + .run() + return toDto(stored) +} + /** * The oldest joinable public instance of a room (not private, not full, joins - * enabled), or null when there's none to join. Used by matchmaking to reuse an - * existing instance before creating a new one. + * enabled, not already in progress), or null when there's none to join. Used by + * matchmaking to reuse an existing instance before creating a new one. */ export async function getJoinableInstance( db: D1Database, @@ -189,6 +213,7 @@ export async function getJoinableInstance( .prepare( `SELECT data FROM room_instance WHERE room_id = ?1 AND is_private = 0 AND is_full = 0 AND join_disabled = 0 + AND is_in_progress = 0 ORDER BY id LIMIT 1` ) .bind(roomId)