Full project scaffold: XcodeGen project.yml, Core models/protocols/errors, SMBService (kishikawakatsumi/SMBClient), SFTPService (Citadel 0.9.2), PhotoLibraryService, LANMonitor, BackupEngine, BackgroundTaskManager, all feature UIs (Login, Connect, Browse, Backup, History, Settings), Shared components and theme. Builds clean with zero errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
60 lines
1.6 KiB
Swift
60 lines
1.6 KiB
Swift
import Foundation
|
|
import Network
|
|
import NetworkExtension
|
|
import Combine
|
|
|
|
@MainActor
|
|
final class LANMonitor: ObservableObject {
|
|
static let shared = LANMonitor()
|
|
|
|
@Published private(set) var isOnNetwork: Bool = false
|
|
@Published private(set) var currentSSID: String? = nil
|
|
|
|
private let monitor = NWPathMonitor()
|
|
private let queue = DispatchQueue(label: "com.albert.nasbackup.lan", qos: .utility)
|
|
|
|
var onTrustedNetworkJoined: ((String) -> Void)?
|
|
|
|
private init() {}
|
|
|
|
func start() {
|
|
monitor.pathUpdateHandler = { [weak self] path in
|
|
guard let self else { return }
|
|
Task { @MainActor in
|
|
let satisfied = path.status == .satisfied
|
|
self.isOnNetwork = satisfied
|
|
|
|
if satisfied {
|
|
await self.checkSSID()
|
|
} else {
|
|
self.currentSSID = nil
|
|
}
|
|
}
|
|
}
|
|
monitor.start(queue: queue)
|
|
}
|
|
|
|
func stop() {
|
|
monitor.cancel()
|
|
}
|
|
|
|
private func checkSSID() async {
|
|
let ssid = await fetchCurrentSSID()
|
|
self.currentSSID = ssid
|
|
}
|
|
|
|
func fetchCurrentSSID() async -> String? {
|
|
await withCheckedContinuation { continuation in
|
|
NEHotspotNetwork.fetchCurrent { network in
|
|
continuation.resume(returning: network?.ssid)
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkAndTriggerIfTrusted(trustedSSIDs: [String]) async {
|
|
let ssid = await fetchCurrentSSID()
|
|
guard let ssid, trustedSSIDs.contains(ssid) else { return }
|
|
onTrustedNetworkJoined?(ssid)
|
|
}
|
|
}
|