// // 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) } }