From 68fb7d4844025726c29e7c207112c20aabffd618 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Mon, 1 Sep 2025 18:49:48 +0100 Subject: [PATCH] Added support for reconnecting to a server, using the same terminal added reconnect() to sshhandler added support to go() and connect() to use an arbritrary sessionID redid readloop in sshterminaldelegate to use a timer, instead of a while loop in a Task, allowsfor one readloop per terminal instead updated the ui for the disconnected alert increased max read size from 1024 to added reconnecterror updated tracker to remove print statements and exit start/stop tracking funcs early if tracking/not tracking --- ShhShell/Misc/Backgrounder.swift | 9 ++++++--- ShhShell/SSH/SSHError.swift | 4 ++++ ShhShell/SSH/SSHHandler.swift | 15 ++++++++++----- ShhShell/Terminal/SSHTerminalDelegate.swift | 15 ++++++++------- ShhShell/Views/Terminal/ShellView.swift | 7 +++++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/ShhShell/Misc/Backgrounder.swift b/ShhShell/Misc/Backgrounder.swift index 4b07b3d..d0c56c3 100644 --- a/ShhShell/Misc/Backgrounder.swift +++ b/ShhShell/Misc/Backgrounder.swift @@ -10,6 +10,7 @@ import CoreLocation class Backgrounder: NSObject, CLLocationManagerDelegate, ObservableObject { private let manager = CLLocationManager() + var tracking: Bool = false @MainActor static var shared: Backgrounder = Backgrounder() @@ -23,17 +24,19 @@ class Backgrounder: NSObject, CLLocationManagerDelegate, ObservableObject { } func startBgTracking() { -// guard mana + guard !tracking else { return } + guard checkPermsStatus() else { return } manager.allowsBackgroundLocationUpdates = true manager.pausesLocationUpdatesAutomatically = false manager.startMonitoringSignificantLocationChanges() - print("started tgracking") + tracking = true } func stopBgTracking() { + guard tracking else { return } manager.stopUpdatingLocation() manager.allowsBackgroundLocationUpdates = false - print("stopped tracking") + tracking = false } func requestPerms() { diff --git a/ShhShell/SSH/SSHError.swift b/ShhShell/SSH/SSHError.swift index dfcc04a..374f572 100644 --- a/ShhShell/SSH/SSHError.swift +++ b/ShhShell/SSH/SSHError.swift @@ -25,3 +25,7 @@ enum KeyError: Error { case pubkeyRejected case privkeyRejected } + +enum ReconnectError: Error { + case alreadyConnected +} diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 01d9292..1272bb5 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -59,10 +59,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject { return String(cString: cString) } - func go() { + func go(id: UUID = UUID()) { guard !connected else { disconnect(); return } - do { try connect() } catch { + do { try connect(id: id) } catch { print("error when connecting \(error.localizedDescription)") return } @@ -108,10 +108,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject { setTitle("\(host.username)@\(host.address)") } - func connect() throws(SSHError) { + func connect(id: UUID) throws(SSHError) { guard !host.address.isEmpty else { throw .connectionFailed("No address to connect to.") } withAnimation { state = .connecting } - sessionID = UUID() + sessionID = id var verbosity: Int = 0 // var verbosity: Int = SSH_LOG_FUNCTIONS @@ -139,6 +139,11 @@ class SSHHandler: @unchecked Sendable, ObservableObject { return } + func reconnect() throws(ReconnectError) { + guard !connected else { throw .alreadyConnected } + go(id: sessionID!) + } + func disconnect() { // Task { self.hostkeyChanged = false @@ -359,7 +364,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject { return nil } - var buffer: [CChar] = Array(repeating: 0, count: 1024) + var buffer: [CChar] = Array(repeating: 0, count: 4096) let nbytes = ssh_channel_read_nonblocking(channel, &buffer, UInt32(buffer.count), 0) guard nbytes > 0 else { return nil } diff --git a/ShhShell/Terminal/SSHTerminalDelegate.swift b/ShhShell/Terminal/SSHTerminalDelegate.swift index de668e2..1dd7450 100644 --- a/ShhShell/Terminal/SSHTerminalDelegate.swift +++ b/ShhShell/Terminal/SSHTerminalDelegate.swift @@ -14,6 +14,8 @@ final class SSHTerminalDelegate: TerminalView, Sendable, @preconcurrency Termina var handler: SSHHandler? var hostsManager: HostsManager? + var readTimer: Timer? + public convenience init(frame: CGRect, handler: SSHHandler, hostsManager: HostsManager) { self.init(frame: frame) @@ -97,19 +99,18 @@ final class SSHTerminalDelegate: TerminalView, Sendable, @preconcurrency Termina } func startFeedLoop() { - Task { - guard let handler else { return } - while checkShell(handler.state) { + guard readTimer == nil else { return } + readTimer = Timer(timeInterval: 0.01, repeats: true) { timer in + Task(priority: .high) { + guard let handler = await self.handler else { return } if let read = handler.readFromChannel() { - await MainActor.run { + Task { @MainActor in self.feed(text: read) } - } else { - try? await Task.sleep(nanoseconds: 10_000_000) //10ms } } - print("task end?") } + RunLoop.main.add(readTimer!, forMode: .common) } func applySelectedTheme() { diff --git a/ShhShell/Views/Terminal/ShellView.swift b/ShhShell/Views/Terminal/ShellView.swift index e178c7e..d7456a2 100644 --- a/ShhShell/Views/Terminal/ShellView.swift +++ b/ShhShell/Views/Terminal/ShellView.swift @@ -59,8 +59,9 @@ struct ShellView: View { if !checkShell(handler.state) { ZStack { RoundedRectangle(cornerRadius: 25) - .fill(hostsManager.selectedTheme.foreground.suiColor.opacity(0.5)) - .blur(radius: 5) + .fill(hostsManager.selectedTheme.foreground.suiColor) + .opacity(0.5) + .blur(radius: 2) .shadow(color: hostsManager.selectedTheme.foreground.suiColor, radius: 5) VStack { HStack { @@ -86,6 +87,8 @@ struct ShellView: View { .padding(10) } .fixedSize() + .transition(.opacity) + .animation(.spring, value: checkShell(handler.state)) } } }