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
This commit is contained in:
neon443
2025-09-01 18:49:48 +01:00
parent ff02122bcc
commit 68fb7d4844
5 changed files with 33 additions and 17 deletions

View File

@@ -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() {

View File

@@ -25,3 +25,7 @@ enum KeyError: Error {
case pubkeyRejected
case privkeyRejected
}
enum ReconnectError: Error {
case alreadyConnected
}

View File

@@ -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 }

View File

@@ -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() {

View File

@@ -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))
}
}
}