fix Context
This commit is contained in:
parent
af140f7da6
commit
3a6b04aa9b
@ -41,6 +41,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||||||
|
|
||||||
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
|
self.contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
|
||||||
await self.contextActor?.start()
|
await self.contextActor?.start()
|
||||||
|
try await self.contextActor?.waitForReady()
|
||||||
|
|
||||||
completionHandler(nil)
|
completionHandler(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,17 @@ actor SDLContextActor {
|
|||||||
case registered
|
case registered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ReadyState {
|
||||||
|
case idle
|
||||||
|
case starting
|
||||||
|
case ready
|
||||||
|
case failed(any Error)
|
||||||
|
case stopped
|
||||||
|
}
|
||||||
|
|
||||||
private var state: State = .unregistered
|
private var state: State = .unregistered
|
||||||
|
private var readyState: ReadyState = .idle
|
||||||
|
private var readyWaiters: [CheckedContinuation<Void, Error>] = []
|
||||||
|
|
||||||
var config: SDLConfiguration
|
var config: SDLConfiguration
|
||||||
// nat的网络类型
|
// nat的网络类型
|
||||||
@ -103,6 +113,11 @@ actor SDLContextActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func start() async {
|
public func start() async {
|
||||||
|
guard case .idle = self.readyState else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.readyState = .starting
|
||||||
self.startMonitor()
|
self.startMonitor()
|
||||||
|
|
||||||
// 启动arp的定时清理任务
|
// 启动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
|
// 取消出口节点的时候,ip地址为: 0.0.0.0
|
||||||
public func updateExitNode(exitNodeIp: String) async throws {
|
public func updateExitNode(exitNodeIp: String) async throws {
|
||||||
if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 {
|
if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 {
|
||||||
@ -338,6 +368,9 @@ actor SDLContextActor {
|
|||||||
|
|
||||||
// 处理context的停止问题
|
// 处理context的停止问题
|
||||||
public func stop() async {
|
public func stop() async {
|
||||||
|
self.resumeReadyWaiters(.failure(CancellationError()))
|
||||||
|
self.readyState = .stopped
|
||||||
|
|
||||||
await self.supervisor.stop()
|
await self.supervisor.stop()
|
||||||
|
|
||||||
self.udpHoleWorkers?.forEach { $0.cancel() }
|
self.udpHoleWorkers?.forEach { $0.cancel() }
|
||||||
@ -427,7 +460,9 @@ actor SDLContextActor {
|
|||||||
// 需要对数据通过rsa的私钥解码
|
// 需要对数据通过rsa的私钥解码
|
||||||
guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else {
|
guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else {
|
||||||
SDLLogger.log("[SDLContext] registerSuperAck invalid key")
|
SDLLogger.log("[SDLContext] registerSuperAck invalid key")
|
||||||
self.provider.cancelTunnelWithError(SDLError.invalidKey)
|
let error = SDLError.invalidKey
|
||||||
|
self.failReady(error)
|
||||||
|
self.provider.cancelTunnelWithError(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +477,9 @@ actor SDLContextActor {
|
|||||||
self.dataCipher = CCChaCha20Cipher(regionId: regionId, keyData: key)
|
self.dataCipher = CCChaCha20Cipher(regionId: regionId, keyData: key)
|
||||||
default:
|
default:
|
||||||
SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)")
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,8 +490,10 @@ actor SDLContextActor {
|
|||||||
SDLLogger.log("[SDLContext] setNetworkSettings successed")
|
SDLLogger.log("[SDLContext] setNetworkSettings successed")
|
||||||
self.state = .registered
|
self.state = .registered
|
||||||
self.startReader()
|
self.startReader()
|
||||||
|
self.markReady()
|
||||||
} catch let err {
|
} catch let err {
|
||||||
SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)")
|
SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)")
|
||||||
|
self.failReady(err)
|
||||||
self.provider.cancelTunnelWithError(err)
|
self.provider.cancelTunnelWithError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,6 +510,7 @@ actor SDLContextActor {
|
|||||||
self.noticeClient?.send(data: alertNotice)
|
self.noticeClient?.send(data: alertNotice)
|
||||||
// 报告错误并退出
|
// 报告错误并退出
|
||||||
let error = NSError(domain: "com.jihe.punchnet.tun", code: -1)
|
let error = NSError(domain: "com.jihe.punchnet.tun", code: -1)
|
||||||
|
self.failReady(error)
|
||||||
self.provider.cancelTunnelWithError(error)
|
self.provider.cancelTunnelWithError(error)
|
||||||
|
|
||||||
case .noIpAddress, .networkFault, .internalFault:
|
case .noIpAddress, .networkFault, .internalFault:
|
||||||
@ -504,6 +544,7 @@ actor SDLContextActor {
|
|||||||
|
|
||||||
// 报告错误并退出
|
// 报告错误并退出
|
||||||
let error = NSError(domain: "com.jihe.punchnet.tun", code: -2)
|
let error = NSError(domain: "com.jihe.punchnet.tun", code: -2)
|
||||||
|
self.failReady(error)
|
||||||
self.provider.cancelTunnelWithError(error)
|
self.provider.cancelTunnelWithError(error)
|
||||||
case .none:
|
case .none:
|
||||||
()
|
()
|
||||||
@ -911,6 +952,39 @@ actor SDLContextActor {
|
|||||||
return ipv4DnsServers.map { NEIPv4Route(destinationAddress: $0, subnetMask: "255.255.255.255") }
|
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 {
|
deinit {
|
||||||
self.udpHole = nil
|
self.udpHole = nil
|
||||||
self.dnsClient = nil
|
self.dnsClient = nil
|
||||||
|
|||||||
@ -17,6 +17,18 @@ extension SDLAPIClient {
|
|||||||
let identityId: UInt32
|
let identityId: UInt32
|
||||||
let resourceList: [Resource]
|
let resourceList: [Resource]
|
||||||
let nodeList: [Node]
|
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 {
|
struct Resource: Codable {
|
||||||
@ -85,6 +97,7 @@ extension SDLAPIClient {
|
|||||||
case identityId = "identity_id"
|
case identityId = "identity_id"
|
||||||
case resourceList = "resource_list"
|
case resourceList = "resource_list"
|
||||||
case nodeList = "node_list"
|
case nodeList = "node_list"
|
||||||
|
case exitNodeList = "exit_node"
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNode(id: Int?) -> Node? {
|
func getNode(id: Int?) -> Node? {
|
||||||
|
|||||||
@ -10,17 +10,6 @@ extension SDLAPIClient {
|
|||||||
|
|
||||||
// 登陆后的网络会话信息
|
// 登陆后的网络会话信息
|
||||||
struct NetworkSession: Codable {
|
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 accessToken: String
|
||||||
let username: String
|
let username: String
|
||||||
let userType: String
|
let userType: String
|
||||||
@ -28,7 +17,6 @@ extension SDLAPIClient {
|
|||||||
let networkId: Int
|
let networkId: Int
|
||||||
let networkName: String
|
let networkName: String
|
||||||
let networkDomain: String
|
let networkDomain: String
|
||||||
let exitNodes: [ExitNode]
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
var networkUrl: String {
|
var networkUrl: String {
|
||||||
@ -43,7 +31,6 @@ extension SDLAPIClient {
|
|||||||
case networkId = "network_id"
|
case networkId = "network_id"
|
||||||
case networkName = "network_name"
|
case networkName = "network_name"
|
||||||
case networkDomain = "network_domain"
|
case networkDomain = "network_domain"
|
||||||
case exitNodes = "exit_node"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ struct SettingsNetworkView: View {
|
|||||||
@Environment(AppContext.self) var appContext: AppContext
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
@Environment(\.openURL) var openURL
|
@Environment(\.openURL) var openURL
|
||||||
|
|
||||||
@State private var selectedExitNode: SDLAPIClient.NetworkSession.ExitNode?
|
@State private var selectedExitNode: SDLAPIClient.NetworkContext.ExitNode?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
@ -73,7 +73,7 @@ struct SettingsNetworkView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
ForEach(networkSession.exitNodes, id: \.uuid) { node in
|
ForEach(appContext.networkContext?.exitNodeList ?? [], id: \.uuid) { node in
|
||||||
Button {
|
Button {
|
||||||
self.selectedExitNode = node
|
self.selectedExitNode = node
|
||||||
} label: {
|
} label: {
|
||||||
@ -113,7 +113,7 @@ struct SettingsNetworkView: View {
|
|||||||
.frame(maxWidth: 600, alignment: .leading)
|
.frame(maxWidth: 600, alignment: .leading)
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
self.selectedExitNode = self.appContext.networkSession?.exitNodes.first
|
self.selectedExitNode = self.appContext.networkContext?.exitNodeList.first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user