fix Context

This commit is contained in:
anlicheng 2026-04-13 17:09:29 +08:00
parent af140f7da6
commit 3a6b04aa9b
5 changed files with 94 additions and 18 deletions

View File

@ -41,6 +41,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
await self.contextActor?.start()
try await self.contextActor?.waitForReady()
completionHandler(nil)
}
}

View File

@ -19,7 +19,17 @@ actor SDLContextActor {
case registered
}
enum ReadyState {
case idle
case starting
case ready
case failed(any Error)
case stopped
}
private var state: State = .unregistered
private var readyState: ReadyState = .idle
private var readyWaiters: [CheckedContinuation<Void, Error>] = []
var config: SDLConfiguration
// nat
@ -103,6 +113,11 @@ actor SDLContextActor {
}
public func start() async {
guard case .idle = self.readyState else {
return
}
self.readyState = .starting
self.startMonitor()
// arp
@ -133,6 +148,21 @@ actor SDLContextActor {
}
}
public func waitForReady() async throws {
switch self.readyState {
case .ready:
return
case .failed(let error):
throw error
case .stopped:
throw CancellationError()
case .idle, .starting:
try await withCheckedThrowingContinuation { continuation in
self.readyWaiters.append(continuation)
}
}
}
// ip: 0.0.0.0
public func updateExitNode(exitNodeIp: String) async throws {
if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 {
@ -338,6 +368,9 @@ actor SDLContextActor {
// context
public func stop() async {
self.resumeReadyWaiters(.failure(CancellationError()))
self.readyState = .stopped
await self.supervisor.stop()
self.udpHoleWorkers?.forEach { $0.cancel() }
@ -427,7 +460,9 @@ actor SDLContextActor {
// rsa
guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else {
SDLLogger.log("[SDLContext] registerSuperAck invalid key")
self.provider.cancelTunnelWithError(SDLError.invalidKey)
let error = SDLError.invalidKey
self.failReady(error)
self.provider.cancelTunnelWithError(error)
return
}
@ -442,7 +477,9 @@ actor SDLContextActor {
self.dataCipher = CCChaCha20Cipher(regionId: regionId, keyData: key)
default:
SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)")
self.provider.cancelTunnelWithError(SDLError.unsupportedAlgorithm(algorithm: algorithm))
let error = SDLError.unsupportedAlgorithm(algorithm: algorithm)
self.failReady(error)
self.provider.cancelTunnelWithError(error)
return
}
@ -453,8 +490,10 @@ actor SDLContextActor {
SDLLogger.log("[SDLContext] setNetworkSettings successed")
self.state = .registered
self.startReader()
self.markReady()
} catch let err {
SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)")
self.failReady(err)
self.provider.cancelTunnelWithError(err)
}
}
@ -471,6 +510,7 @@ actor SDLContextActor {
self.noticeClient?.send(data: alertNotice)
// 退
let error = NSError(domain: "com.jihe.punchnet.tun", code: -1)
self.failReady(error)
self.provider.cancelTunnelWithError(error)
case .noIpAddress, .networkFault, .internalFault:
@ -504,6 +544,7 @@ actor SDLContextActor {
// 退
let error = NSError(domain: "com.jihe.punchnet.tun", code: -2)
self.failReady(error)
self.provider.cancelTunnelWithError(error)
case .none:
()
@ -911,6 +952,39 @@ actor SDLContextActor {
return ipv4DnsServers.map { NEIPv4Route(destinationAddress: $0, subnetMask: "255.255.255.255") }
}
private func markReady() {
guard case .starting = self.readyState else {
return
}
self.readyState = .ready
self.resumeReadyWaiters(.success(()))
}
private func failReady(_ error: any Error) {
switch self.readyState {
case .ready, .failed, .stopped:
return
case .idle, .starting:
self.readyState = .failed(error)
self.resumeReadyWaiters(.failure(error))
}
}
private func resumeReadyWaiters(_ result: Result<Void, any Error>) {
let waiters = self.readyWaiters
self.readyWaiters.removeAll()
waiters.forEach { continuation in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
deinit {
self.udpHole = nil
self.dnsClient = nil

View File

@ -17,6 +17,18 @@ extension SDLAPIClient {
let identityId: UInt32
let resourceList: [Resource]
let nodeList: [Node]
let exitNodeList: [ExitNode]
struct ExitNode: Codable {
let uuid = UUID().uuidString
let nnid: Int
let nodeName: String
enum CodingKeys: String, CodingKey {
case nnid = "node_id"
case nodeName = "node_name"
}
}
//
struct Resource: Codable {
@ -85,6 +97,7 @@ extension SDLAPIClient {
case identityId = "identity_id"
case resourceList = "resource_list"
case nodeList = "node_list"
case exitNodeList = "exit_node"
}
func getNode(id: Int?) -> Node? {

View File

@ -10,17 +10,6 @@ extension SDLAPIClient {
//
struct NetworkSession: Codable {
struct ExitNode: Codable {
let uuid = UUID().uuidString
let nnid: Int
let nodeName: String
enum CodingKeys: String, CodingKey {
case nnid = "node_id"
case nodeName = "node_name"
}
}
let accessToken: String
let username: String
let userType: String
@ -28,7 +17,6 @@ extension SDLAPIClient {
let networkId: Int
let networkName: String
let networkDomain: String
let exitNodes: [ExitNode]
// TODO
var networkUrl: String {
@ -43,7 +31,6 @@ extension SDLAPIClient {
case networkId = "network_id"
case networkName = "network_name"
case networkDomain = "network_domain"
case exitNodes = "exit_node"
}
}

View File

@ -10,7 +10,7 @@ struct SettingsNetworkView: View {
@Environment(AppContext.self) var appContext: AppContext
@Environment(\.openURL) var openURL
@State private var selectedExitNode: SDLAPIClient.NetworkSession.ExitNode?
@State private var selectedExitNode: SDLAPIClient.NetworkContext.ExitNode?
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
@ -73,7 +73,7 @@ struct SettingsNetworkView: View {
Spacer()
Menu {
ForEach(networkSession.exitNodes, id: \.uuid) { node in
ForEach(appContext.networkContext?.exitNodeList ?? [], id: \.uuid) { node in
Button {
self.selectedExitNode = node
} label: {
@ -113,7 +113,7 @@ struct SettingsNetworkView: View {
.frame(maxWidth: 600, alignment: .leading)
}
.onAppear {
self.selectedExitNode = self.appContext.networkSession?.exitNodes.first
self.selectedExitNode = self.appContext.networkContext?.exitNodeList.first
}
}