fix context
This commit is contained in:
parent
bba1180b11
commit
43a19c030c
@ -14,36 +14,32 @@ enum TunnelError: Error {
|
||||
}
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
private var runtimeEnv: SDLRuntimeEnvironment?
|
||||
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
// 如果当前在运行状态,不允许重复请求
|
||||
guard self.runtimeEnv == nil else {
|
||||
completionHandler(TunnelError.invalidContext)
|
||||
return
|
||||
private enum RuntimeState {
|
||||
case idle
|
||||
case starting
|
||||
case running
|
||||
case stopping
|
||||
}
|
||||
|
||||
private let runtimeLock = NSLock()
|
||||
private var runtimeState: RuntimeState = .idle
|
||||
private var config: SDLConfiguration?
|
||||
private var rsaCipher: CCRSACipher?
|
||||
private var contextActor: SDLContextActor?
|
||||
private var startCompletionHandler: ((Error?) -> Void)?
|
||||
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
guard let options, let config = SDLConfiguration.parse(options: options) else {
|
||||
completionHandler(TunnelError.invalidConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
if self.runtimeEnv == nil {
|
||||
let rsaCipher = try! CCRSACipher(keySize: 1024)
|
||||
self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self)
|
||||
self.runtimeEnv?.run()
|
||||
}
|
||||
|
||||
self.runtimeEnv?.submitCommand(command: .start(completion: { err in
|
||||
completionHandler(err)
|
||||
}))
|
||||
self.startContext(config: config, rsaCipher: rsaCipher, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
// Add code here to start the process of stopping the tunnel.
|
||||
self.runtimeEnv?.submitCommand(command: .stop(completion: {
|
||||
completionHandler()
|
||||
}))
|
||||
self.stopContext(clearRuntimeConfiguration: true, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
||||
@ -65,29 +61,25 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
}
|
||||
|
||||
override func sleep(completionHandler: @escaping () -> Void) {
|
||||
// Add code here to get ready to sleep.
|
||||
guard let runtimeEnv else {
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
|
||||
runtimeEnv.submitCommand(command: .stop(completion: {
|
||||
self.stopContext(clearRuntimeConfiguration: false) {
|
||||
SDLLogger.log("[PacketTunnelProvider] sleep")
|
||||
completionHandler()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
override func wake() {
|
||||
SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!")
|
||||
// Add code here to wake up.
|
||||
// 重新启动
|
||||
self.runtimeEnv?.submitCommand(command: .start(completion: { err in
|
||||
self.startCachedContext { err in
|
||||
if let err {
|
||||
SDLLogger.log("[PacketTunnelProvider] wakeup start failed: \(err.localizedDescription)")
|
||||
} else {
|
||||
SDLLogger.log("[PacketTunnelProvider] wakeup and try start")
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleAppRequest(message: AppRequest) async throws -> Data? {
|
||||
guard let contextActor = self.runtimeEnv?.getContextActor() else {
|
||||
guard let contextActor = self.currentContextActor() else {
|
||||
throw TunnelError.invalidContext
|
||||
}
|
||||
|
||||
@ -117,3 +109,126 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension PacketTunnelProvider {
|
||||
|
||||
func startCachedContext(completionHandler: @escaping (Error?) -> Void) {
|
||||
self.runtimeLock.lock()
|
||||
let config = self.config
|
||||
let rsaCipher = self.rsaCipher
|
||||
self.runtimeLock.unlock()
|
||||
|
||||
guard let config, let rsaCipher else {
|
||||
completionHandler(TunnelError.invalidConfiguration)
|
||||
return
|
||||
}
|
||||
|
||||
self.startContext(config: config, rsaCipher: rsaCipher, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func startContext(config: SDLConfiguration, rsaCipher: CCRSACipher, completionHandler: @escaping (Error?) -> Void) {
|
||||
self.runtimeLock.lock()
|
||||
switch self.runtimeState {
|
||||
case .idle:
|
||||
SDLTunnelAppNotifier.shared.clear()
|
||||
|
||||
let contextActor = SDLContextActor(
|
||||
provider: self,
|
||||
config: config,
|
||||
rsaCipher: rsaCipher
|
||||
)
|
||||
|
||||
self.config = config
|
||||
self.rsaCipher = rsaCipher
|
||||
self.contextActor = contextActor
|
||||
self.startCompletionHandler = completionHandler
|
||||
self.runtimeState = .starting
|
||||
self.runtimeLock.unlock()
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await contextActor.start()
|
||||
self.finishContextStart(contextActor, error: nil)
|
||||
} catch {
|
||||
self.finishContextStart(contextActor, error: error)
|
||||
}
|
||||
}
|
||||
|
||||
case .starting, .running, .stopping:
|
||||
self.runtimeLock.unlock()
|
||||
completionHandler(TunnelError.invalidContext)
|
||||
}
|
||||
}
|
||||
|
||||
func stopContext(clearRuntimeConfiguration: Bool, completionHandler: @escaping () -> Void) {
|
||||
self.runtimeLock.lock()
|
||||
let contextActor = self.contextActor
|
||||
let startCompletionHandler = self.startCompletionHandler
|
||||
|
||||
guard contextActor != nil else {
|
||||
self.runtimeState = .idle
|
||||
self.startCompletionHandler = nil
|
||||
if clearRuntimeConfiguration {
|
||||
self.config = nil
|
||||
self.rsaCipher = nil
|
||||
}
|
||||
self.runtimeLock.unlock()
|
||||
startCompletionHandler?(TunnelError.invalidContext)
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
|
||||
self.contextActor = nil
|
||||
self.startCompletionHandler = nil
|
||||
self.runtimeState = .stopping
|
||||
if clearRuntimeConfiguration {
|
||||
self.config = nil
|
||||
self.rsaCipher = nil
|
||||
}
|
||||
self.runtimeLock.unlock()
|
||||
|
||||
startCompletionHandler?(TunnelError.invalidContext)
|
||||
|
||||
Task {
|
||||
await contextActor?.stop()
|
||||
self.markContextStopped()
|
||||
completionHandler()
|
||||
}
|
||||
}
|
||||
|
||||
func currentContextActor() -> SDLContextActor? {
|
||||
self.runtimeLock.lock()
|
||||
let contextActor = self.contextActor
|
||||
self.runtimeLock.unlock()
|
||||
return contextActor
|
||||
}
|
||||
|
||||
func finishContextStart(_ contextActor: SDLContextActor, error: Error?) {
|
||||
self.runtimeLock.lock()
|
||||
guard self.contextActor === contextActor else {
|
||||
self.runtimeLock.unlock()
|
||||
return
|
||||
}
|
||||
|
||||
let startCompletionHandler = self.startCompletionHandler
|
||||
self.startCompletionHandler = nil
|
||||
|
||||
if let error {
|
||||
self.contextActor = nil
|
||||
self.runtimeState = .idle
|
||||
} else {
|
||||
self.runtimeState = .running
|
||||
}
|
||||
self.runtimeLock.unlock()
|
||||
|
||||
startCompletionHandler?(error)
|
||||
}
|
||||
|
||||
func markContextStopped() {
|
||||
self.runtimeLock.lock()
|
||||
if self.contextActor == nil {
|
||||
self.runtimeState = .idle
|
||||
}
|
||||
self.runtimeLock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
enum SDLRuntimeEnvironmentCommand {
|
||||
case start(completion: @Sendable (Error?) -> Void)
|
||||
case stop(completion: @Sendable () -> Void)
|
||||
}
|
||||
|
||||
final class SDLRuntimeEnvironment {
|
||||
private enum State {
|
||||
case idle
|
||||
case running
|
||||
}
|
||||
|
||||
private var state: State = .idle
|
||||
private var contextActor: SDLContextActor?
|
||||
|
||||
private var config: SDLConfiguration
|
||||
private let rsaCipher: CCRSACipher
|
||||
private let provider: PacketTunnelProvider
|
||||
|
||||
private let commandStream: AsyncStream<SDLRuntimeEnvironmentCommand>
|
||||
private let commandCont: AsyncStream<SDLRuntimeEnvironmentCommand>.Continuation
|
||||
|
||||
private var commandTask: Task<Void, Never>?
|
||||
|
||||
init(config: SDLConfiguration, rsaCipher: CCRSACipher, provider: PacketTunnelProvider) {
|
||||
self.config = config
|
||||
self.rsaCipher = rsaCipher
|
||||
self.provider = provider
|
||||
|
||||
let pair = AsyncStream.makeStream(of: SDLRuntimeEnvironmentCommand.self)
|
||||
self.commandStream = pair.stream
|
||||
self.commandCont = pair.continuation
|
||||
}
|
||||
|
||||
func submitCommand(command: SDLRuntimeEnvironmentCommand) {
|
||||
self.commandCont.yield(command)
|
||||
}
|
||||
|
||||
func getContextActor() -> SDLContextActor? {
|
||||
self.contextActor
|
||||
}
|
||||
|
||||
func run() {
|
||||
let stream = self.commandStream
|
||||
|
||||
self.commandTask = Task { [weak self] in
|
||||
for await command in stream {
|
||||
guard let self else {
|
||||
break
|
||||
}
|
||||
|
||||
await self.handle(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handle(_ command: SDLRuntimeEnvironmentCommand) async {
|
||||
switch command {
|
||||
case .start(let handler):
|
||||
do {
|
||||
try await self.startCommand()
|
||||
handler(nil)
|
||||
} catch {
|
||||
handler(error)
|
||||
}
|
||||
|
||||
case .stop(let handler):
|
||||
await self.stopCommand()
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
private func startCommand() async throws {
|
||||
switch self.state {
|
||||
case .idle:
|
||||
SDLTunnelAppNotifier.shared.clear()
|
||||
|
||||
let contextActor = SDLContextActor(
|
||||
provider: provider,
|
||||
config: config,
|
||||
rsaCipher: self.rsaCipher
|
||||
)
|
||||
|
||||
self.contextActor = contextActor
|
||||
try await contextActor.start()
|
||||
self.state = .running
|
||||
case .running:
|
||||
SDLLogger.log("[SDLRuntimeEnvironment] is running, ignore start command")
|
||||
}
|
||||
}
|
||||
|
||||
private func stopCommand() async {
|
||||
switch self.state {
|
||||
case .idle:
|
||||
SDLLogger.log("[SDLRuntimeEnvironment] is idle, ignore stop command")
|
||||
|
||||
case .running:
|
||||
let contextActor = self.contextActor
|
||||
self.contextActor = nil
|
||||
self.state = .idle
|
||||
|
||||
await contextActor?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.commandCont.finish()
|
||||
self.commandTask?.cancel()
|
||||
self.commandTask = nil
|
||||
}
|
||||
}
|
||||
@ -171,6 +171,7 @@ actor SDLContextActor {
|
||||
self.rootTask = nil
|
||||
|
||||
rootTask?.cancel()
|
||||
await self.readySignal.fail(CancellationError())
|
||||
_ = try? await rootTask?.value
|
||||
|
||||
await self.cleanupRoot()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user