diff --git a/api.go b/api.go index 095a41b..690133a 100644 --- a/api.go +++ b/api.go @@ -2,8 +2,9 @@ package main import ( "net/http" - "github.com/go-chi/chi/v5" "strings" + + "github.com/go-chi/chi/v5" "github.com/spf13/viper" ) @@ -14,14 +15,12 @@ func (r *Repository) UploadHandler(w http.ResponseWriter, req *http.Request) { logger.Error("Authorization header missing") return } - parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { http.Error(w, "Unauthorized", http.StatusUnauthorized) logger.Error("Invalid Authorization header format") return } - token := parts[1] if token != viper.GetString("auth.token") { http.Error(w, "Unauthorized", http.StatusUnauthorized) @@ -46,13 +45,14 @@ func (r *Repository) UploadHandler(w http.ResponseWriter, req *http.Request) { logger.Infof("Uploading package %s for architecture %s", handler.Filename, arch) - if err := r.SavePackage(arch, handler.Filename, file); err != nil { - http.Error(w, "Error saving package", http.StatusInternalServerError) - logger.Errorf("Error saving package: %v", err) + // Передаем управление в Repository для обработки файла + if err := r.ProcessPackage(arch, handler.Filename, file); err != nil { + http.Error(w, "Error processing package", http.StatusInternalServerError) + logger.Errorf("Error processing package: %v", err) return } w.WriteHeader(http.StatusOK) w.Write([]byte("Package uploaded successfully")) logger.Infof("Package %s uploaded successfully for architecture %s", handler.Filename, arch) -} +} \ No newline at end of file diff --git a/logger.go b/logger.go index 30e4a4d..337b345 100644 --- a/logger.go +++ b/logger.go @@ -10,19 +10,21 @@ var logger *logrus.Logger func initLogger() { logger = &logrus.Logger{ Out: logrus.StandardLogger().Out, - Formatter: logrus.StandardLogger().Formatter, + Formatter: &logrus.TextFormatter{}, Level: logrus.InfoLevel, ReportCaller: true, } - logLevel := viper.GetString("log.level") - if logLevel == "debug" { + switch logLevel { + case "debug": logger.SetLevel(logrus.DebugLevel) - } else if logLevel == "info" { + case "info": logger.SetLevel(logrus.InfoLevel) - } else if logLevel == "warn" { + case "warn": logger.SetLevel(logrus.WarnLevel) - } else if logLevel == "error" { + case "error": logger.SetLevel(logrus.ErrorLevel) + default: + logger.SetLevel(logrus.InfoLevel) } } \ No newline at end of file diff --git a/main.go b/main.go index 85751dd..486b893 100644 --- a/main.go +++ b/main.go @@ -1,29 +1,20 @@ 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") viper.AddConfigPath(".") if err := viper.ReadInConfig(); err != nil { - log.Fatalf("Error reading config file, %s", err) + logger.Fatalf("Error reading config file: %v", err) } initLogger() repo := NewRepository() @@ -41,12 +32,13 @@ func main() { logger.Fatal(err) } if len(os.Args) > 1 { - if os.Args[1] == "install" { + switch os.Args[1] { + case "install": if err := s.Install(); err != nil { logger.Fatal(err) } return - } else if os.Args[1] == "uninstall" { + case "uninstall": if err := s.Uninstall(); err != nil { logger.Fatal(err) } @@ -78,101 +70,15 @@ func (p *serviceProgram) Stop(s service.Service) error { 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) { + if authToken != "Bearer "+expectedToken { http.Error(w, "Unauthorized", http.StatusUnauthorized) + logger.Error("Unauthorized access attempt") return } next.ServeHTTP(w, r) }) -} - -func initLogger() { - logger = log.New(os.Stdout, "", log.LstdFlags) } \ No newline at end of file diff --git a/repository.go b/repository.go index dfc1d12..c123388 100644 --- a/repository.go +++ b/repository.go @@ -1,12 +1,15 @@ package main import ( + "crypto/sha256" + "encoding/hex" "fmt" "io" "os" "path/filepath" "strings" "os/exec" + "github.com/spf13/viper" ) @@ -29,15 +32,51 @@ func NewRepository() *Repository { } } +// ProcessPackage обрабатывает загруженный пакет +func (r *Repository) ProcessPackage(arch, filename string, body io.Reader) error { + // Преобразуем body к io.ReadSeeker для возможности использовать Seek + readSeeker, ok := body.(io.ReadSeeker) + if !ok { + logger.Errorf("Failed to cast body to io.ReadSeeker for file %s", filename) + return fmt.Errorf("failed to cast body to io.ReadSeeker") + } + + // Вычисляем контрольную сумму загруженного файла + hash := sha256.New() + if _, err := io.Copy(hash, readSeeker); err != nil { + logger.Errorf("Error computing checksum for file %s: %v", filename, err) + return err + } + checksum := hex.EncodeToString(hash.Sum(nil)) + + // Возвращаемся к началу файла для записи + if _, err := readSeeker.Seek(0, 0); err != nil { + logger.Errorf("Error seeking to the beginning of file %s: %v", filename, err) + return err + } + + // Проверяем, существует ли файл с такой контрольной суммой + if r.fileExistsWithChecksum(arch, filename, checksum) { + logger.Infof("File %s already exists with the same checksum, skipping upload.", filename) + return nil + } + + // Сохраняем пакет + if err := r.SavePackage(arch, filename, readSeeker); err != nil { + logger.Errorf("Error saving package %s: %v", filename, err) + return err + } + + return nil +} + func (r *Repository) SavePackage(arch, name string, body io.Reader) error { logger.Infof("Saving package %s for architecture %s", name, arch) - dir := filepath.Join(r.BasePath, arch) if err := os.MkdirAll(dir, 0755); err != nil { logger.Errorf("Failed to create directory %s: %v", dir, err) return err } - filePath := filepath.Join(dir, name) file, err := os.Create(filePath) if err != nil { @@ -45,7 +84,6 @@ func (r *Repository) SavePackage(arch, name string, body io.Reader) error { return err } defer file.Close() - _, err = io.Copy(file, body) if err != nil { logger.Errorf("Failed to copy file content to %s: %v", filePath, err) @@ -59,11 +97,32 @@ func (r *Repository) SavePackage(arch, name string, body io.Reader) error { logger.Errorf("Failed to generate metadata: %v", err) return fmt.Errorf("failed to generate metadata: %w", err) } - logger.Infof("Package %s saved successfully for architecture %s", name, arch) return nil } +func (r *Repository) fileExistsWithChecksum(arch, filename, checksum string) bool { + filePath := filepath.Join(r.BasePath, arch, filename) + file, err := os.Open(filePath) + if err != nil { + if os.IsNotExist(err) { + return false + } + logger.Errorf("Error opening file %s: %v", filePath, err) + return false + } + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + logger.Errorf("Error computing checksum for file %s: %v", filePath, err) + return false + } + existingChecksum := hex.EncodeToString(hash.Sum(nil)) + + return existingChecksum == checksum +} + func (r *Repository) GetArch(arch string) string { switch strings.ToLower(arch) { case ARCH_X86_64: