Files
TorrServerJellyfin/server/settings/migrate.go
2024-02-03 01:13:16 +03:00

191 lines
4.4 KiB
Go

package settings
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
"server/log"
"server/web/api/utils"
bolt "go.etcd.io/bbolt"
)
var dbTorrentsName = []byte("Torrents")
type torrentOldDB struct {
Name string
Magnet string
InfoBytes []byte
Hash string
Size int64
Timestamp int64
}
// Migrate from torrserver.db to config.db
func Migrate1() {
if _, err := os.Lstat(filepath.Join(Path, "torrserver.db")); os.IsNotExist(err) {
return
}
db, err := bolt.Open(filepath.Join(Path, "torrserver.db"), 0o666, nil)
if err != nil {
return
}
torrs := make([]*torrentOldDB, 0)
err = db.View(func(tx *bolt.Tx) error {
tdb := tx.Bucket(dbTorrentsName)
if tdb == nil {
return nil
}
c := tdb.Cursor()
for h, _ := c.First(); h != nil; h, _ = c.Next() {
hdb := tdb.Bucket(h)
if hdb != nil {
torr := new(torrentOldDB)
torr.Hash = string(h)
tmp := hdb.Get([]byte("Name"))
if tmp == nil {
return fmt.Errorf("error load torrent")
}
torr.Name = string(tmp)
tmp = hdb.Get([]byte("Link"))
if tmp == nil {
return fmt.Errorf("error load torrent")
}
torr.Magnet = string(tmp)
tmp = hdb.Get([]byte("Size"))
if tmp == nil {
return fmt.Errorf("error load torrent")
}
torr.Size = b2i(tmp)
tmp = hdb.Get([]byte("Timestamp"))
if tmp == nil {
return fmt.Errorf("error load torrent")
}
torr.Timestamp = b2i(tmp)
torrs = append(torrs, torr)
}
}
return nil
})
db.Close()
if err == nil && len(torrs) > 0 {
for _, torr := range torrs {
spec, err := utils.ParseLink(torr.Magnet)
if err != nil {
continue
}
title := torr.Name
if len(spec.DisplayName) > len(title) {
title = spec.DisplayName
}
log.TLogln("Migrate torrent", torr.Name, torr.Hash, torr.Size)
AddTorrent(&TorrentDB{
TorrentSpec: spec,
Title: title,
Timestamp: torr.Timestamp,
Size: torr.Size,
})
}
}
os.Remove(filepath.Join(Path, "torrserver.db"))
}
func b2i(v []byte) int64 {
return int64(binary.BigEndian.Uint64(v))
}
/*
=== Migrate 2 ===
Migrate 'Settings' and 'Viewed' buckets from BBolt ('config.db')
to separate JSON files ('settings.json' and 'viewed.json')
'Torrents' data continues to remain in the BBolt database ('config.db')
due to the fact that BLOBs are stored there
To make user be able to roll settings back, no data is deleted from 'config.db' file.
*/
func Migrate2(bboltDB, jsonDB TorrServerDB) error {
var err error = nil
const XPATH_SETTINGS = "Settings"
const NAME_BITTORR = "BitTorr"
const XPATH_VIEWED = "Viewed"
if BTsets != nil {
msg := "Migrate0002 MUST be called before initializing BTSets"
log.TLogln(msg)
os.Exit(1)
}
isByteArraysEqualJson := func(a, b []byte) (bool, error) {
var objectA interface{}
var objectB interface{}
var err error = nil
if err = json.Unmarshal(a, &objectA); err == nil {
if err = json.Unmarshal(b, &objectB); err == nil {
return reflect.DeepEqual(objectA, objectB), nil
} else {
err = fmt.Errorf("Error unmashalling B: %s", err.Error())
}
} else {
err = fmt.Errorf("Error unmashalling A: %s", err.Error())
}
return false, err
}
migrateXPath := func(xPath, name string) error {
if jsonDB.Get(xPath, name) == nil {
bboltDBBlob := bboltDB.Get(xPath, name)
if bboltDBBlob != nil {
log.TLogln(fmt.Sprintf("Attempting to migrate %s->%s from TDB to JsonDB", xPath, name))
jsonDB.Set(xPath, name, bboltDBBlob)
jsonDBBlob := jsonDB.Get(xPath, name)
if isEqual, err := isByteArraysEqualJson(bboltDBBlob, jsonDBBlob); err == nil {
if isEqual {
log.TLogln(fmt.Sprintf("Migrated %s->%s successful", xPath, name))
} else {
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: equality check failed", xPath, name)
log.TLogln(msg)
return errors.New(msg)
}
} else {
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: %s", xPath, name, err)
log.TLogln(msg)
return errors.New(msg)
}
}
}
return nil
}
if err = migrateXPath(XPATH_SETTINGS, NAME_BITTORR); err != nil {
return err
}
jsonDBViewedNames := jsonDB.List(XPATH_VIEWED)
if len(jsonDBViewedNames) <= 0 {
bboltDBViewedNames := bboltDB.List(XPATH_VIEWED)
if len(bboltDBViewedNames) > 0 {
for _, name := range bboltDBViewedNames {
err = migrateXPath(XPATH_VIEWED, name)
if err != nil {
break
}
}
}
}
return err
}