Исправь статус модулей VPN-приложения

This commit is contained in:
2026-05-19 13:16:08 +03:00
parent 89e899dfa1
commit 44ff3a2df9
5 changed files with 85 additions and 13 deletions

View File

@@ -45,21 +45,29 @@ struct ModuleStatus: Decodable {
var backup: Bool
}
struct AppModule: Decodable {
var installed: Bool
var autostart: Bool
}
var core: Core
var bitwarden: ToggleModule
var touchid: ToggleModule
var keychain: Keychain
var dns_cleanup: DnsCleanup
var patches: Patches
var app: AppModule?
var summary: String {
let coreState = core.openconnect && core.openconnect_lite && core.openconnect_lite_config ? "core ok" : "core missing"
let bwState = bitwarden.enabled ? (bitwarden.installed ? "bw on" : "bw missing") : "bw off"
let touchState = touchid.enabled ? (touchid.installed ? "touch on" : "touch missing") : "touch off"
let dnsState = dns_cleanup.installed ? "dns on" : "dns missing"
let appState = app.map { $0.installed ? "app on" : "app missing" } ?? "app unknown"
let autostartState = app.map { $0.autostart ? "autostart on" : "autostart off" } ?? "autostart unknown"
let patchState = patches.active ? "patches active" : "patches pending"
let keychainState = "kc \(keychain.password ? "pass" : "-")/\(keychain.totp_seed ? "totp" : "-")"
return [coreState, bwState, touchState, dnsState, patchState, keychainState].joined(separator: " | ")
return [coreState, bwState, touchState, dnsState, appState, autostartState, patchState, keychainState].joined(separator: " | ")
}
}
@@ -88,7 +96,7 @@ class VPNManager: ObservableObject {
@Published var state: VPNState = .disconnected
@Published var lastError: String?
@Published var tunnelHealthy: Bool = true
@Published var moduleSummary: String = "modules unknown"
@Published var moduleSummary: String = "modules loading..."
private var process: Process?
private var outputPipe: Pipe?
@@ -151,12 +159,34 @@ class VPNManager: ObservableObject {
proc.terminationHandler = { [weak self] _ in
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let self = self, let text = String(data: data, encoding: .utf8) else { return }
guard let self = self else { return }
let text = String(data: data, encoding: .utf8) ?? ""
let lastLine = text.split(separator: "\n").map(String.init).last ?? ""
guard let jsonData = lastLine.data(using: .utf8),
let response = try? JSONDecoder().decode(VPNStatusResponse.self, from: jsonData),
let modules = response.modules else { return }
Task { @MainActor in
guard !lastLine.isEmpty, let jsonData = lastLine.data(using: .utf8) else {
self.moduleSummary = "modules unavailable"
self.log("[modules] status refresh returned no JSON output")
return
}
let response: VPNStatusResponse
do {
response = try JSONDecoder().decode(VPNStatusResponse.self, from: jsonData)
} catch {
self.moduleSummary = "modules unavailable"
let compact = text.replacingOccurrences(of: "\n", with: "\\n")
let preview = compact.count > 500 ? String(compact.prefix(500)) + "..." : compact
self.log("[modules] status decode failed: \(error.localizedDescription); output=\(preview)")
return
}
guard let modules = response.modules else {
self.moduleSummary = "modules unavailable: update CLI"
self.log("[modules] status has no modules field; reinstall CLI with install.sh")
return
}
self.moduleSummary = modules.summary
}
}