| 1 | import type { TimelineItem } from './types'; |
| 2 | |
| 3 | export const FEDERATION_LAG_MS = 60 * 1000; |
| 4 | |
| 5 | /** |
| 6 | * Carries delivery lag forward from the previous list and measures it for events appended |
| 7 | * after the last one already known. `since` is when the room last became able to receive |
| 8 | * events, so catch-up after being offline or closed doesn't count as federation delay. |
| 9 | * Returns null when nothing in `items` was known before, meaning the list was replaced. |
| 10 | */ |
| 11 | export function observeArrivals(previous: TimelineItem[], items: TimelineItem[], since: number, now: number): TimelineItem[] | null { |
| 12 | const lags = new Map<string, number | undefined>(); |
| 13 | for (const item of previous) if (item.kind === 'event') lags.set(item.event.item_id, item.event.delivery_lag_ms); |
| 14 | let lastKnown = -1; |
| 15 | items.forEach((item, index) => { |
| 16 | if (item.kind === 'event' && lags.has(item.event.item_id)) lastKnown = index; |
| 17 | }); |
| 18 | if (lastKnown === -1) return null; |
| 19 | return items.map((item, index) => { |
| 20 | if (item.kind !== 'event') return item; |
| 21 | const event = item.event; |
| 22 | if (lags.has(event.item_id)) { |
| 23 | const carried = lags.get(event.item_id); |
| 24 | return carried === undefined ? item : { ...item, event: { ...event, delivery_lag_ms: carried } }; |
| 25 | } |
| 26 | if (index < lastKnown || event.own) return item; |
| 27 | const lag = now - Math.max(event.timestamp_ms, since); |
| 28 | return lag < FEDERATION_LAG_MS ? item : { ...item, event: { ...event, delivery_lag_ms: lag } }; |
| 29 | }); |
| 30 | } |