diff --git a/server/balancer.ts b/server/balancer.ts index 11def2f4e..8d0a44e39 100644 --- a/server/balancer.ts +++ b/server/balancer.ts @@ -278,6 +278,7 @@ async function onRoomLoad(roomName: string) { type: "loaded", payload: { room: obj, + load_epoch: room.loadEpoch, }, }); gossipDebounced(); @@ -299,14 +300,17 @@ function gossip() { type: "gossip", payload: { rooms: roommanager.rooms.map(room => ({ - name: room.name, - title: room.title, - description: room.description, - isTemporary: room.isTemporary, - visibility: room.visibility, - queueMode: room.queueMode, - currentSource: room.currentSource, - users: room.users.length, + room: { + name: room.name, + title: room.title, + description: room.description, + isTemporary: room.isTemporary, + visibility: room.visibility, + queueMode: room.queueMode, + currentSource: room.currentSource, + users: room.users.length, + }, + load_epoch: room.loadEpoch, })), }, }); diff --git a/server/generated.ts b/server/generated.ts index 32ae97791..be32ea215 100644 --- a/server/generated.ts +++ b/server/generated.ts @@ -86,17 +86,16 @@ export interface M2BKick { reason: number; } -export type MsgB2M = - | { type: "load", payload: B2MLoad } - | { type: "join", payload: B2MJoin } - | { type: "leave", payload: B2MLeave } - | { type: "client_msg", payload: B2MClientMsg }; - -export type MsgM2B = - | { type: "init", payload: M2BInit } - | { type: "loaded", payload: M2BLoaded } - | { type: "unloaded", payload: M2BUnloaded } - | { type: "gossip", payload: M2BGossip } - | { type: "room_msg", payload: M2BRoomMsg } - | { type: "kick", payload: M2BKick }; - +export type MsgB2M = + | { type: "load"; payload: B2MLoad } + | { type: "join"; payload: B2MJoin } + | { type: "leave"; payload: B2MLeave } + | { type: "client_msg"; payload: B2MClientMsg }; + +export type MsgM2B = + | { type: "init"; payload: M2BInit } + | { type: "loaded"; payload: M2BLoaded } + | { type: "unloaded"; payload: M2BUnloaded } + | { type: "gossip"; payload: M2BGossip } + | { type: "room_msg"; payload: M2BRoomMsg } + | { type: "kick"; payload: M2BKick }; diff --git a/server/room.ts b/server/room.ts index 1bccfcc77..bf1872095 100644 --- a/server/room.ts +++ b/server/room.ts @@ -251,6 +251,7 @@ export class Room implements RoomState { */ wantSponsorBlock = false; dontSkipSegmentsUntil: number | null = null; + loadEpoch: number = -1; constructor(options: Partial) { this.log = getLogger(`room/${options.name}`); diff --git a/server/roommanager.ts b/server/roommanager.ts index 84a32e4b4..dc6efc7f9 100644 --- a/server/roommanager.ts +++ b/server/roommanager.ts @@ -18,6 +18,7 @@ import type { ClientManagerCommand } from "./clientmanager"; export const log = getLogger("roommanager"); export const rooms: Room[] = []; +const LOAD_EPOCH_KEY = "roommanager:load_epoch"; export type RoomManagerEvents = "publish" | "load" | "unload" | "command"; export type RoomManagerEventHandlers = E extends "publish" @@ -31,8 +32,10 @@ export type RoomManagerEventHandlers = E extends "publish" : never; const bus = new EventEmitter(); -function addRoom(room: Room) { +async function addRoom(room: Room) { rooms.push(room); + const epoch = await redisClient.incr(LOAD_EPOCH_KEY); + room.loadEpoch = epoch; bus.emit("load", room.name); } @@ -95,7 +98,7 @@ export async function createRoom(options: Partial & { name: string } await room.update(); await room.sync(); - addRoom(room); + await addRoom(room); log.info(`Room created: ${room.name}`); } @@ -130,7 +133,7 @@ export async function getRoom( const state = JSON.parse(redisState) as RoomStateFromRedis; const fixedState = redisStateToState(state); const room = new Room(fixedState); - addRoom(room); + await addRoom(room); return ok(room); } @@ -140,7 +143,7 @@ export async function getRoom( return err(new RoomNotFoundException(roomName)); } const room = new Room(opts); - addRoom(room); + await addRoom(room); return ok(room); }