| 54 | } |
| 55 | |
| 56 | function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[]) { |
| 57 | if (items.length === 0) return { ...page, observed: [] as { messageID: string; parts: Part[] }[] } |
| 58 | const session = [...page.session] |
| 59 | const part = new Map(page.part.map((item) => [item.id, item.part])) |
| 60 | const observed: { messageID: string; parts: Part[] }[] = [] |
| 61 | for (const item of items) { |
| 62 | const result = Binary.search(session, item.message.id, (message) => message.id) |
| 63 | if (!result.found) session.splice(result.index, 0, item.message) |
| 64 | const current = part.get(item.message.id) |
| 65 | const confirmed = result.found |
| 66 | ? item.parts.filter((part) => Binary.search(current ?? [], part.id, (value) => value.id).found) |
| 67 | : [] |
| 68 | if (result.found) observed.push({ messageID: item.message.id, parts: confirmed }) |
| 69 | part.set( |
| 70 | item.message.id, |
| 71 | merge( |
| 72 | result.found ? (current ?? []) : merge(item.confirmedParts ?? [], current ?? []), |
| 73 | item.parts.filter((part) => !confirmed.includes(part)), |
| 74 | ), |
| 75 | ) |
| 76 | } |
| 77 | return { |
| 78 | ...page, |
| 79 | session, |
| 80 | part: [...part.entries()].sort((a, b) => cmp(a[0], b[0])).map(([id, parts]) => ({ id, part: parts })), |
| 81 | observed, |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | function runInflight(map: Map<string, Promise<void>>, key: string, task: () => Promise<void>) { |
| 86 | const pending = map.get(key) |