Files
backup/cmd/serve.go
T
wt a1681ab58a
Go Build and Test / build-and-test (push) Successful in 29s
Улучшение обработки путей и добавление списка файлов
- Заменена filepath.Ext() на strings.HasSuffix() для корректной проверки
расширений - Оптимизирована логика проверки исключаемых путей: - Упрощён
pattern matching - Добавлена явная проверка префиксов путей - Улучшена
обработка базовых имён файлов - Добавлен новый endpoint GET /backup: -
Возвращает JSON-список файлов в директории бэкапов - Реализована
фильтрация директорий
2025-08-12 16:17:43 +07:00

119 lines
3.3 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
)
var (
serveAddress string
serveDirectory string
)
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Run a backup server",
Long: "Run an HTTP server to upload and download backups.",
Run: func(cmd *cobra.Command, args []string) {
if serveDirectory == "" {
home, err := os.UserHomeDir()
if err != nil {
log.Fatalf("Failed to get user home directory: %v", err)
}
serveDirectory = filepath.Join(home, "backups")
}
if err := os.MkdirAll(serveDirectory, 0755); err != nil {
log.Fatalf("Failed to create backup directory: %v", err)
}
r := mux.NewRouter()
r.HandleFunc("/backup/{filename}", uploadHandler).Methods("POST")
r.HandleFunc("/backup/{filename}", downloadHandler).Methods("GET")
r.HandleFunc("/backup", listHandler).Methods("GET")
log.Printf("Starting server on %s", serveAddress)
log.Printf("Using backup directory: %s", serveDirectory)
if err := http.ListenAndServe(serveAddress, r); err != nil {
log.Fatalf("Server failed: %v", err)
}
},
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
filename := vars["filename"]
filePath := filepath.Join(serveDirectory, filename)
file, err := os.Create(filePath)
if err != nil {
http.Error(w, "Failed to create file", http.StatusInternalServerError)
log.Printf("Error creating file %s: %v", filename, err)
return
}
defer file.Close()
_, err = io.Copy(file, r.Body)
if err != nil {
http.Error(w, "Failed to write to file", http.StatusInternalServerError)
log.Printf("Error writing to file %s: %v", filename, err)
return
}
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "File %s uploaded successfully.", filename)
log.Printf("Uploaded %s", filename)
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
filename := vars["filename"]
filePath := filepath.Join(serveDirectory, filename)
// Проверяем, существует ли файл, перед отправкой
if _, err := os.Stat(filePath); os.IsNotExist(err) {
http.NotFound(w, r)
log.Printf("File not found: %s", filename)
return
}
// http.ServeFile - это идиоматический способ отправки файлов в Go.
// Он автоматически устанавливает Content-Type, Content-Length и другие заголовки.
http.ServeFile(w, r, filePath)
log.Printf("Downloaded %s", filename)
}
func listHandler(w http.ResponseWriter, r *http.Request) {
files, err := os.ReadDir(serveDirectory)
if err != nil {
http.Error(w, "Failed to read directory", http.StatusInternalServerError)
log.Printf("Error reading directory: %v", err)
return
}
var filenames []string
for _, file := range files {
if !file.IsDir() {
filenames = append(filenames, file.Name())
}
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(filenames)
log.Printf("Listed files")
}
func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringVarP(&serveAddress, "address", "a", "localhost:8080", "Address and port for the server")
serveCmd.Flags().StringVarP(&serveDirectory, "directory", "d", "", "Directory to store backups (defaults to ~/backups)")
}