mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 09:37:38 +00:00
20999401b2
Cherry pick PR #9295 --------- Co-authored-by: Alex Sharov <AskAlexSharov@gmail.com>
150 lines
3.7 KiB
Go
150 lines
3.7 KiB
Go
package downloader
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/anacrolix/torrent"
|
|
"github.com/anacrolix/torrent/metainfo"
|
|
dir2 "github.com/ledgerwatch/erigon-lib/common/dir"
|
|
)
|
|
|
|
// TorrentFiles - does provide thread-safe CRUD operations on .torrent files
|
|
type TorrentFiles struct {
|
|
lock sync.Mutex
|
|
dir string
|
|
}
|
|
|
|
func NewAtomicTorrentFiles(dir string) *TorrentFiles {
|
|
return &TorrentFiles{dir: dir}
|
|
}
|
|
|
|
func (tf *TorrentFiles) Exists(name string) bool {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.exists(name)
|
|
}
|
|
|
|
func (tf *TorrentFiles) exists(name string) bool {
|
|
if !strings.HasSuffix(name, ".torrent") {
|
|
name += ".torrent"
|
|
}
|
|
return dir2.FileExist(filepath.Join(tf.dir, name))
|
|
}
|
|
func (tf *TorrentFiles) Delete(name string) error {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.delete(name)
|
|
}
|
|
|
|
func (tf *TorrentFiles) delete(name string) error {
|
|
if !strings.HasSuffix(name, ".torrent") {
|
|
name += ".torrent"
|
|
}
|
|
return os.Remove(filepath.Join(tf.dir, name))
|
|
}
|
|
|
|
func (tf *TorrentFiles) Create(torrentFilePath string, res []byte) error {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.create(torrentFilePath, res)
|
|
}
|
|
func (tf *TorrentFiles) create(torrentFilePath string, res []byte) error {
|
|
if len(res) == 0 {
|
|
return fmt.Errorf("try to write 0 bytes to file: %s", torrentFilePath)
|
|
}
|
|
f, err := os.Create(torrentFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(res); err != nil {
|
|
return err
|
|
}
|
|
if err = f.Sync(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tf *TorrentFiles) CreateTorrentFromMetaInfo(fPath string, mi *metainfo.MetaInfo) error {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.createTorrentFromMetaInfo(fPath, mi)
|
|
}
|
|
func (tf *TorrentFiles) createTorrentFromMetaInfo(fPath string, mi *metainfo.MetaInfo) error {
|
|
file, err := os.Create(fPath + ".tmp")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
if err := mi.Write(file); err != nil {
|
|
return err
|
|
}
|
|
if err := file.Sync(); err != nil {
|
|
return err
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Rename(fPath+".tmp", fPath); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tf *TorrentFiles) LoadByName(name string) (*torrent.TorrentSpec, error) {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.load(filepath.Join(tf.dir, name))
|
|
}
|
|
|
|
func (tf *TorrentFiles) LoadByPath(fPath string) (*torrent.TorrentSpec, error) {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return tf.load(fPath)
|
|
}
|
|
|
|
func (tf *TorrentFiles) load(fPath string) (*torrent.TorrentSpec, error) {
|
|
if !strings.HasSuffix(fPath, ".torrent") {
|
|
fPath += ".torrent"
|
|
}
|
|
mi, err := metainfo.LoadFromFile(fPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("LoadFromFile: %w, file=%s", err, fPath)
|
|
}
|
|
mi.AnnounceList = Trackers
|
|
return torrent.TorrentSpecFromMetaInfoErr(mi)
|
|
}
|
|
|
|
const ProhibitNewDownloadsFileName = "prohibit_new_downloads.lock"
|
|
|
|
// Erigon "download once" - means restart/upgrade/downgrade will not download files (and will be fast)
|
|
// After "download once" - Erigon will produce and seed new files
|
|
// Downloader will able: seed new files (already existing on FS), download uncomplete parts of existing files (if Verify found some bad parts)
|
|
func (tf *TorrentFiles) prohibitNewDownloads() error {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return CreateProhibitNewDownloadsFile(tf.dir)
|
|
}
|
|
func (tf *TorrentFiles) newDownloadsAreProhibited() bool {
|
|
tf.lock.Lock()
|
|
defer tf.lock.Unlock()
|
|
return dir2.FileExist(filepath.Join(tf.dir, ProhibitNewDownloadsFileName))
|
|
}
|
|
func CreateProhibitNewDownloadsFile(dir string) error {
|
|
fPath := filepath.Join(dir, ProhibitNewDownloadsFileName)
|
|
f, err := os.Create(fPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if err := f.Sync(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|