Initialize AutoLibrary website with Gitea deployment
This commit is contained in:
commit
18216953e7
101 files changed
+12581
No files matched your search
@@ -0,0 +1,117 @@
|
||||
package themes_service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"autolibrary.top/webserver/backend/models/themes_model"
|
||||
"autolibrary.top/webserver/backend/services/theme_files"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Service coordinates database changes and their corresponding theme archive.
|
||||
type Service struct {
|
||||
DB *gorm.DB
|
||||
Files *theme_files.Store
|
||||
locks sync.Map
|
||||
}
|
||||
|
||||
func (s *Service) lock(id uint) func() {
|
||||
value, _ := s.locks.LoadOrStore(id, &sync.Mutex{})
|
||||
mutex := value.(*sync.Mutex)
|
||||
mutex.Lock()
|
||||
return mutex.Unlock
|
||||
}
|
||||
|
||||
func (s *Service) ArchivePath(id uint) string {
|
||||
return filepath.Join(s.Files.Root(), fmt.Sprintf("%d.altheme", id))
|
||||
}
|
||||
|
||||
func (s *Service) Create(theme *themes_model.Theme, qss []byte) error {
|
||||
var path string
|
||||
err := s.DB.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(theme).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
path = s.ArchivePath(theme.ID)
|
||||
data, err := theme_files.CreateAlthemeArchive(qss, theme_files.BuildInfoJSON(*theme))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Files.WriteFile(path, data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
theme.FilePath = path
|
||||
theme.FileSize = fmt.Sprintf("%.1f KB", float64(len(data))/1024)
|
||||
return tx.Save(theme).Error
|
||||
})
|
||||
if err != nil && path != "" {
|
||||
_ = s.Files.Remove(path)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) Save(theme *themes_model.Theme, qss []byte) error {
|
||||
unlock := s.lock(theme.ID)
|
||||
defer unlock()
|
||||
path := s.ArchivePath(theme.ID)
|
||||
previous, readErr := os.ReadFile(path)
|
||||
if qss == nil {
|
||||
var err error
|
||||
qss, err = theme_files.ExtractQSSFromAltheme(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read existing theme archive: %w", err)
|
||||
}
|
||||
}
|
||||
data, err := theme_files.CreateAlthemeArchive(qss, theme_files.BuildInfoJSON(*theme))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
theme.FilePath = path
|
||||
theme.FileSize = fmt.Sprintf("%.1f KB", float64(len(data))/1024)
|
||||
wrote := false
|
||||
err = s.DB.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Save(theme).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Files.WriteFile(path, data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
wrote = true
|
||||
return nil
|
||||
})
|
||||
if err != nil && wrote {
|
||||
var restoreErr error
|
||||
if readErr == nil {
|
||||
restoreErr = s.Files.WriteFile(path, previous, 0644)
|
||||
} else {
|
||||
restoreErr = s.Files.Remove(path)
|
||||
}
|
||||
if restoreErr != nil {
|
||||
log.Printf("[E] archive rollback failed for theme %d: %v", theme.ID, restoreErr)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) Delete(theme *themes_model.Theme) error {
|
||||
unlock := s.lock(theme.ID)
|
||||
defer unlock()
|
||||
if err := s.DB.Delete(theme).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
paths := []string{s.ArchivePath(theme.ID)}
|
||||
if theme.PreviewURL != "" {
|
||||
paths = append(paths, filepath.Join(s.Files.Root(), "previews", filepath.Base(theme.PreviewURL)))
|
||||
}
|
||||
for _, path := range paths {
|
||||
if err := s.Files.Remove(path); err != nil {
|
||||
log.Printf("[W] theme %d file cleanup: %v", theme.ID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user