/** * Status messages are saved per device (`lotus-status-msg-`) and * re-sent with every presence heartbeat, because a presence write that omits * `status_msg` clears it on Synapse. #187 DP3: a device never receives its own * user's presence changes made on other devices, so a status cleared elsewhere * stayed in its local copy and was re-published on the next heartbeat. The * heartbeat now reconciles with the server first (see usePresenceUpdater); this * module only tracks this device's own writes so that a fresh local save isn't * overridden by a server read that hasn't caught up yet. */ /** The status_msg Lotus sends for Do Not Disturb (see usePresenceUpdater). */ export const DND_STATUS_SENTINEL = 'dnd'; /** Trust this device's own copy for this long after it saved or cleared it. */ export const LOCAL_WRITE_GRACE_MS = 15_000; let lastLocalWriteAt = 0; /** Call whenever this device saves or clears its own status. */ export const noteLocalStatusWrite = (now: number = Date.now()): void => { lastLocalWriteAt = now; }; export const getLastLocalStatusWrite = (): number => lastLocalWriteAt; /** * Which status a heartbeat should send, given what the server says now. * `server` is undefined when the read failed. An offline server presence * (invisible mode) carries an empty status by design, so it isn't a clear. */ export const pickHeartbeatStatus = ({ local, server, lastLocalWriteAt: writtenAt, now, }: { local: string; server: { presence: string; status_msg?: string } | undefined; lastLocalWriteAt: number; now: number; }): string => { // [Gitea #283] Lotus encodes Do Not Disturb as status_msg "dnd", so a device // leaving DND must not adopt that sentinel as the user's status — keep (and // so restore) the real one it holds locally. const mine = local === DND_STATUS_SENTINEL ? '' : local; if (!server || server.presence === 'offline') return mine; if (now - writtenAt < LOCAL_WRITE_GRACE_MS) return mine; if (server.status_msg === DND_STATUS_SENTINEL) return mine; return server.status_msg ?? ''; };