add IDLE monitoring to SyncCoordinator: start/stop with capability check

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 13:40:47 +01:00
parent 1cbe09c443
commit 9a42ae9574
2 changed files with 93 additions and 1 deletions

View File

@@ -13,7 +13,10 @@ public final class SyncCoordinator {
private let store: MailStore
private let actionQueue: ActionQueue?
private let taskStore: TaskStore?
private let credentials: Credentials?
private var syncTask: Task<Void, Never>?
private var idleClient: IMAPIdleClient?
private var idleActive = false
public private(set) var syncState: SyncState = .idle
private var eventHandlers: [(SyncEvent) -> Void] = []
@@ -23,13 +26,15 @@ public final class SyncCoordinator {
imapClient: any IMAPClientProtocol,
store: MailStore,
actionQueue: ActionQueue? = nil,
taskStore: TaskStore? = nil
taskStore: TaskStore? = nil,
credentials: Credentials? = nil
) {
self.accountConfig = accountConfig
self.imapClient = imapClient
self.store = store
self.actionQueue = actionQueue
self.taskStore = taskStore
self.credentials = credentials
}
public func onEvent(_ handler: @escaping (SyncEvent) -> Void) {
@@ -286,6 +291,49 @@ public final class SyncCoordinator {
}
}
// MARK: - IMAP IDLE
/// Check server capabilities and start IDLE monitoring if supported.
/// Must be called after at least one successful sync (so capabilities are cached).
public func startIdleMonitoring() async {
guard let credentials else {
print("[SyncCoordinator] No credentials provided, cannot start IDLE")
return
}
do {
let caps = try await imapClient.capabilities()
guard caps.contains("IDLE") else {
print("[SyncCoordinator] Server does not support IDLE, using periodic sync only")
return
}
let client = IMAPIdleClient(
host: accountConfig.imapHost,
port: accountConfig.imapPort,
credentials: credentials
)
idleClient = client
idleActive = true
try await client.startMonitoring { [weak self] in
Task { @MainActor [weak self] in
try? await self?.syncNow()
}
}
} catch {
print("[SyncCoordinator] Failed to start IDLE monitoring: \(error)")
}
}
/// Stop IDLE monitoring and clean up.
public func stopIdleMonitoring() async {
idleActive = false
await idleClient?.stopMonitoring()
idleClient = nil
}
// MARK: - Periodic Sync
public func startPeriodicSync(interval: Duration = .seconds(300)) {