99 lines
2.2 KiB
Swift
99 lines
2.2 KiB
Swift
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)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|