Files

99 lines
2.2 KiB
Swift
Raw Permalink Normal View History

2026-10-16 22:46:54 -07:00
import Foundation
import Observation
@MainActor
final class Listeners<T> {
private var fns: [(id: UUID, fn: (T) -> Void)] = []
func add(_ fn: @escaping (T) -> Void) -> () -> Void {
let id = UUID()
fns.append((id, fn))
return { [weak self] in
self?.fns.removeAll { $0.id == id }
}
}
func send(_ value: T) {
for entry in fns {
entry.fn(value)
}
}
}
@MainActor
@Observable
final class Feed {
private(set) var events: [ByreEvent] = []
private(set) var ready = false
let appended = Listeners<[ByreEvent]>()
let streamed = Listeners<ByreEvent>()
@ObservationIgnored private var last: Int64 = 0
@ObservationIgnored private var buffer: [ByreEvent] = []
@ObservationIgnored private var scheduled = false
@ObservationIgnored private let shown: () -> Bool
init(shown: @escaping () -> Bool) {
self.shown = shown
}
func push(_ ev: ByreEvent) {
if ev.seq == 0 && (!ready || !shown()) {
return
}
buffer.append(ev)
if ready && !scheduled {
scheduled = true
Task { @MainActor in
self.flush()
}
}
}
func load(_ history: [ByreEvent]) {
if ready {
return
}
ready = true
buffer = history + buffer
flush()
}
func prepend(_ older: [ByreEvent]) {
events.insert(contentsOf: older, at: 0)
}
private func flush() {
scheduled = false
let pending = buffer
buffer = []
var stored: [ByreEvent] = []
for ev in pending {
if ev.seq != 0 {
stored.append(ev)
continue
}
append(stored)
stored = []
if shown() {
streamed.send(ev)
}
}
append(stored)
}
private func append(_ batch: [ByreEvent]) {
var fresh: [ByreEvent] = []
for ev in batch where ev.seq > last {
fresh.append(ev)
last = ev.seq
}
if fresh.isEmpty {
return
}
events.append(contentsOf: fresh)
if shown() {
appended.send(fresh)
}
}
}