heyvm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +621 -0
- package/bin/file-browser +0 -0
- package/bin/heyvm +0 -0
- package/bin/heyvm-core +0 -0
- package/bin/heyvm.js +61 -0
- package/core/README.md +51 -0
- package/core/cmd/heyvm-core/main.go +73 -0
- package/core/go.mod +25 -0
- package/core/go.sum +47 -0
- package/core/internal/auth/errors.go +29 -0
- package/core/internal/auth/password.go +187 -0
- package/core/internal/auth/provider.go +33 -0
- package/core/internal/auth/ssh_key.go +142 -0
- package/core/internal/config/config.go +111 -0
- package/core/internal/ipc/actions.go +738 -0
- package/core/internal/ipc/handler.go +281 -0
- package/core/internal/ipc/protocol.go +126 -0
- package/core/internal/sftp/errors.go +29 -0
- package/core/internal/sftp/manager.go +303 -0
- package/core/internal/sftp/types.go +30 -0
- package/core/internal/ssh/errors.go +23 -0
- package/core/internal/ssh/manager.go +226 -0
- package/core/internal/ssh/session.go +105 -0
- package/core/internal/vm/errors.go +35 -0
- package/core/internal/vm/models.go +84 -0
- package/core/internal/vm/registry.go +240 -0
- package/package.json +59 -0
- package/scripts/install.js +100 -0
- package/ui/README.md +43 -0
- package/ui/dist/App.d.ts +3 -0
- package/ui/dist/App.d.ts.map +1 -0
- package/ui/dist/App.js +142 -0
- package/ui/dist/App.js.map +1 -0
- package/ui/dist/components/ConfirmDialog.d.ts +9 -0
- package/ui/dist/components/ConfirmDialog.d.ts.map +1 -0
- package/ui/dist/components/ConfirmDialog.js +22 -0
- package/ui/dist/components/ConfirmDialog.js.map +1 -0
- package/ui/dist/components/ErrorMessage.d.ts +8 -0
- package/ui/dist/components/ErrorMessage.d.ts.map +1 -0
- package/ui/dist/components/ErrorMessage.js +10 -0
- package/ui/dist/components/ErrorMessage.js.map +1 -0
- package/ui/dist/components/Header.d.ts +8 -0
- package/ui/dist/components/Header.d.ts.map +1 -0
- package/ui/dist/components/Header.js +10 -0
- package/ui/dist/components/Header.js.map +1 -0
- package/ui/dist/components/LoadingSpinner.d.ts +7 -0
- package/ui/dist/components/LoadingSpinner.d.ts.map +1 -0
- package/ui/dist/components/LoadingSpinner.js +7 -0
- package/ui/dist/components/LoadingSpinner.js.map +1 -0
- package/ui/dist/components/StatusBar.d.ts +11 -0
- package/ui/dist/components/StatusBar.d.ts.map +1 -0
- package/ui/dist/components/StatusBar.js +11 -0
- package/ui/dist/components/StatusBar.js.map +1 -0
- package/ui/dist/core/ipc.d.ts +96 -0
- package/ui/dist/core/ipc.d.ts.map +1 -0
- package/ui/dist/core/ipc.js +310 -0
- package/ui/dist/core/ipc.js.map +1 -0
- package/ui/dist/core/types.d.ts +45 -0
- package/ui/dist/core/types.d.ts.map +1 -0
- package/ui/dist/core/types.js +3 -0
- package/ui/dist/core/types.js.map +1 -0
- package/ui/dist/hooks/useFiles.d.ts +14 -0
- package/ui/dist/hooks/useFiles.d.ts.map +1 -0
- package/ui/dist/hooks/useFiles.js +102 -0
- package/ui/dist/hooks/useFiles.js.map +1 -0
- package/ui/dist/hooks/useVM.d.ts +10 -0
- package/ui/dist/hooks/useVM.d.ts.map +1 -0
- package/ui/dist/hooks/useVM.js +54 -0
- package/ui/dist/hooks/useVM.js.map +1 -0
- package/ui/dist/hooks/useVMList.d.ts +10 -0
- package/ui/dist/hooks/useVMList.d.ts.map +1 -0
- package/ui/dist/hooks/useVMList.js +56 -0
- package/ui/dist/hooks/useVMList.js.map +1 -0
- package/ui/dist/index.d.ts +3 -0
- package/ui/dist/index.d.ts.map +1 -0
- package/ui/dist/index.js +7488 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/keybindings.d.ts +146 -0
- package/ui/dist/keybindings.d.ts.map +1 -0
- package/ui/dist/keybindings.js +96 -0
- package/ui/dist/keybindings.js.map +1 -0
- package/ui/dist/screens/AddVMScreen.d.ts +9 -0
- package/ui/dist/screens/AddVMScreen.d.ts.map +1 -0
- package/ui/dist/screens/AddVMScreen.js +163 -0
- package/ui/dist/screens/AddVMScreen.js.map +1 -0
- package/ui/dist/screens/VMDetailScreen.d.ts +12 -0
- package/ui/dist/screens/VMDetailScreen.d.ts.map +1 -0
- package/ui/dist/screens/VMDetailScreen.js +96 -0
- package/ui/dist/screens/VMDetailScreen.js.map +1 -0
- package/ui/dist/screens/VMListScreen.d.ts +12 -0
- package/ui/dist/screens/VMListScreen.d.ts.map +1 -0
- package/ui/dist/screens/VMListScreen.js +158 -0
- package/ui/dist/screens/VMListScreen.js.map +1 -0
- package/ui/dist/screens/tabs/FilesTab.d.ts +9 -0
- package/ui/dist/screens/tabs/FilesTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/FilesTab.js +374 -0
- package/ui/dist/screens/tabs/FilesTab.js.map +1 -0
- package/ui/dist/screens/tabs/OverviewTab.d.ts +10 -0
- package/ui/dist/screens/tabs/OverviewTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/OverviewTab.js +110 -0
- package/ui/dist/screens/tabs/OverviewTab.js.map +1 -0
- package/ui/dist/screens/tabs/TerminalTab.d.ts +9 -0
- package/ui/dist/screens/tabs/TerminalTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/TerminalTab.js +270 -0
- package/ui/dist/screens/tabs/TerminalTab.js.map +1 -0
- package/ui/dist/utils/terminalEmulator.d.ts +49 -0
- package/ui/dist/utils/terminalEmulator.d.ts.map +1 -0
- package/ui/dist/utils/terminalEmulator.js +88 -0
- package/ui/dist/utils/terminalEmulator.js.map +1 -0
- package/ui/package.json +34 -0
- package/ui/scripts/start-with-core.js +81 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
package ipc
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"fmt"
|
|
6
|
+
"io"
|
|
7
|
+
"log"
|
|
8
|
+
"os"
|
|
9
|
+
"sync"
|
|
10
|
+
|
|
11
|
+
"github.com/adishm/heyvm/internal/auth"
|
|
12
|
+
"github.com/adishm/heyvm/internal/sftp"
|
|
13
|
+
"github.com/adishm/heyvm/internal/ssh"
|
|
14
|
+
"github.com/adishm/heyvm/internal/vm"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// Handler manages IPC communication and VM operations
|
|
18
|
+
type Handler struct {
|
|
19
|
+
registry *vm.Registry
|
|
20
|
+
sshManagers map[string]*ssh.Manager // vmID -> SSH manager
|
|
21
|
+
sftpManagers map[string]*sftp.Manager // vmID -> SFTP manager
|
|
22
|
+
authProviders map[string]auth.Provider // vmID -> auth provider
|
|
23
|
+
mu sync.RWMutex
|
|
24
|
+
input io.Reader
|
|
25
|
+
output io.Writer
|
|
26
|
+
outputMu sync.Mutex // Protect output writes
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// NewHandler creates a new IPC handler
|
|
30
|
+
func NewHandler(registry *vm.Registry) *Handler {
|
|
31
|
+
return &Handler{
|
|
32
|
+
registry: registry,
|
|
33
|
+
sshManagers: make(map[string]*ssh.Manager),
|
|
34
|
+
sftpManagers: make(map[string]*sftp.Manager),
|
|
35
|
+
authProviders: make(map[string]auth.Provider),
|
|
36
|
+
input: os.Stdin,
|
|
37
|
+
output: os.Stdout,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Emit sends an event to the UI (non-blocking, fire-and-forget)
|
|
42
|
+
func (h *Handler) Emit(event string, data interface{}) {
|
|
43
|
+
h.outputMu.Lock()
|
|
44
|
+
defer h.outputMu.Unlock()
|
|
45
|
+
|
|
46
|
+
encoder := json.NewEncoder(h.output)
|
|
47
|
+
response := NewEvent(event, data)
|
|
48
|
+
|
|
49
|
+
if err := encoder.Encode(response); err != nil {
|
|
50
|
+
log.Printf("IPC handler: error emitting event %s: %v", event, err)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Start begins the IPC request/response loop
|
|
55
|
+
func (h *Handler) Start() error {
|
|
56
|
+
decoder := json.NewDecoder(h.input)
|
|
57
|
+
encoder := json.NewEncoder(h.output)
|
|
58
|
+
|
|
59
|
+
log.Println("IPC handler started, listening for requests...")
|
|
60
|
+
|
|
61
|
+
for {
|
|
62
|
+
var req Request
|
|
63
|
+
if err := decoder.Decode(&req); err != nil {
|
|
64
|
+
if err == io.EOF {
|
|
65
|
+
log.Println("IPC handler: received EOF, shutting down")
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
log.Printf("IPC handler: error decoding request: %v", err)
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
log.Printf("IPC handler: received request: %s", req.Action)
|
|
73
|
+
|
|
74
|
+
// Handle request
|
|
75
|
+
resp := h.HandleRequest(req)
|
|
76
|
+
|
|
77
|
+
// Skip sending response for fire-and-forget actions (empty response)
|
|
78
|
+
if resp.Status == "" {
|
|
79
|
+
log.Printf("IPC handler: fire-and-forget action, no response sent")
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Send response
|
|
84
|
+
h.outputMu.Lock()
|
|
85
|
+
if err := encoder.Encode(resp); err != nil {
|
|
86
|
+
log.Printf("IPC handler: error encoding response: %v", err)
|
|
87
|
+
h.outputMu.Unlock()
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
h.outputMu.Unlock()
|
|
91
|
+
|
|
92
|
+
log.Printf("IPC handler: sent response: status=%s", resp.Status)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Cleanup on shutdown
|
|
96
|
+
h.cleanup()
|
|
97
|
+
return nil
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// HandleRequest routes a request to the appropriate action handler
|
|
101
|
+
func (h *Handler) HandleRequest(req Request) Response {
|
|
102
|
+
var resp Response
|
|
103
|
+
|
|
104
|
+
switch req.Action {
|
|
105
|
+
case ActionListVMs:
|
|
106
|
+
resp = h.handleListVMs(req.Params)
|
|
107
|
+
case ActionAddVM:
|
|
108
|
+
resp = h.handleAddVM(req.Params)
|
|
109
|
+
case ActionRemoveVM:
|
|
110
|
+
resp = h.handleRemoveVM(req.Params)
|
|
111
|
+
case ActionConnectVM:
|
|
112
|
+
resp = h.handleConnectVM(req.Params)
|
|
113
|
+
case ActionDisconnectVM:
|
|
114
|
+
resp = h.handleDisconnectVM(req.Params)
|
|
115
|
+
case ActionExecuteCommand:
|
|
116
|
+
resp = h.handleExecuteCommand(req.Params)
|
|
117
|
+
case ActionListFiles:
|
|
118
|
+
resp = h.handleListFiles(req.Params)
|
|
119
|
+
case ActionUploadFile:
|
|
120
|
+
resp = h.handleUploadFile(req.Params)
|
|
121
|
+
case ActionDownloadFile:
|
|
122
|
+
resp = h.handleDownloadFile(req.Params)
|
|
123
|
+
case ActionDeleteFile:
|
|
124
|
+
resp = h.handleDeleteFile(req.Params)
|
|
125
|
+
case ActionRenameFile:
|
|
126
|
+
resp = h.handleRenameFile(req.Params)
|
|
127
|
+
case ActionStorePassword:
|
|
128
|
+
resp = h.handleStorePassword(req.Params)
|
|
129
|
+
case ActionTestConnection:
|
|
130
|
+
resp = h.handleTestConnection(req.Params)
|
|
131
|
+
case ActionStartPTY:
|
|
132
|
+
// Fire-and-forget: handle but don't send response
|
|
133
|
+
go h.handleStartPTY(req.Params)
|
|
134
|
+
return Response{} // Return empty response (won't be sent)
|
|
135
|
+
case ActionWriteToPTY:
|
|
136
|
+
// Fire-and-forget: handle but don't send response
|
|
137
|
+
go h.handleWriteToPTY(req.Params)
|
|
138
|
+
return Response{} // Return empty response (won't be sent)
|
|
139
|
+
case ActionResizePTY:
|
|
140
|
+
// Fire-and-forget: handle but don't send response
|
|
141
|
+
go h.handleResizePTY(req.Params)
|
|
142
|
+
return Response{} // Return empty response (won't be sent)
|
|
143
|
+
case ActionClosePTY:
|
|
144
|
+
// Fire-and-forget: handle but don't send response
|
|
145
|
+
go h.handleClosePTY(req.Params)
|
|
146
|
+
return Response{} // Return empty response (won't be sent)
|
|
147
|
+
default:
|
|
148
|
+
resp = NewErrorResponseWithMessage(fmt.Sprintf("unknown action: %s", req.Action))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Add request ID to response for proper matching
|
|
152
|
+
resp.RequestID = req.RequestID
|
|
153
|
+
return resp
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// cleanup closes all active connections
|
|
157
|
+
func (h *Handler) cleanup() {
|
|
158
|
+
log.Println("IPC handler: cleaning up connections...")
|
|
159
|
+
|
|
160
|
+
h.mu.Lock()
|
|
161
|
+
defer h.mu.Unlock()
|
|
162
|
+
|
|
163
|
+
// Close all SFTP managers
|
|
164
|
+
for vmID, sftpMgr := range h.sftpManagers {
|
|
165
|
+
if err := sftpMgr.Close(); err != nil {
|
|
166
|
+
log.Printf("Error closing SFTP manager for VM %s: %v", vmID, err)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Close all SSH managers
|
|
171
|
+
for vmID, sshMgr := range h.sshManagers {
|
|
172
|
+
if err := sshMgr.Disconnect(); err != nil {
|
|
173
|
+
log.Printf("Error disconnecting SSH manager for VM %s: %v", vmID, err)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Disconnect all auth providers
|
|
178
|
+
for vmID, provider := range h.authProviders {
|
|
179
|
+
if err := provider.Disconnect(); err != nil {
|
|
180
|
+
log.Printf("Error disconnecting auth provider for VM %s: %v", vmID, err)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
log.Println("IPC handler: cleanup complete")
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// getSSHManager gets or creates an SSH manager for a VM
|
|
188
|
+
func (h *Handler) getSSHManager(vmID string) (*ssh.Manager, error) {
|
|
189
|
+
h.mu.RLock()
|
|
190
|
+
manager, exists := h.sshManagers[vmID]
|
|
191
|
+
h.mu.RUnlock()
|
|
192
|
+
|
|
193
|
+
if exists && manager.IsConnected() {
|
|
194
|
+
return manager, nil
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Get VM from registry
|
|
198
|
+
v, err := h.registry.Get(vmID)
|
|
199
|
+
if err != nil {
|
|
200
|
+
return nil, fmt.Errorf("VM not found: %w", err)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Get or create auth provider
|
|
204
|
+
provider, err := h.getAuthProvider(vmID, v)
|
|
205
|
+
if err != nil {
|
|
206
|
+
return nil, fmt.Errorf("failed to get auth provider: %w", err)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Create SSH manager
|
|
210
|
+
manager = ssh.NewManager(v, provider)
|
|
211
|
+
|
|
212
|
+
h.mu.Lock()
|
|
213
|
+
h.sshManagers[vmID] = manager
|
|
214
|
+
h.mu.Unlock()
|
|
215
|
+
|
|
216
|
+
return manager, nil
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// getSFTPManager gets or creates an SFTP manager for a VM
|
|
220
|
+
func (h *Handler) getSFTPManager(vmID string) (*sftp.Manager, error) {
|
|
221
|
+
h.mu.RLock()
|
|
222
|
+
manager, exists := h.sftpManagers[vmID]
|
|
223
|
+
h.mu.RUnlock()
|
|
224
|
+
|
|
225
|
+
if exists {
|
|
226
|
+
return manager, nil
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Get SSH manager first
|
|
230
|
+
sshMgr, err := h.getSSHManager(vmID)
|
|
231
|
+
if err != nil {
|
|
232
|
+
return nil, fmt.Errorf("failed to get SSH manager: %w", err)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Ensure connected
|
|
236
|
+
if !sshMgr.IsConnected() {
|
|
237
|
+
if err := sshMgr.Connect(); err != nil {
|
|
238
|
+
return nil, fmt.Errorf("failed to connect SSH: %w", err)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Create SFTP manager
|
|
243
|
+
client := sshMgr.GetClient()
|
|
244
|
+
if client == nil {
|
|
245
|
+
return nil, fmt.Errorf("SSH client is nil")
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
manager, err = sftp.NewManager(client)
|
|
249
|
+
if err != nil {
|
|
250
|
+
return nil, fmt.Errorf("failed to create SFTP manager: %w", err)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
h.mu.Lock()
|
|
254
|
+
h.sftpManagers[vmID] = manager
|
|
255
|
+
h.mu.Unlock()
|
|
256
|
+
|
|
257
|
+
return manager, nil
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// getAuthProvider gets or creates an auth provider for a VM
|
|
261
|
+
func (h *Handler) getAuthProvider(vmID string, v *vm.VM) (auth.Provider, error) {
|
|
262
|
+
h.mu.RLock()
|
|
263
|
+
provider, exists := h.authProviders[vmID]
|
|
264
|
+
h.mu.RUnlock()
|
|
265
|
+
|
|
266
|
+
if exists {
|
|
267
|
+
return provider, nil
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Create new provider
|
|
271
|
+
provider, err := auth.NewProvider(v)
|
|
272
|
+
if err != nil {
|
|
273
|
+
return nil, err
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
h.mu.Lock()
|
|
277
|
+
h.authProviders[vmID] = provider
|
|
278
|
+
h.mu.Unlock()
|
|
279
|
+
|
|
280
|
+
return provider, nil
|
|
281
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
package ipc
|
|
2
|
+
|
|
3
|
+
// Request represents an IPC request from the UI
|
|
4
|
+
type Request struct {
|
|
5
|
+
RequestID int `json:"request_id"`
|
|
6
|
+
Action string `json:"action"`
|
|
7
|
+
Params map[string]interface{} `json:"params,omitempty"`
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Response represents an IPC response to the UI
|
|
11
|
+
type Response struct {
|
|
12
|
+
RequestID int `json:"request_id"`
|
|
13
|
+
Status string `json:"status"` // "success" | "error"
|
|
14
|
+
Message string `json:"message,omitempty"`
|
|
15
|
+
Data interface{} `json:"data,omitempty"`
|
|
16
|
+
Event string `json:"event,omitempty"` // For event-based messages
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// NewSuccessResponse creates a success response
|
|
20
|
+
func NewSuccessResponse(data interface{}) Response {
|
|
21
|
+
return Response{
|
|
22
|
+
Status: "success",
|
|
23
|
+
Data: data,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// NewSuccessResponseWithID creates a success response with request ID
|
|
28
|
+
func NewSuccessResponseWithID(requestID int, data interface{}) Response {
|
|
29
|
+
return Response{
|
|
30
|
+
RequestID: requestID,
|
|
31
|
+
Status: "success",
|
|
32
|
+
Data: data,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// NewSuccessResponseWithMessage creates a success response with a message
|
|
37
|
+
func NewSuccessResponseWithMessage(message string, data interface{}) Response {
|
|
38
|
+
return Response{
|
|
39
|
+
Status: "success",
|
|
40
|
+
Message: message,
|
|
41
|
+
Data: data,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// NewSuccessResponseWithMessageAndID creates a success response with message and request ID
|
|
46
|
+
func NewSuccessResponseWithMessageAndID(requestID int, message string, data interface{}) Response {
|
|
47
|
+
return Response{
|
|
48
|
+
RequestID: requestID,
|
|
49
|
+
Status: "success",
|
|
50
|
+
Message: message,
|
|
51
|
+
Data: data,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// NewErrorResponse creates an error response
|
|
56
|
+
func NewErrorResponse(err error) Response {
|
|
57
|
+
return Response{
|
|
58
|
+
Status: "error",
|
|
59
|
+
Message: err.Error(),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// NewErrorResponseWithID creates an error response with request ID
|
|
64
|
+
func NewErrorResponseWithID(requestID int, err error) Response {
|
|
65
|
+
return Response{
|
|
66
|
+
RequestID: requestID,
|
|
67
|
+
Status: "error",
|
|
68
|
+
Message: err.Error(),
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// NewErrorResponseWithMessage creates an error response with a custom message
|
|
73
|
+
func NewErrorResponseWithMessage(message string) Response {
|
|
74
|
+
return Response{
|
|
75
|
+
Status: "error",
|
|
76
|
+
Message: message,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// NewErrorResponseWithMessageAndID creates an error response with custom message and request ID
|
|
81
|
+
func NewErrorResponseWithMessageAndID(requestID int, message string) Response {
|
|
82
|
+
return Response{
|
|
83
|
+
RequestID: requestID,
|
|
84
|
+
Status: "error",
|
|
85
|
+
Message: message,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Action constants
|
|
90
|
+
const (
|
|
91
|
+
ActionListVMs = "list_vms"
|
|
92
|
+
ActionAddVM = "add_vm"
|
|
93
|
+
ActionRemoveVM = "remove_vm"
|
|
94
|
+
ActionConnectVM = "connect_vm"
|
|
95
|
+
ActionDisconnectVM = "disconnect_vm"
|
|
96
|
+
ActionExecuteCommand = "execute_command"
|
|
97
|
+
ActionListFiles = "list_files"
|
|
98
|
+
ActionUploadFile = "upload_file"
|
|
99
|
+
ActionDownloadFile = "download_file"
|
|
100
|
+
ActionDeleteFile = "delete_file"
|
|
101
|
+
ActionRenameFile = "rename_file"
|
|
102
|
+
ActionStorePassword = "store_password"
|
|
103
|
+
ActionTestConnection = "test_connection"
|
|
104
|
+
ActionStartPTY = "start_pty"
|
|
105
|
+
ActionWriteToPTY = "write_to_pty"
|
|
106
|
+
ActionResizePTY = "resize_pty"
|
|
107
|
+
ActionClosePTY = "close_pty"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
// Event constants
|
|
111
|
+
const (
|
|
112
|
+
EventPTYReady = "PTY_READY"
|
|
113
|
+
EventPTYOutput = "PTY_OUTPUT"
|
|
114
|
+
EventPTYExit = "PTY_EXIT"
|
|
115
|
+
EventPTYError = "PTY_ERROR"
|
|
116
|
+
EventTransferProgress = "TRANSFER_PROGRESS"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
// NewEvent creates an event response (no request ID needed)
|
|
120
|
+
func NewEvent(event string, data interface{}) Response {
|
|
121
|
+
return Response{
|
|
122
|
+
Status: "success",
|
|
123
|
+
Event: event,
|
|
124
|
+
Data: data,
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
package sftp
|
|
2
|
+
|
|
3
|
+
import "errors"
|
|
4
|
+
|
|
5
|
+
var (
|
|
6
|
+
// ErrSFTPClientNotInitialized is returned when SFTP client is not initialized
|
|
7
|
+
ErrSFTPClientNotInitialized = errors.New("SFTP client not initialized")
|
|
8
|
+
|
|
9
|
+
// ErrFileNotFound is returned when a file doesn't exist
|
|
10
|
+
ErrFileNotFound = errors.New("file not found")
|
|
11
|
+
|
|
12
|
+
// ErrPermissionDenied is returned when permission is denied
|
|
13
|
+
ErrPermissionDenied = errors.New("permission denied")
|
|
14
|
+
|
|
15
|
+
// ErrFileAlreadyExists is returned when trying to create a file that already exists
|
|
16
|
+
ErrFileAlreadyExists = errors.New("file already exists")
|
|
17
|
+
|
|
18
|
+
// ErrInvalidPath is returned when a path is invalid
|
|
19
|
+
ErrInvalidPath = errors.New("invalid path")
|
|
20
|
+
|
|
21
|
+
// ErrIsDirectory is returned when expecting a file but got a directory
|
|
22
|
+
ErrIsDirectory = errors.New("path is a directory")
|
|
23
|
+
|
|
24
|
+
// ErrNotDirectory is returned when expecting a directory but got a file
|
|
25
|
+
ErrNotDirectory = errors.New("path is not a directory")
|
|
26
|
+
|
|
27
|
+
// ErrTransferFailed is returned when file transfer fails
|
|
28
|
+
ErrTransferFailed = errors.New("file transfer failed")
|
|
29
|
+
)
|