From f082d8b77c9a27c1b3a0fddd6b9b9d305547f328 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Thu, 26 Jun 2025 15:03:59 +0100 Subject: [PATCH] tried to implement resuming --- ShhShell/Host/HostsManager.swift | 5 +++ ShhShell/SSH/SSHHandler.swift | 5 +++ ShhShell/SSH/SSHState.swift | 17 +++++++++ ShhShell/Views/Hosts/ConnectionView.swift | 17 ++++----- ShhShell/Views/Hosts/HostsView.swift | 2 +- ShhShell/Views/Keys/KeyManagerView.swift | 6 +++- ShhShell/Views/Terminal/SSHTerminalView.swift | 35 +++++++++++++------ ShhShell/Views/Terminal/ShellView.swift | 18 +++++----- .../Views/Terminal/TerminalController.swift | 4 ++- 9 files changed, 78 insertions(+), 31 deletions(-) diff --git a/ShhShell/Host/HostsManager.swift b/ShhShell/Host/HostsManager.swift index 5644cec..afa9cca 100644 --- a/ShhShell/Host/HostsManager.swift +++ b/ShhShell/Host/HostsManager.swift @@ -36,10 +36,15 @@ class HostsManager: ObservableObject, @unchecked Sendable { } func updateHost(_ updatedHost: Host) { + let oldID = updatedHost.id + if let index = savedHosts.firstIndex(where: { $0.id == updatedHost.id }) { var updateHostWithNewID = updatedHost updateHostWithNewID.id = UUID() withAnimation { savedHosts[index] = updateHostWithNewID } + + updateHostWithNewID.id = oldID + withAnimation { savedHosts[index] = updateHostWithNewID } saveSavedHosts() } } diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 0786285..04783cb 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -14,6 +14,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject { private var session: ssh_session? private var channel: ssh_channel? + var scrollback: [String] = [] + @Published var title: String = "" @Published var state: SSHState = .idle var connected: Bool { @@ -393,6 +395,9 @@ class SSHHandler: @unchecked Sendable, ObservableObject { #if DEBUG // print(String(data: Data(bytes: buffer, count: Int(nbytes)), encoding: .utf8)!) #endif + Task { @MainActor in + scrollback.append(string) + } return string } return nil diff --git a/ShhShell/SSH/SSHState.swift b/ShhShell/SSH/SSHState.swift index a3fc09d..3933348 100644 --- a/ShhShell/SSH/SSHState.swift +++ b/ShhShell/SSH/SSHState.swift @@ -6,6 +6,7 @@ // import Foundation +import SwiftUI enum SSHState { case idle @@ -16,6 +17,22 @@ enum SSHState { case connectionFailed case authFailed + + var color: Color { + switch self { + case .idle: + return .gray + + case .connecting, .authorizing: + return .orange + + case .authorized, .shellOpen: + return .green + + case .connectionFailed, .authFailed: + return .red + } + } } func checkConnected(_ state: SSHState) -> Bool { diff --git a/ShhShell/Views/Hosts/ConnectionView.swift b/ShhShell/Views/Hosts/ConnectionView.swift index 50b1c81..6cd7d4c 100644 --- a/ShhShell/Views/Hosts/ConnectionView.swift +++ b/ShhShell/Views/Hosts/ConnectionView.swift @@ -12,6 +12,8 @@ struct ConnectionView: View { @ObservedObject var hostsManager: HostsManager @ObservedObject var keyManager: KeyManager + @State var resuming: Bool = false + @State var passphrase: String = "" @State var pubkeyStr: String = "" @@ -54,14 +56,8 @@ struct ConnectionView: View { } } Section { - HStack { - Text(handler.connected ? "connected" : "not connected") - .modifier(foregroundColorStyle(handler.connected ? .green : .red)) - - Text(checkAuth(handler.state) ? "authorized" : "unauthorized") - .modifier(foregroundColorStyle(checkAuth(handler.state) ? .green : .red)) - Text("\(handler.state)") - } + Text("\(handler.state)") + .foregroundStyle(handler.state.color) TextField("name", text: $handler.host.name) .textFieldStyle(.roundedBorder) @@ -116,6 +112,7 @@ struct ConnectionView: View { Button() { showTerminal.toggle() + resuming = true } label: { Label("Show Terminal", systemImage: "apple.terminal") } @@ -162,7 +159,7 @@ struct ConnectionView: View { } } .fullScreenCover(isPresented: $showTerminal) { - ShellView(handler: handler) + ShellView(handler: handler, resuming: resuming) } .onChange(of: handler.host.key) { _ in guard let previousKnownHost = hostsManager.getHostMatching(handler.host) else { return } @@ -172,7 +169,7 @@ struct ConnectionView: View { } } .onDisappear { - hostsManager.updateHost(handler.host) +// hostsManager.updateHost(handler.host) } .task { if let publicKeyData = handler.host.publicKey { diff --git a/ShhShell/Views/Hosts/HostsView.swift b/ShhShell/Views/Hosts/HostsView.swift index eafde56..e171c74 100644 --- a/ShhShell/Views/Hosts/HostsView.swift +++ b/ShhShell/Views/Hosts/HostsView.swift @@ -29,7 +29,7 @@ struct HostsView: View { NavigationLink() { ForEach(hostsManager.savedHosts) { host in let miniHandler = SSHHandler(host: host) - TerminalController(handler: miniHandler) + TerminalController(handler: miniHandler, resuming: false) .onAppear { miniHandler.go() } } } label: { diff --git a/ShhShell/Views/Keys/KeyManagerView.swift b/ShhShell/Views/Keys/KeyManagerView.swift index 96ce9bb..12ca671 100644 --- a/ShhShell/Views/Keys/KeyManagerView.swift +++ b/ShhShell/Views/Keys/KeyManagerView.swift @@ -46,7 +46,11 @@ struct KeyManagerView: View { } ForEach(hostsManager.savedHosts) { host in VStack(alignment: .leading) { - Text(host.name + "\n" + host.address) + if !host.name.isEmpty { + Text(host.name) + .bold() + } + Text(host.address) .bold() Text(host.key ?? "nil") } diff --git a/ShhShell/Views/Terminal/SSHTerminalView.swift b/ShhShell/Views/Terminal/SSHTerminalView.swift index fb568e2..047ff93 100644 --- a/ShhShell/Views/Terminal/SSHTerminalView.swift +++ b/ShhShell/Views/Terminal/SSHTerminalView.swift @@ -12,25 +12,34 @@ import SwiftTerm @MainActor final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalViewDelegate { var handler: SSHHandler? - var sshQueue: DispatchQueue + var sshQueue = DispatchQueue(label: "sshQueue") + var resuming: Bool - public convenience init(frame: CGRect, handler: SSHHandler) { + public convenience init(frame: CGRect, handler: SSHHandler, resuming: Bool) { self.init(frame: frame) self.handler = handler - } - - public override init(frame: CGRect) { - sshQueue = DispatchQueue(label: "sshQueue") - - super.init(frame: frame) - terminalDelegate = self + self.resuming = resuming + sshQueue.async { + Task { + if resuming { + if let handler = await self.handler { + for chunk in handler.scrollback { + await MainActor.run { + self.feed(text: chunk) + } + } + } + } + } + } + sshQueue.async { Task { guard let handler = await self.handler else { return } while handler.connected { if let read = handler.readFromChannel() { - Task { @MainActor in + await MainActor.run { self.feed(text: read) } } else { @@ -42,6 +51,12 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie } } + public override init(frame: CGRect) { + self.resuming = false + super.init(frame: frame) + terminalDelegate = self + } + required init?(coder: NSCoder) { fatalError("unimplemented") } diff --git a/ShhShell/Views/Terminal/ShellView.swift b/ShhShell/Views/Terminal/ShellView.swift index dc7f792..cb1c874 100644 --- a/ShhShell/Views/Terminal/ShellView.swift +++ b/ShhShell/Views/Terminal/ShellView.swift @@ -9,6 +9,8 @@ import SwiftUI struct ShellView: View { @ObservedObject var handler: SSHHandler + @State var resuming: Bool = false + @Environment(\.dismiss) var dismiss @State private var terminalControllerRef: TerminalController? @@ -31,7 +33,7 @@ struct ShellView: View { } } .task { - terminalControllerRef = TerminalController(handler: handler) + terminalControllerRef = TerminalController(handler: handler, resuming: resuming) } .toolbar { ToolbarItem { @@ -43,13 +45,13 @@ struct ShellView: View { } } //TODO: FIX -// ToolbarItem(placement: .cancellationAction) { -// Button() { -// dismiss() -// } label: { -// Label("Close", systemImage: "arrow.down.right.and.arrow.up.left") -// } -// } + ToolbarItem(placement: .cancellationAction) { + Button() { + dismiss() + } label: { + Label("Close", systemImage: "arrow.down.right.and.arrow.up.left") + } + } } .onChange(of: handler.connected) { _ in if !handler.connected { dismiss() } diff --git a/ShhShell/Views/Terminal/TerminalController.swift b/ShhShell/Views/Terminal/TerminalController.swift index 247511c..6fdb652 100644 --- a/ShhShell/Views/Terminal/TerminalController.swift +++ b/ShhShell/Views/Terminal/TerminalController.swift @@ -12,6 +12,7 @@ import SwiftTerm struct TerminalController: UIViewRepresentable { @ObservedObject var handler: SSHHandler + @State var resuming: Bool func makeUIView(context: Context) -> TerminalView { let tv = SSHTerminalView( @@ -19,7 +20,8 @@ struct TerminalController: UIViewRepresentable { origin: CGPoint(x: 0, y: 0), size: .zero ), - handler: handler + handler: handler, + resuming: resuming ) tv.translatesAutoresizingMaskIntoConstraints = false