diff --git a/Tun/Punchnet/SDLTunnelAppNotifier.swift b/Tun/Punchnet/SDLTunnelAppNotifier.swift new file mode 100644 index 0000000..60a0b1f --- /dev/null +++ b/Tun/Punchnet/SDLTunnelAppNotifier.swift @@ -0,0 +1,71 @@ +// +// SDLTunnelAppNotifier.swift +// Tun +// +// Created by 安礼成 on 2026/4/15. +// + +import Foundation + +final class SDLTunnelAppNotifier { + struct Event: Codable, Sendable { + enum Level: String, Codable, Sendable { + case info + case warning + case error + case fatal + } + + let id: String + let timestamp: TimeInterval + let level: Level + let code: Int? + let message: String + } + + static let shared = SDLTunnelAppNotifier() + + static let appGroupSuiteName = "group.com.jihe.punchnetmac" + static let latestEventKey = "tunnel.latestEvent" + + private let suiteName: String + private let eventKey: String + + init(suiteName: String = SDLTunnelAppNotifier.appGroupSuiteName, + eventKey: String = SDLTunnelAppNotifier.latestEventKey) { + self.suiteName = suiteName + self.eventKey = eventKey + } + + func publish(level: Event.Level = .error, code: Int? = nil, message: String) { + let event = Event( + id: UUID().uuidString, + timestamp: Date().timeIntervalSince1970, + level: level, + code: code, + message: message + ) + self.publish(event) + } + + func publish(_ event: Event) { + guard let shared = UserDefaults(suiteName: self.suiteName), + let data = try? JSONEncoder().encode(event) else { + return + } + + shared.set(data, forKey: self.eventKey) + shared.synchronize() + DarwinNotificationCenter.shared.post(.tunnelEventChanged) + } + + func clear() { + guard let shared = UserDefaults(suiteName: self.suiteName) else { + return + } + + shared.removeObject(forKey: self.eventKey) + shared.synchronize() + DarwinNotificationCenter.shared.post(.tunnelEventChanged) + } +} diff --git a/punchnet/Core/DarwinNotificationCenter.swift b/punchnet/Core/DarwinNotificationCenter.swift index 02b3af4..11b01c6 100644 --- a/punchnet/Core/DarwinNotificationCenter.swift +++ b/punchnet/Core/DarwinNotificationCenter.swift @@ -18,6 +18,7 @@ public struct DarwinNotificationName: RawRepresentable, Hashable { // 预定义名称 extension DarwinNotificationName { static let vpnStatusChanged = DarwinNotificationName(rawValue: "com.jihe.punchnetmac.vpnStatusChanged") + static let tunnelEventChanged = DarwinNotificationName(rawValue: "com.jihe.punchnetmac.tunnelEventChanged") }