Refactor command client
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import Foundation
|
||||
import Libbox
|
||||
|
||||
public class CommandClient: ObservableObject {
|
||||
public enum ConnectionType {
|
||||
case status
|
||||
case groups
|
||||
case log
|
||||
}
|
||||
|
||||
private let connectionType: ConnectionType
|
||||
private let logMaxLines: Int
|
||||
private var commandClient: LibboxCommandClient?
|
||||
private var connectTask: Task<Void, Error>?
|
||||
|
||||
@Published public var isConnected: Bool
|
||||
@Published public var status: LibboxStatusMessage?
|
||||
@Published public var groups: [LibboxOutboundGroup]?
|
||||
@Published public var logList: [String]
|
||||
|
||||
public init(_ connectionType: ConnectionType, logMaxLines: Int = 300) {
|
||||
self.connectionType = connectionType
|
||||
self.logMaxLines = logMaxLines
|
||||
logList = []
|
||||
isConnected = false
|
||||
}
|
||||
|
||||
public func connect() {
|
||||
if isConnected {
|
||||
return
|
||||
}
|
||||
if let connectTask {
|
||||
connectTask.cancel()
|
||||
}
|
||||
connectTask = Task.detached {
|
||||
await self.connect0()
|
||||
}
|
||||
}
|
||||
|
||||
public func disconnect() {
|
||||
if let connectTask {
|
||||
connectTask.cancel()
|
||||
self.connectTask = nil
|
||||
}
|
||||
if let commandClient {
|
||||
try? commandClient.disconnect()
|
||||
self.commandClient = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func connect0() async {
|
||||
let clientOptions = LibboxCommandClientOptions()
|
||||
switch connectionType {
|
||||
case .status:
|
||||
clientOptions.command = LibboxCommandStatus
|
||||
case .groups:
|
||||
clientOptions.command = LibboxCommandGroup
|
||||
case .log:
|
||||
clientOptions.command = LibboxCommandLog
|
||||
}
|
||||
clientOptions.statusInterval = Int64(2 * NSEC_PER_SEC)
|
||||
let client = LibboxNewCommandClient(FilePath.sharedDirectory.relativePath, clientHandler(self), clientOptions)!
|
||||
do {
|
||||
for i in 0 ..< 10 {
|
||||
try await Task.sleep(nanoseconds: UInt64(Double(100 + (i * 50)) * Double(NSEC_PER_MSEC)))
|
||||
try Task.checkCancellation()
|
||||
let isConnected: Bool
|
||||
do {
|
||||
try client.connect()
|
||||
isConnected = true
|
||||
} catch {
|
||||
isConnected = false
|
||||
}
|
||||
try Task.checkCancellation()
|
||||
if isConnected {
|
||||
commandClient = client
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
try? client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private class clientHandler: NSObject, LibboxCommandClientHandlerProtocol {
|
||||
private let commandClient: CommandClient
|
||||
|
||||
init(_ commandClient: CommandClient) {
|
||||
self.commandClient = commandClient
|
||||
}
|
||||
|
||||
func connected() {
|
||||
DispatchQueue.main.sync {
|
||||
self.commandClient.isConnected = true
|
||||
}
|
||||
}
|
||||
|
||||
func disconnected(_: String?) {
|
||||
DispatchQueue.main.sync {
|
||||
self.commandClient.isConnected = false
|
||||
}
|
||||
}
|
||||
|
||||
func writeLog(_ message: String?) {
|
||||
guard let message else {
|
||||
return
|
||||
}
|
||||
var logList = commandClient.logList
|
||||
if logList.count > commandClient.logMaxLines {
|
||||
logList.removeFirst()
|
||||
}
|
||||
logList.append(message)
|
||||
DispatchQueue.main.sync {
|
||||
self.commandClient.logList = logList
|
||||
}
|
||||
}
|
||||
|
||||
func writeStatus(_ message: LibboxStatusMessage?) {
|
||||
DispatchQueue.main.sync {
|
||||
self.commandClient.status = message
|
||||
}
|
||||
}
|
||||
|
||||
func writeGroups(_ groups: LibboxOutboundGroupIteratorProtocol?) {
|
||||
guard let groups else {
|
||||
return
|
||||
}
|
||||
var newGroups: [LibboxOutboundGroup] = []
|
||||
while groups.hasNext() {
|
||||
newGroups.append(groups.next()!)
|
||||
}
|
||||
DispatchQueue.main.sync {
|
||||
self.commandClient.groups = newGroups
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import Foundation
|
||||
|
||||
public class ExtensionEnvironments: ObservableObject {
|
||||
@Published public var logClient = CommandClient(.log)
|
||||
@Published public var extensionProfileLoading = true
|
||||
@Published public var extensionProfile: ExtensionProfile?
|
||||
|
||||
public init() {}
|
||||
|
||||
deinit {
|
||||
logClient.disconnect()
|
||||
}
|
||||
|
||||
public func postReload() {
|
||||
Task.detached {
|
||||
await self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
public func reload() async {
|
||||
if let newProfile = try? await ExtensionProfile.load() {
|
||||
if extensionProfile == nil || extensionProfile?.status == .invalid {
|
||||
newProfile.register()
|
||||
await MainActor.run {
|
||||
extensionProfile = newProfile
|
||||
extensionProfileLoading = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
extensionProfile = nil
|
||||
extensionProfileLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func connectLog() {
|
||||
guard let profile = extensionProfile else {
|
||||
return
|
||||
}
|
||||
if profile.status.isConnected, !logClient.isConnected {
|
||||
logClient.connect()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user