Files
Termind/Frameworks/TermindApplication/FeatureModels/LocalDiscoveryModel.swift
T

62 lines
1.9 KiB
Swift

import Foundation
import Observation
import TermindDomain
@MainActor
public protocol LocalHostDiscovering: AnyObject {
var connectionProtocol: LocalDiscoveryProtocol { get }
func discover() async throws -> [DiscoveredLocalHost]
}
public nonisolated enum LocalDiscoveryError: Error {
case unavailable
case permissionDenied
case failed
}
@MainActor
@Observable
public final class LocalDiscoveryModel {
public enum Phase { case idle, scanning, finished, unavailable, permissionDenied, failed }
public private(set) var phase = Phase.idle
public private(set) var hosts: [DiscoveredLocalHost] = []
public var connectionProtocol: LocalDiscoveryProtocol { service.connectionProtocol }
private let service: any LocalHostDiscovering
private var task: Task<Void, Never>?
private var generation = UUID()
public init(service: any LocalHostDiscovering) { self.service = service }
public func scan() {
cancel()
hosts = []
phase = .scanning
let token = generation
task = Task { [weak self] in
guard let self else { return }
do {
let hosts = try await service.discover()
try Task.checkCancellation()
guard token == generation else { return }
self.hosts = DiscoveredLocalHost.merged(hosts)
phase = .finished
} catch {
guard token == generation, !Task.isCancelled else { return }
switch error {
case LocalDiscoveryError.unavailable: phase = .unavailable
case LocalDiscoveryError.permissionDenied: phase = .permissionDenied
default: phase = .failed
}
}
task = nil
}
}
public func cancel() {
generation = UUID()
task?.cancel()
task = nil
if phase == .scanning { phase = .idle }
}
}