server switcher is broken

This commit is contained in:
Ian Gulliver
2026-10-19 09:51:42 -07:00
parent 6382dfda0e
commit 55fea11fab
3 changed files with 49 additions and 18 deletions
+41 -12
View File
@@ -121,6 +121,7 @@ final class Connection {
let overlays = Overlays()
var phase: Phase = .starting
@ObservationIgnored private var stopped = false
@ObservationIgnored private var restarting = false
init(origin: URL) {
self.origin = origin
@@ -144,13 +145,32 @@ final class Connection {
}
private func start() async {
while !stopped, !(await attempt()) {
let old = store
while !stopped, !(await attempt(old)) {
try? await Task.sleep(for: .seconds(2))
}
if let old {
await old.stop()
}
}
private func attempt() async -> Bool {
let store = Store(api: API(origin: origin))
private func reconnected(_ startedAt: Date) {
guard !restarting else {
return
}
Task {
guard let status = try? await API(origin: origin).client.getStatus().ok.body.json, status.startedAt != startedAt, !stopped, !restarting else {
return
}
log.notice("\(self.origin.absoluteString, privacy: .public) restarted, reloading")
restarting = true
await start()
restarting = false
}
}
private func attempt(_ old: Store?) async -> Bool {
let store = Store(api: API(origin: origin), images: old?.images ?? ImageDrafts())
do {
let status = try await store.api.client.getStatus().ok.body.json
async let me: Void = store.loadMe()
@@ -159,17 +179,19 @@ final class Connection {
async let lead: Void = store.loadLeadSessions()
async let reads: Void = store.loadSummaryReads()
_ = try await (me, projects, inbox, lead, reads)
store.loadDrafts()
try await store.loadFocus()
guard !stopped else {
await store.stop()
return true
}
store.loadDrafts(from: old)
Task {
await store.startLeadStream()
}
phase = .running(store)
store.startGlobalStream(after: status.lastEventSeq)
store.startGlobalStream(after: status.lastEventSeq) { [weak self] in
self?.reconnected(status.startedAt)
}
store.remote.start()
Notifier.shared.deliver()
return true
@@ -394,7 +416,7 @@ struct ServerWindow: View {
MainView()
.environment(store)
.environment(connection.overlays)
.id(connection.origin)
.id(ObjectIdentifier(store))
}
} else {
ConnectView(form: form) { connected in
@@ -421,6 +443,7 @@ struct ServerWindow: View {
ToolbarItem(placement: .principal) {
ServerPicker()
}
.sharedBackgroundVisibility(.hidden)
}
.toolbar(removing: .title)
.focusedSceneValue(\.serverWindow, focus)
@@ -499,12 +522,18 @@ private struct ServerChip: View {
Badge(count: questions)
.help("open questions")
}
if summaries > 0 {
Text("\(summaries) new")
.font(Fonts.font(11, weight: 700))
.foregroundStyle(Palette.accent)
.help("Turn summaries you haven't read")
}
Text("99")
.font(Fonts.font(11, weight: 700))
.hidden()
.overlay(alignment: .leading) {
if summaries > 0 {
Text("\(summaries)")
.font(Fonts.font(11, weight: 700))
.foregroundStyle(Palette.accent)
.fixedSize()
.help("Turn summaries you haven't read")
}
}
}
.foregroundStyle(hover || current ? Palette.text : questions > 0 ? Palette.warn : Palette.muted)
.padding(.horizontal, 8)
+7 -5
View File
@@ -60,7 +60,7 @@ final class Store {
var todoBusy: [String: String] = [:]
var pickedMembers: [String: String] = [:]
private(set) var drafts: Drafts?
let images = ImageDrafts()
let images: ImageDrafts
let imageCache = ImageCache()
let events = Listeners<ByreEvent>()
let paneFocus: PaneFocus
@@ -74,8 +74,9 @@ final class Store {
@ObservationIgnored private var stopped = false
@ObservationIgnored var changesMemory = ChangesMemory()
init(api: API) {
init(api: API, images: ImageDrafts) {
self.api = api
self.images = images
leadFeed = Feed(shown: { true })
paneFocus = PaneFocus(api: api)
remote = Remote(api: api)
@@ -90,8 +91,8 @@ final class Store {
await paneFocus.leave()
}
func loadDrafts() {
drafts = Drafts(origin: api.origin, login: me!.login)
func loadDrafts(from old: Store?) {
drafts = old?.drafts ?? Drafts(origin: api.origin, login: me!.login)
drafts!.prune(self)
}
@@ -565,13 +566,14 @@ final class Store {
})
}
func startGlobalStream(after: Int64) {
func startGlobalStream(after: Int64, reconnected: @escaping () -> Void) {
globalStream = EventStream(api: api, after: after, lead: false, onEvent: { [weak self] ev in
self?.handleEvent(ev)
}, onState: { [weak self] up in
self?.connected = up
if up {
self?.paneFocus.reconnected()
reconnected()
}
}, onReady: {})
}