113 lines
2.9 KiB
Swift
113 lines
2.9 KiB
Swift
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
|
|
}
|
|
}
|