Проверенная версия на разных архитектурах

master v1.1.0
Роман Бородин 2022-03-25 01:27:42 +03:00
parent afe5f9a232
commit ed0f8b5c21
3 changed files with 36 additions and 32 deletions

View File

@ -10,12 +10,13 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
) )
const boltDbDir = `piece_complete_db` const refreshSec = 3
type TorrentStatus struct { type TorrentStatus struct {
DownloadRate int64 DownloadRate int64
@ -48,6 +49,7 @@ type Engine struct {
upRate int64 upRate int64
seeds int64 seeds int64
} }
fs FileStatus
} }
func (o *Engine) IsAlive() bool { func (o *Engine) IsAlive() bool {
@ -60,6 +62,7 @@ func (o *Engine) StartTorrent(idx int64) error {
o.torrCfg.ListenPort = o.settings.ListenPort o.torrCfg.ListenPort = o.settings.ListenPort
o.torrCfg.DataDir = o.settings.DownloadPath o.torrCfg.DataDir = o.settings.DownloadPath
o.torrCfg.DefaultStorage = storage.NewFileWithCompletion(o.settings.DownloadPath, storage.NewMapPieceCompletion()) o.torrCfg.DefaultStorage = storage.NewFileWithCompletion(o.settings.DownloadPath, storage.NewMapPieceCompletion())
if o.settings.Proxy != "" { if o.settings.Proxy != "" {
if u, err := url.Parse(o.settings.Proxy); err != nil { if u, err := url.Parse(o.settings.Proxy); err != nil {
o.torrCfg.HTTPProxy = func(request *http.Request) (*url.URL, error) { return u, nil } o.torrCfg.HTTPProxy = func(request *http.Request) (*url.URL, error) { return u, nil }
@ -82,6 +85,8 @@ func (o *Engine) StartTorrent(idx int64) error {
t := o.torrent t := o.torrent
<-t.GotInfo() <-t.GotInfo()
o.setStaticFileStatusData(idx)
file := o.torrent.Files()[idx] file := o.torrent.Files()[idx]
// отключаем загрузку всех файлов // отключаем загрузку всех файлов
@ -92,12 +97,8 @@ func (o *Engine) StartTorrent(idx int64) error {
endPieceIndex := (file.Offset() + file.Length()) * int64(t.NumPieces()) / t.Length() endPieceIndex := (file.Offset() + file.Length()) * int64(t.NumPieces()) / t.Length()
o.torrent.DownloadPieces(int(firstPieceIndex), int(endPieceIndex)) o.torrent.DownloadPieces(int(firstPieceIndex), int(endPieceIndex))
for i := firstPieceIndex; i <= endPieceIndex*5/100; i++ {
t.Piece(int(i)).SetPriority(torrent.PiecePriorityNow)
}
go func() { go func() {
ticker := time.NewTicker(time.Second) ticker := time.NewTicker(time.Second * refreshSec)
defer ticker.Stop() defer ticker.Stop()
for { for {
select { select {
@ -131,18 +132,34 @@ func (o *Engine) StartTorrent(idx int64) error {
return nil return nil
} }
func (o *Engine) setStaticFileStatusData(i int64) {
o.fs = FileStatus{}
file := o.torrent.Files()[i]
pathParts := strings.Split(file.DisplayPath(), `/`)
o.fs.Name = file.DisplayPath()
for idx := range pathParts {
pathParts[idx] = url.QueryEscape(pathParts[idx])
}
o.fs.Url = fmt.Sprintf(`http://%s:%d/files/%s`, o.settings.HttpBindHost, o.settings.HttpBindPort, strings.Join(pathParts, `/`))
o.fs.Length = file.Length()
if o.fs.Length < 0 {
o.fs.Length *= -1
}
}
func (o *Engine) updateStats() { func (o *Engine) updateStats() {
stats := o.torrent.Stats() stats := o.torrent.Stats()
if o.status.lastBytesReadData == 0 { if o.status.lastBytesReadData == 0 {
o.status.downRate = 0 o.status.downRate = 0
} else { } else {
o.status.downRate = (stats.BytesReadData.Int64() - o.status.lastBytesReadData) / 1024 o.status.downRate = (stats.BytesReadData.Int64() - o.status.lastBytesReadData) / 1024 / refreshSec
} }
o.status.lastBytesReadData = stats.BytesReadData.Int64() o.status.lastBytesReadData = stats.BytesReadData.Int64()
if o.status.lastBytesWrittenData == 0 { if o.status.lastBytesWrittenData == 0 {
o.status.upRate = 0 o.status.upRate = 0
} else { } else {
o.status.upRate = (stats.BytesWrittenData.Int64() - o.status.lastBytesWrittenData) / 1024 o.status.upRate = (stats.BytesWrittenData.Int64() - o.status.lastBytesWrittenData) / 1024 / refreshSec
} }
o.status.lastBytesWrittenData = stats.BytesWrittenData.Int64() o.status.lastBytesWrittenData = stats.BytesWrittenData.Int64()
o.status.seeds = int64(stats.ConnectedSeeders) o.status.seeds = int64(stats.ConnectedSeeders)
@ -156,28 +173,15 @@ func (o *Engine) Status() TorrentStatus {
return res return res
} }
func (o *Engine) FileStatus(i int) (FileStatus, error) { func (o *Engine) FileStatus(i int) (FileStatus, error) {
fs := FileStatus{}
if i < 0 || i > len(o.torrent.Files())-1 { if i < 0 || i > len(o.torrent.Files())-1 {
return fs, fmt.Errorf(`file index out of range: %d`, i) return o.fs, fmt.Errorf(`file index out of range: %d`, i)
} }
file := o.torrent.Files()[i] file := o.torrent.Files()[i]
o.fs.Progress = int64(float64(file.BytesCompleted()) / float64(file.Length()) * 100.0)
pathParts := strings.Split(file.DisplayPath(), `/`) if o.fs.Progress < 0 {
fs.Name = file.DisplayPath() o.fs.Progress *= -1
for idx := range pathParts {
pathParts[idx] = url.QueryEscape(pathParts[idx])
} }
fs.Url = fmt.Sprintf(`http://%s:%d/files/%s`, o.settings.HttpBindHost, o.settings.HttpBindPort, strings.Join(pathParts, `/`)) return o.fs, nil
fs.Progress = int64(float64(file.BytesCompleted()) / float64(file.Length()) * 100.0)
if fs.Progress < 0 {
fs.Progress *= -1
}
fs.Length = file.Length()
if fs.Length < 0 {
fs.Length *= -1
}
return fs, nil
} }
func (o *Engine) Stop() { func (o *Engine) Stop() {
@ -201,6 +205,7 @@ func (o *Engine) Stop() {
} }
o.syncDebug(`torrent engine stopped`) o.syncDebug(`torrent engine stopped`)
o.shutdown()
close(o.msgs) close(o.msgs)
o.alive = false o.alive = false
}() }()
@ -276,8 +281,6 @@ func (o *Engine) syncInfo(t string, a ...interface{}) {
func (o *Engine) GetFileHandler(target *torrent.File) func(http.ResponseWriter, *http.Request) { func (o *Engine) GetFileHandler(target *torrent.File) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
entry := target.NewReader() entry := target.NewReader()
entry.SetReadahead(target.Length() / 100)
entry.SetResponsive()
defer func() { defer func() {
if err := entry.Close(); err != nil { if err := entry.Close(); err != nil {
@ -285,9 +288,7 @@ func (o *Engine) GetFileHandler(target *torrent.File) func(http.ResponseWriter,
} }
}() }()
pathParts := strings.Split(target.DisplayPath(), `/`) w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(target.DisplayPath()))
w.Header().Set("Content-Disposition", "attachment; filename=\""+pathParts[len(pathParts)-1]+"\"")
http.ServeContent(w, r, target.DisplayPath(), time.Now(), entry) http.ServeContent(w, r, target.DisplayPath(), time.Now(), entry)
} }
} }

3
go.mod
View File

@ -3,6 +3,7 @@ module gorrent
go 1.17 go 1.17
require ( require (
github.com/anacrolix/missinggo/v2 v2.5.2
github.com/anacrolix/torrent v1.41.0 github.com/anacrolix/torrent v1.41.0
github.com/go-python/gopy v0.4.0 github.com/go-python/gopy v0.4.0
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
@ -18,7 +19,6 @@ require (
github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8 // indirect github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8 // indirect
github.com/anacrolix/missinggo v1.3.0 // indirect github.com/anacrolix/missinggo v1.3.0 // indirect
github.com/anacrolix/missinggo/perf v1.0.0 // indirect github.com/anacrolix/missinggo/perf v1.0.0 // indirect
github.com/anacrolix/missinggo/v2 v2.5.2 // indirect
github.com/anacrolix/mmsg v1.0.0 // indirect github.com/anacrolix/mmsg v1.0.0 // indirect
github.com/anacrolix/multiless v0.2.0 // indirect github.com/anacrolix/multiless v0.2.0 // indirect
github.com/anacrolix/stm v0.3.0 // indirect github.com/anacrolix/stm v0.3.0 // indirect
@ -57,6 +57,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686 // indirect github.com/rs/dnscache v0.0.0-20210201191234-295bba877686 // indirect
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
go.etcd.io/bbolt v1.3.6 // indirect go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect

View File

@ -4,6 +4,8 @@ import "context"
var version = `1.0.0` var version = `1.0.0`
const defaultMaxReadaheadBytes = 20 * 1024 * 1024
func GetMetaFromFile(path string) (*Info, error) { func GetMetaFromFile(path string) (*Info, error) {
info := &Info{} info := &Info{}
if err := info.LoadFile(path); err != nil { if err := info.LoadFile(path); err != nil {