mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 21:36:17 +00:00
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:
@@ -10,6 +10,7 @@ import CoreLocation
|
|||||||
|
|
||||||
class Backgrounder: NSObject, CLLocationManagerDelegate, ObservableObject {
|
class Backgrounder: NSObject, CLLocationManagerDelegate, ObservableObject {
|
||||||
private let manager = CLLocationManager()
|
private let manager = CLLocationManager()
|
||||||
|
var tracking: Bool = false
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
static var shared: Backgrounder = Backgrounder()
|
static var shared: Backgrounder = Backgrounder()
|
||||||
@@ -23,17 +24,19 @@ class Backgrounder: NSObject, CLLocationManagerDelegate, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startBgTracking() {
|
func startBgTracking() {
|
||||||
// guard mana
|
guard !tracking else { return }
|
||||||
|
guard checkPermsStatus() else { return }
|
||||||
manager.allowsBackgroundLocationUpdates = true
|
manager.allowsBackgroundLocationUpdates = true
|
||||||
manager.pausesLocationUpdatesAutomatically = false
|
manager.pausesLocationUpdatesAutomatically = false
|
||||||
manager.startMonitoringSignificantLocationChanges()
|
manager.startMonitoringSignificantLocationChanges()
|
||||||
print("started tgracking")
|
tracking = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopBgTracking() {
|
func stopBgTracking() {
|
||||||
|
guard tracking else { return }
|
||||||
manager.stopUpdatingLocation()
|
manager.stopUpdatingLocation()
|
||||||
manager.allowsBackgroundLocationUpdates = false
|
manager.allowsBackgroundLocationUpdates = false
|
||||||
print("stopped tracking")
|
tracking = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestPerms() {
|
func requestPerms() {
|
||||||
|
|||||||
@@ -25,3 +25,7 @@ enum KeyError: Error {
|
|||||||
case pubkeyRejected
|
case pubkeyRejected
|
||||||
case privkeyRejected
|
case privkeyRejected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ReconnectError: Error {
|
||||||
|
case alreadyConnected
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
return String(cString: cString)
|
return String(cString: cString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func go() {
|
func go(id: UUID = UUID()) {
|
||||||
guard !connected else { disconnect(); return }
|
guard !connected else { disconnect(); return }
|
||||||
|
|
||||||
do { try connect() } catch {
|
do { try connect(id: id) } catch {
|
||||||
print("error when connecting \(error.localizedDescription)")
|
print("error when connecting \(error.localizedDescription)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -108,10 +108,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
setTitle("\(host.username)@\(host.address)")
|
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.") }
|
guard !host.address.isEmpty else { throw .connectionFailed("No address to connect to.") }
|
||||||
withAnimation { state = .connecting }
|
withAnimation { state = .connecting }
|
||||||
sessionID = UUID()
|
sessionID = id
|
||||||
|
|
||||||
var verbosity: Int = 0
|
var verbosity: Int = 0
|
||||||
// var verbosity: Int = SSH_LOG_FUNCTIONS
|
// var verbosity: Int = SSH_LOG_FUNCTIONS
|
||||||
@@ -139,6 +139,11 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reconnect() throws(ReconnectError) {
|
||||||
|
guard !connected else { throw .alreadyConnected }
|
||||||
|
go(id: sessionID!)
|
||||||
|
}
|
||||||
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
// Task {
|
// Task {
|
||||||
self.hostkeyChanged = false
|
self.hostkeyChanged = false
|
||||||
@@ -359,7 +364,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
return nil
|
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)
|
let nbytes = ssh_channel_read_nonblocking(channel, &buffer, UInt32(buffer.count), 0)
|
||||||
|
|
||||||
guard nbytes > 0 else { return nil }
|
guard nbytes > 0 else { return nil }
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ final class SSHTerminalDelegate: TerminalView, Sendable, @preconcurrency Termina
|
|||||||
var handler: SSHHandler?
|
var handler: SSHHandler?
|
||||||
var hostsManager: HostsManager?
|
var hostsManager: HostsManager?
|
||||||
|
|
||||||
|
var readTimer: Timer?
|
||||||
|
|
||||||
public convenience init(frame: CGRect, handler: SSHHandler, hostsManager: HostsManager) {
|
public convenience init(frame: CGRect, handler: SSHHandler, hostsManager: HostsManager) {
|
||||||
self.init(frame: frame)
|
self.init(frame: frame)
|
||||||
|
|
||||||
@@ -97,19 +99,18 @@ final class SSHTerminalDelegate: TerminalView, Sendable, @preconcurrency Termina
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startFeedLoop() {
|
func startFeedLoop() {
|
||||||
Task {
|
guard readTimer == nil else { return }
|
||||||
guard let handler else { return }
|
readTimer = Timer(timeInterval: 0.01, repeats: true) { timer in
|
||||||
while checkShell(handler.state) {
|
Task(priority: .high) {
|
||||||
|
guard let handler = await self.handler else { return }
|
||||||
if let read = handler.readFromChannel() {
|
if let read = handler.readFromChannel() {
|
||||||
await MainActor.run {
|
Task { @MainActor in
|
||||||
self.feed(text: read)
|
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() {
|
func applySelectedTheme() {
|
||||||
|
|||||||
@@ -59,8 +59,9 @@ struct ShellView: View {
|
|||||||
if !checkShell(handler.state) {
|
if !checkShell(handler.state) {
|
||||||
ZStack {
|
ZStack {
|
||||||
RoundedRectangle(cornerRadius: 25)
|
RoundedRectangle(cornerRadius: 25)
|
||||||
.fill(hostsManager.selectedTheme.foreground.suiColor.opacity(0.5))
|
.fill(hostsManager.selectedTheme.foreground.suiColor)
|
||||||
.blur(radius: 5)
|
.opacity(0.5)
|
||||||
|
.blur(radius: 2)
|
||||||
.shadow(color: hostsManager.selectedTheme.foreground.suiColor, radius: 5)
|
.shadow(color: hostsManager.selectedTheme.foreground.suiColor, radius: 5)
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -86,6 +87,8 @@ struct ShellView: View {
|
|||||||
.padding(10)
|
.padding(10)
|
||||||
}
|
}
|
||||||
.fixedSize()
|
.fixedSize()
|
||||||
|
.transition(.opacity)
|
||||||
|
.animation(.spring, value: checkShell(handler.state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user