mirror of
https://github.com/veops/oneterm.git
synced 2025-10-22 15:00:41 +08:00
122 lines
3.6 KiB
Go
122 lines
3.6 KiB
Go
package guacd
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
)
|
|
|
|
// File transfer instruction constants
|
|
const (
|
|
INSTRUCTION_FILE_UPLOAD = "file-upload"
|
|
INSTRUCTION_FILE_DOWNLOAD = "file-download"
|
|
INSTRUCTION_FILE_DATA = "file-data"
|
|
INSTRUCTION_FILE_ACK = "file-ack"
|
|
INSTRUCTION_FILE_COMPLETE = "file-complete"
|
|
INSTRUCTION_FILE_ERROR = "file-error"
|
|
)
|
|
|
|
// Object instruction constants for filesystem operations
|
|
const (
|
|
INSTRUCTION_FILESYSTEM = "filesystem"
|
|
INSTRUCTION_GET = "get"
|
|
INSTRUCTION_PUT = "put"
|
|
INSTRUCTION_BODY = "body"
|
|
INSTRUCTION_UNDEFINE = "undefine"
|
|
)
|
|
|
|
// Stream instruction constants
|
|
const (
|
|
INSTRUCTION_BLOB = "blob"
|
|
INSTRUCTION_END = "end"
|
|
)
|
|
|
|
// Filesystem mimetypes
|
|
const (
|
|
MIMETYPE_STREAM_INDEX = "application/vnd.glyptodon.guacamole.stream-index+json"
|
|
MIMETYPE_TEXT_PLAIN = "text/plain"
|
|
)
|
|
|
|
// HandleFileInstruction processes file transfer related instructions
|
|
func (t *Tunnel) HandleFileInstruction(instruction *Instruction) (*Instruction, error) {
|
|
switch instruction.Opcode {
|
|
case INSTRUCTION_FILE_UPLOAD:
|
|
if len(instruction.Args) < 2 {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, "Invalid upload request"), nil
|
|
}
|
|
|
|
filename := instruction.Args[0]
|
|
size, err := strconv.ParseInt(instruction.Args[1], 10, 64)
|
|
if err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, "Invalid file size"), nil
|
|
}
|
|
|
|
transferId, err := t.HandleFileUpload(filename, size)
|
|
if err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, err.Error()), nil
|
|
}
|
|
|
|
return NewInstruction(INSTRUCTION_FILE_ACK, transferId), nil
|
|
|
|
case INSTRUCTION_FILE_DOWNLOAD:
|
|
if len(instruction.Args) < 1 {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, "Invalid download request"), nil
|
|
}
|
|
|
|
filename := instruction.Args[0]
|
|
transferId, size, err := t.HandleFileDownload(filename)
|
|
if err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, err.Error()), nil
|
|
}
|
|
|
|
// Send acknowledgement with transfer ID and file size
|
|
ackInstr := NewInstruction(INSTRUCTION_FILE_ACK, transferId, strconv.FormatInt(size, 10))
|
|
if _, err := t.WriteInstruction(ackInstr); err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, fmt.Sprintf("Failed to send ACK: %s", err.Error())), nil
|
|
}
|
|
|
|
// Start file download process in a new goroutine
|
|
go func() {
|
|
if err := t.SendDownloadData(transferId); err != nil {
|
|
// Log error, but we can't send error instruction here as it would interfere with protocol
|
|
fmt.Printf("Download failed: %s\n", err.Error())
|
|
}
|
|
}()
|
|
|
|
// Return nil to avoid sending another response
|
|
return nil, nil
|
|
|
|
case INSTRUCTION_FILE_DATA:
|
|
if len(instruction.Args) < 2 {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, "Invalid data request"), nil
|
|
}
|
|
|
|
transferId := instruction.Args[0]
|
|
data := []byte(instruction.Args[1])
|
|
|
|
// If this is an upload, write the data
|
|
n, err := t.WriteFileData(transferId, data)
|
|
if err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, fmt.Sprintf("Write error: %s", err.Error())), nil
|
|
}
|
|
|
|
return NewInstruction(INSTRUCTION_FILE_ACK, transferId, strconv.Itoa(n)), nil
|
|
|
|
case INSTRUCTION_FILE_COMPLETE:
|
|
if len(instruction.Args) < 1 {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, "Invalid complete request"), nil
|
|
}
|
|
|
|
transferId := instruction.Args[0]
|
|
|
|
err := t.CloseFileTransfer(transferId)
|
|
if err != nil {
|
|
return NewInstruction(INSTRUCTION_FILE_ERROR, fmt.Sprintf("Failed to complete transfer: %s", err.Error())), nil
|
|
}
|
|
|
|
return NewInstruction(INSTRUCTION_FILE_ACK, transferId, "complete"), nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("Unknown file instruction: %s", instruction.Opcode)
|
|
}
|
|
}
|