macOS client store and API
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user