feat(modpack): modpack updates
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"gitea.mrixs.me/minecraft-platform/backend/internal/core"
|
||||
"gitea.mrixs.me/minecraft-platform/backend/internal/core/importer"
|
||||
"gitea.mrixs.me/minecraft-platform/backend/internal/database"
|
||||
"gitea.mrixs.me/minecraft-platform/backend/internal/models"
|
||||
)
|
||||
|
||||
type ModpackHandler struct {
|
||||
ModpackRepo *database.ModpackRepository
|
||||
ModpackRepo *database.ModpackRepository
|
||||
JanitorService *core.FileJanitorService
|
||||
}
|
||||
|
||||
// ImportModpack обрабатывает загрузку и импорт модпака.
|
||||
func (h *ModpackHandler) ImportModpack(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(512 << 20); err != nil { // 512 MB лимит
|
||||
http.Error(w, "File too large", http.StatusBadRequest)
|
||||
@@ -65,4 +69,7 @@ func (h *ModpackHandler) ImportModpack(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
fmt.Fprintf(w, "Modpack '%s' imported successfully with %d files.", modpack.DisplayName, len(files))
|
||||
|
||||
// Запускаем очистку в фоне, чтобы не блокировать ответ
|
||||
go h.JanitorService.CleanOrphanedFiles(context.Background())
|
||||
}
|
||||
|
||||
61
internal/core/file_janitor.go
Normal file
61
internal/core/file_janitor.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gitea.mrixs.me/minecraft-platform/backend/internal/database"
|
||||
)
|
||||
|
||||
// FileJanitorService отвечает за очистку осиротевших файлов.
|
||||
type FileJanitorService struct {
|
||||
ModpackRepo *database.ModpackRepository
|
||||
StoragePath string
|
||||
}
|
||||
|
||||
// NewFileJanitorService создает новый экземпляр сервиса-уборщика.
|
||||
func NewFileJanitorService(repo *database.ModpackRepository, storagePath string) *FileJanitorService {
|
||||
return &FileJanitorService{
|
||||
ModpackRepo: repo,
|
||||
StoragePath: storagePath,
|
||||
}
|
||||
}
|
||||
|
||||
// CleanOrphanedFiles сканирует хранилище и удаляет файлы, отсутствующие в БД.
|
||||
func (s *FileJanitorService) CleanOrphanedFiles(ctx context.Context) {
|
||||
log.Println("Janitor: Starting orphaned file cleanup...")
|
||||
|
||||
liveHashes, err := s.ModpackRepo.GetAllFileHashes(ctx)
|
||||
if err != nil {
|
||||
log.Printf("Janitor: Error getting live hashes from DB: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
diskFiles, err := os.ReadDir(s.StoragePath)
|
||||
if err != nil {
|
||||
log.Printf("Janitor: Error reading storage directory %s: %v", s.StoragePath, err)
|
||||
return
|
||||
}
|
||||
|
||||
removedCount := 0
|
||||
for _, file := range diskFiles {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
fileName := file.Name()
|
||||
if _, isLive := liveHashes[fileName]; !isLive {
|
||||
filePath := filepath.Join(s.StoragePath, fileName)
|
||||
if err := os.Remove(filePath); err != nil {
|
||||
log.Printf("Janitor: Failed to remove orphaned file %s: %v", filePath, err)
|
||||
} else {
|
||||
log.Printf("Janitor: Removed orphaned file %s", filePath)
|
||||
removedCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Janitor: Cleanup complete. Removed %d orphaned files.", removedCount)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// File: backend/internal/database/modpack_repository.go
|
||||
package database
|
||||
|
||||
import (
|
||||
@@ -81,3 +80,24 @@ func (r *ModpackRepository) GetModpackManifest(ctx context.Context, modpackName
|
||||
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
// GetAllFileHashes извлекает все уникальные хеши файлов из базы данных.
|
||||
func (r *ModpackRepository) GetAllFileHashes(ctx context.Context) (map[string]struct{}, error) {
|
||||
query := "SELECT DISTINCT file_hash FROM modpack_files"
|
||||
rows, err := r.DB.Query(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
hashes := make(map[string]struct{})
|
||||
for rows.Next() {
|
||||
var hash string
|
||||
if err := rows.Scan(&hash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashes[hash] = struct{}{}
|
||||
}
|
||||
|
||||
return hashes, rows.Err()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user