feat(modpacks): implement simple zip importer and API

This commit is contained in:
2025-06-18 12:41:27 +03:00
parent 5e609017f0
commit ca182d6d6f
9 changed files with 274 additions and 45 deletions

View File

@@ -0,0 +1,9 @@
package importer
import "gitea.mrixs.me/minecraft-platform/backend/internal/models"
// ModpackImporter определяет контракт для всех типов импортеров.
// Он принимает путь к временному zip-файлу и возвращает список файлов модпака.
type ModpackImporter interface {
Import(zipPath string) ([]models.ModpackFile, error)
}

View File

@@ -0,0 +1,78 @@
package importer
import (
"archive/zip"
"crypto/sha1"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"gitea.mrixs.me/minecraft-platform/backend/internal/models"
)
// SimpleZipImporter реализует интерфейс ModpackImporter для простых zip-архивов.
type SimpleZipImporter struct {
StoragePath string // Путь к хранилищу файлов модпаков
}
// processFile - это наша "общая конвейерная лента".
// Он читает файл, вычисляет хеш, сохраняет его на диск и возвращает метаданные.
func (i *SimpleZipImporter) processFile(reader io.Reader) (hash string, size int64, err error) {
data, err := io.ReadAll(reader)
if err != nil {
return "", 0, err
}
hasher := sha1.New()
hasher.Write(data)
hash = hex.EncodeToString(hasher.Sum(nil))
size = int64(len(data))
filePath := filepath.Join(i.StoragePath, hash)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
if err := os.WriteFile(filePath, data, 0644); err != nil {
return "", 0, fmt.Errorf("failed to save file %s: %w", hash, err)
}
}
return hash, size, nil
}
// Import реализует основной метод интерфейса.
func (i *SimpleZipImporter) Import(zipPath string) ([]models.ModpackFile, error) {
r, err := zip.OpenReader(zipPath)
if err != nil {
return nil, err
}
defer r.Close()
var files []models.ModpackFile
for _, f := range r.File {
if f.FileInfo().IsDir() {
continue
}
fileReader, err := f.Open()
if err != nil {
return nil, fmt.Errorf("failed to open file in zip %s: %w", f.Name, err)
}
defer fileReader.Close()
hash, size, err := i.processFile(fileReader)
if err != nil {
return nil, fmt.Errorf("failed to process file %s: %w", f.Name, err)
}
files = append(files, models.ModpackFile{
RelativePath: f.Name,
FileHash: hash,
FileSize: size,
})
}
return files, nil
}