The template notes a seat's address at most once in ten minutes, so a seat open on two networks writes no line per request
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
1 parent
1a46d611a0
commit
210db2d5c3
2 files changed
+13
-2
No files matched your search
@@ -337,6 +337,8 @@ describe('a seat a browser lost', () => {
|
|||||||
expect(room.seats.find((s) => s.id === 'B')?.addr).toBe('home');
|
expect(room.seats.find((s) => s.id === 'B')?.addr).toBe('home');
|
||||||
expect(room.seq).toBe(seq);
|
expect(room.seq).toBe(seq);
|
||||||
rooms.seen(room, 'no-such-token', 'elsewhere');
|
rooms.seen(room, 'no-such-token', 'elsewhere');
|
||||||
|
// A seat open on two networks at once: the second address is not written on its heels.
|
||||||
|
rooms.seen(room, bo, 'office');
|
||||||
expect(new Store(dir).read(room.id).filter((l) => l.t === 'seen')).toHaveLength(1);
|
expect(new Store(dir).read(room.id).filter((l) => l.t === 'seen')).toHaveLength(1);
|
||||||
expect(new Rooms(game, new Store(dir)).get(room.id).seats.find((s) => s.id === 'B')?.addr).toBe('home');
|
expect(new Rooms(game, new Store(dir)).get(room.id).seats.find((s) => s.id === 'B')?.addr).toBe('home');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ export interface Seat {
|
|||||||
|
|
||||||
/** A table whose ledger has not been written in this long is not looked through for a lost seat. */
|
/** A table whose ledger has not been written in this long is not looked through for a lost seat. */
|
||||||
const LOST_SEAT_LOOKBACK_MS = 90 * 24 * 60 * 60 * 1000;
|
const LOST_SEAT_LOOKBACK_MS = 90 * 24 * 60 * 60 * 1000;
|
||||||
|
/** A seat's address is noted at most this often: one seat open on two networks at once must not write a line per request. */
|
||||||
|
const SEEN_EVERY_MS = 10 * 60 * 1000;
|
||||||
|
|
||||||
function hashToken(token: string): string {
|
function hashToken(token: string): string {
|
||||||
return createHash('sha256').update(token).digest('hex');
|
return createHash('sha256').update(token).digest('hex');
|
||||||
@@ -323,7 +325,10 @@ export class Rooms<State, Input> {
|
|||||||
return { phrase, expiresAt };
|
return { phrase, expiresAt };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The address a seat is used from, noted when it changes. Not a change the table need hear of: nothing wakes for it. */
|
/** When each seat's address was last noted, by room and seat. */
|
||||||
|
private seenAt = new Map<string, number>();
|
||||||
|
|
||||||
|
/** The address a seat is used from, noted when it changes, and not more often than SEEN_EVERY_MS. Not a change the table need hear of: nothing wakes for it. */
|
||||||
seen(room: Room<State>, token: string | undefined, addr: string): void {
|
seen(room: Room<State>, token: string | undefined, addr: string): void {
|
||||||
let seat: Seat;
|
let seat: Seat;
|
||||||
try {
|
try {
|
||||||
@@ -332,7 +337,11 @@ export class Rooms<State, Input> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (seat.addr === addr) return;
|
if (seat.addr === addr) return;
|
||||||
const line: LedgerLine = { t: 'seen', at: Date.now(), id: seat.id, addr };
|
const key = `${room.id}/${seat.id}`;
|
||||||
|
const now = Date.now();
|
||||||
|
if ((this.seenAt.get(key) ?? 0) > now - SEEN_EVERY_MS) return;
|
||||||
|
this.seenAt.set(key, now);
|
||||||
|
const line: LedgerLine = { t: 'seen', at: now, id: seat.id, addr };
|
||||||
this.store.append(room.id, line);
|
this.store.append(room.id, line);
|
||||||
this.apply(room, line);
|
this.apply(room, line);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user