// // VPNManager.swift // sdlan // // Created by 安礼成 on 2024/1/17. // import Foundation import NetworkExtension import SwiftUI import Observation // vpn管理类 @Observable class VPNManager { static let shared = VPNManager() private var manager: NETunnelProviderManager? private var statusObserver: NSObjectProtocol? var vpnStatus: VPNStatus = .disconnected var vpnStatusStream: AsyncStream private var vpnStatusCont: AsyncStream.Continuation enum VPNStatus { case connected case disconnected } private init() { (self.vpnStatusStream, self.vpnStatusCont) = AsyncStream.makeStream(of: VPNStatus.self) } // 开启vpn func enableVpn(options: [String : NSObject]) async throws { NSLog("enable vpn with options: \(options)") let manager = try await loadAndCreateProviderManager() try await manager.loadFromPreferences() self.manager = manager self.addVPNStatusObserver(manager) try manager.connection.startVPNTunnel(options: options) } // 关闭vpn func disableVpn() async throws { guard let manager = self.manager else { return } try await manager.loadFromPreferences() manager.connection.stopVPNTunnel() } // MARK: - Private Methods // 监控系统VPN的状态的变化 private func addVPNStatusObserver(_ manager: NETunnelProviderManager) { if let statusObserver { NotificationCenter.default.removeObserver(statusObserver) self.statusObserver = nil } self.statusObserver = NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: manager.connection, queue: .main) {[weak self] _ in NSLog("status channge: \(manager.connection.status)") switch manager.connection.status { case .invalid, .disconnected, .disconnecting: self?.vpnStatusCont.yield(.disconnected) self?.vpnStatus = .disconnected case .connecting, .connected, .reasserting: self?.vpnStatusCont.yield(.connected) self?.vpnStatus = .connected @unknown default: self?.vpnStatusCont.yield(.disconnected) self?.vpnStatus = .disconnected } } } // MARK: - Private Methods // 加载或者创建相关的配置 private func loadAndCreateProviderManager() async throws -> NETunnelProviderManager { let managers = try await NETunnelProviderManager.loadAllFromPreferences() let manager = managers.first ?? NETunnelProviderManager() manager.localizedDescription = "punchnetmac" manager.isEnabled = true // 设置相关参数,在PacketTunnel中可以用 let protocolConfiguration = NETunnelProviderProtocol() protocolConfiguration.serverAddress = "punchnetmac" protocolConfiguration.providerConfiguration = [String:AnyObject]() protocolConfiguration.providerBundleIdentifier = "com.jihe.punchnetmac.tun" manager.protocolConfiguration = protocolConfiguration manager.isOnDemandEnabled = false manager.isEnabled = true try await manager.saveToPreferences() return manager } deinit { if let statusObserver { NotificationCenter.default.removeObserver(statusObserver) } } }