add file exists

This commit is contained in:
Sergey Zhemoytel 2025-01-31 22:36:50 +03:00
parent 140721e7fc
commit a93af62172

120
main.go
View file

@ -1,15 +1,23 @@
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/spf13/viper"
"github.com/kardianos/service"
"log"
)
var srv service.Service
var logger *log.Logger
func main() {
viper.SetConfigName("config")
@ -17,25 +25,21 @@ func main() {
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Error reading config file, %s", err)
}
initLogger()
repo := NewRepository()
router := chi.NewRouter()
router.Use(middleware.Logger)
router.Use(authMiddleware)
router.Post("/{arch}", repo.UploadHandler)
svcConfig := &service.Config{
Name: "urpm-repo",
DisplayName: "URPM Repository Service",
Description: "Service for managing URPM packages",
}
s, err := service.New(&serviceProgram{repo, router}, svcConfig)
if err != nil {
logger.Fatal(err)
}
if len(os.Args) > 1 {
if os.Args[1] == "install" {
if err := s.Install(); err != nil {
@ -49,15 +53,14 @@ func main() {
return
}
}
if err := s.Run(); err != nil {
logger.Fatal(err)
}
}
type serviceProgram struct {
repo *Repository
router *chi.Mux
repo *Repository
router *chi.Mux
}
func (p *serviceProgram) Start(s service.Service) error {
@ -73,4 +76,103 @@ func (p *serviceProgram) Start(s service.Service) error {
func (p *serviceProgram) Stop(s service.Service) error {
logger.Info("Stopping URPM Repository Service...")
return nil
}
type Repository struct {
repoPath string
}
func NewRepository() *Repository {
return &Repository{
repoPath: viper.GetString("repository.path"),
}
}
func (r *Repository) UploadHandler(w http.ResponseWriter, r *http.Request) {
arch := chi.URLParam(r, "arch")
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
// Вычисляем контрольную сумму загруженного файла
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
checksum := hex.EncodeToString(hash.Sum(nil))
// Проверяем, существует ли файл с такой контрольной суммой
if r.fileExistsWithChecksum(arch, header.Filename, checksum) {
logger.Info("File already exists with the same checksum, skipping upload.")
w.WriteHeader(http.StatusConflict)
fmt.Fprintf(w, "File already exists with the same checksum.")
return
}
// Возвращаемся к началу файла для записи
file.Seek(0, 0)
// Сохраняем файл в репозиторий
dstPath := fmt.Sprintf("%s/%s/%s", r.repoPath, arch, header.Filename)
if err := os.MkdirAll(fmt.Sprintf("%s/%s", r.repoPath, arch), os.ModePerm); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
out, err := os.Create(dstPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer out.Close()
if _, err := io.Copy(out, file); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
logger.Info("File uploaded successfully.")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "File uploaded successfully.")
}
func (r *Repository) fileExistsWithChecksum(arch, filename, checksum string) bool {
filePath := fmt.Sprintf("%s/%s/%s", r.repoPath, arch, filename)
file, err := os.Open(filePath)
if err != nil {
if os.IsNotExist(err) {
return false
}
logger.Error(err)
return false
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
logger.Error(err)
return false
}
existingChecksum := hex.EncodeToString(hash.Sum(nil))
return existingChecksum == checksum
}
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authToken := r.Header.Get("Authorization")
expectedToken := viper.GetString("auth.token")
if authToken != fmt.Sprintf("Bearer %s", expectedToken) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
func initLogger() {
logger = log.New(os.Stdout, "", log.LstdFlags)
}