This commit is contained in:
Josh at WLTechBlog
2025-08-14 18:55:38 -05:00
parent d6209cd34f
commit dc6b288aa4
19 changed files with 4127 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
@@ -95,6 +96,8 @@ func NewDaemon(host string, port int) (*Daemon, error) {
mux := http.NewServeMux()
mux.HandleFunc("/command", daemon.handleCommand)
mux.HandleFunc("/status", daemon.handleStatus)
mux.HandleFunc("/upload", daemon.handleFileUpload)
mux.HandleFunc("/download", daemon.handleFileDownload)
daemon.server = &http.Server{
Addr: fmt.Sprintf("%s:%d", host, port),
@@ -1637,3 +1640,105 @@ func (d *Daemon) switchToMain(tabID string) error {
return nil
}
// handleFileUpload handles file upload requests from clients
func (d *Daemon) handleFileUpload(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Parse multipart form (32MB max memory)
err := r.ParseMultipartForm(32 << 20)
if err != nil {
http.Error(w, "Failed to parse multipart form", http.StatusBadRequest)
return
}
// Get the uploaded file
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "Failed to get uploaded file", http.StatusBadRequest)
return
}
defer file.Close()
// Get the target path (optional, defaults to /tmp/)
targetPath := r.FormValue("path")
if targetPath == "" {
targetPath = "/tmp/" + header.Filename
}
// Create the target file
targetFile, err := os.Create(targetPath)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to create target file: %v", err), http.StatusInternalServerError)
return
}
defer targetFile.Close()
// Copy the uploaded file to the target location
_, err = io.Copy(targetFile, file)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to save file: %v", err), http.StatusInternalServerError)
return
}
// Return success response
response := Response{
Success: true,
Data: map[string]interface{}{
"filename": header.Filename,
"size": header.Size,
"target_path": targetPath,
},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// handleFileDownload handles file download requests from clients
func (d *Daemon) handleFileDownload(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Get the file path from query parameter
filePath := r.URL.Query().Get("path")
if filePath == "" {
http.Error(w, "File path is required", http.StatusBadRequest)
return
}
// Check if file exists and get info
fileInfo, err := os.Stat(filePath)
if err != nil {
if os.IsNotExist(err) {
http.Error(w, "File not found", http.StatusNotFound)
} else {
http.Error(w, fmt.Sprintf("Failed to access file: %v", err), http.StatusInternalServerError)
}
return
}
// Open the file
file, err := os.Open(filePath)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to open file: %v", err), http.StatusInternalServerError)
return
}
defer file.Close()
// Set headers for file download
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileInfo.Name()))
w.Header().Set("Content-Length", strconv.FormatInt(fileInfo.Size(), 10))
// Stream the file to the client
_, err = io.Copy(w, file)
if err != nil {
log.Printf("Error streaming file to client: %v", err)
}
}