Files
silo-server/internal/api/handlers/filesystem.go
T

88 lines
2.0 KiB
Go

package handlers
import (
"net/http"
"os"
"path/filepath"
"sort"
"strings"
)
type filesystemBrowseEntry struct {
Name string `json:"name"`
Path string `json:"path"`
}
type filesystemBrowseResponse struct {
Path string `json:"path"`
Parent string `json:"parent"`
Entries []filesystemBrowseEntry `json:"entries"`
}
type FilesystemHandler struct{}
func NewFilesystemHandler() *FilesystemHandler { return &FilesystemHandler{} }
func (h *FilesystemHandler) HandleBrowse(w http.ResponseWriter, r *http.Request) {
path := strings.TrimSpace(r.URL.Query().Get("path"))
if path == "" {
path = string(filepath.Separator)
}
if !filepath.IsAbs(path) {
writeError(w, http.StatusBadRequest, "bad_request", "path must be an absolute path")
return
}
cleaned := filepath.Clean(path)
info, err := os.Stat(cleaned)
if err != nil {
if os.IsNotExist(err) {
writeError(w, http.StatusNotFound, "not_found", "Directory not found")
} else {
writeError(w, http.StatusBadRequest, "bad_request", "Invalid path")
}
return
}
if !info.IsDir() {
writeError(w, http.StatusBadRequest, "bad_request", "path must point to a directory")
return
}
entries, err := os.ReadDir(cleaned)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal_error", "Failed to read directory")
return
}
result := make([]filesystemBrowseEntry, 0, len(entries))
for _, entry := range entries {
if !entry.IsDir() {
continue
}
name := entry.Name()
result = append(result, filesystemBrowseEntry{
Name: name,
Path: filepath.Join(cleaned, name),
})
}
sort.Slice(result, func(i, j int) bool {
if result[i].Name == result[j].Name {
return result[i].Path < result[j].Path
}
return result[i].Name < result[j].Name
})
parent := filepath.Dir(cleaned)
if cleaned == string(filepath.Separator) || parent == "." || parent == cleaned {
parent = cleaned
}
writeJSON(w, http.StatusOK, filesystemBrowseResponse{
Path: cleaned,
Parent: parent,
Entries: result,
})
}