-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathBashQuickViewModel.swift
More file actions
88 lines (72 loc) · 2.5 KB
/
BashQuickViewModel.swift
File metadata and controls
88 lines (72 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import Foundation
import os
private let logger = Logger(subsystem: "com.wisp.app", category: "BashQuick")
@Observable
@MainActor
final class BashQuickViewModel {
let spriteName: String
let workingDirectory: String
var command = ""
private(set) var output = ""
private(set) var isRunning = false
private(set) var error: String?
private(set) var lastCommand = ""
private var streamTask: Task<Void, Never>?
init(spriteName: String, workingDirectory: String) {
self.spriteName = spriteName
self.workingDirectory = workingDirectory
}
func send(apiClient: SpritesAPIClient) {
let cmd = command.trimmingCharacters(in: .whitespacesAndNewlines)
guard !cmd.isEmpty, !isRunning else { return }
lastCommand = cmd
command = ""
output = ""
error = nil
isRunning = true
streamTask = Task {
await executeCommand(cmd, apiClient: apiClient)
}
}
func cancel(apiClient: SpritesAPIClient) {
streamTask?.cancel()
streamTask = nil
isRunning = false
}
func insertFormatted() -> String {
BashQuickViewModel.formatInsert(command: lastCommand, output: output)
}
static func formatInsert(command: String, output: String) -> String {
"```\n$ \(command)\n\(output.trimmingCharacters(in: .newlines))\n```"
}
// MARK: - Private
private func executeCommand(_ cmd: String, apiClient: SpritesAPIClient) async {
let fullCommand = "cd \(workingDirectory) 2>/dev/null || true; \(cmd)"
let session = apiClient.createExecSession(spriteName: spriteName, command: fullCommand)
session.connect()
do {
streamLoop: for try await event in session.events() {
guard !Task.isCancelled else { break streamLoop }
switch event {
case .stdout(let data), .stderr(let data):
if let text = String(data: data, encoding: .utf8) {
output += text
}
case .exit:
break streamLoop
case .sessionInfo:
break
}
}
} catch {
if !Task.isCancelled {
self.error = "Connection error"
logger.error("Bash quick stream error: \(error.localizedDescription)")
}
}
session.disconnect()
if !Task.isCancelled {
isRunning = false
}
}
}