mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-21 14:36:09 +05:00
init 1.2.x
This commit is contained in:
@@ -1,185 +0,0 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"server/settings"
|
||||
"server/torr/storage/memcache"
|
||||
"server/torr/storage/state"
|
||||
"server/utils"
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
)
|
||||
|
||||
type BTServer struct {
|
||||
config *torrent.ClientConfig
|
||||
client *torrent.Client
|
||||
|
||||
storage *memcache.Storage
|
||||
|
||||
torrents map[metainfo.Hash]*Torrent
|
||||
|
||||
mu sync.Mutex
|
||||
wmu sync.Mutex
|
||||
|
||||
watching bool
|
||||
}
|
||||
|
||||
func NewBTS() *BTServer {
|
||||
bts := new(BTServer)
|
||||
bts.torrents = make(map[metainfo.Hash]*Torrent)
|
||||
return bts
|
||||
}
|
||||
|
||||
func (bt *BTServer) Connect() error {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
var err error
|
||||
bt.configure()
|
||||
bt.client, err = torrent.NewClient(bt.config)
|
||||
bt.torrents = make(map[metainfo.Hash]*Torrent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (bt *BTServer) Disconnect() {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
if bt.client != nil {
|
||||
bt.client.Close()
|
||||
bt.client = nil
|
||||
utils.FreeOSMemGC()
|
||||
}
|
||||
}
|
||||
|
||||
func (bt *BTServer) Reconnect() error {
|
||||
bt.Disconnect()
|
||||
return bt.Connect()
|
||||
}
|
||||
|
||||
func (bt *BTServer) configure() {
|
||||
bt.storage = memcache.NewStorage(settings.Get().CacheSize)
|
||||
|
||||
//blocklist, _ := iplist.MMapPackedFile(filepath.Join(settings.Path, "blocklist"))
|
||||
blocklist, _ := utils.ReadBlockedIP()
|
||||
|
||||
userAgent := "uTorrent/3.5.5"
|
||||
peerID := "-UT3550-"
|
||||
cliVers := "µTorrent 3.5.5"
|
||||
|
||||
bt.config = torrent.NewDefaultClientConfig()
|
||||
|
||||
bt.config.Debug = settings.Get().EnableDebug
|
||||
bt.config.DisableIPv6 = settings.Get().EnableIPv6 == false
|
||||
bt.config.DisableTCP = settings.Get().DisableTCP
|
||||
bt.config.DisableUTP = settings.Get().DisableUTP
|
||||
bt.config.NoDefaultPortForwarding = settings.Get().DisableUPNP
|
||||
bt.config.NoDHT = settings.Get().DisableDHT
|
||||
bt.config.NoUpload = settings.Get().DisableUpload
|
||||
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{
|
||||
DisableEncryption: settings.Get().Encryption == 1,
|
||||
ForceEncryption: settings.Get().Encryption == 2,
|
||||
}
|
||||
bt.config.IPBlocklist = blocklist
|
||||
bt.config.DefaultStorage = bt.storage
|
||||
bt.config.Bep20 = peerID
|
||||
bt.config.PeerID = utils.PeerIDRandom(peerID)
|
||||
bt.config.HTTPUserAgent = userAgent
|
||||
bt.config.ExtendedHandshakeClientVersion = cliVers
|
||||
bt.config.EstablishedConnsPerTorrent = settings.Get().ConnectionsLimit
|
||||
if settings.Get().DhtConnectionLimit > 0 {
|
||||
bt.config.ConnTracker.SetMaxEntries(settings.Get().DhtConnectionLimit)
|
||||
}
|
||||
if settings.Get().DownloadRateLimit > 0 {
|
||||
bt.config.DownloadRateLimiter = utils.Limit(settings.Get().DownloadRateLimit * 1024)
|
||||
}
|
||||
if settings.Get().UploadRateLimit > 0 {
|
||||
bt.config.UploadRateLimiter = utils.Limit(settings.Get().UploadRateLimit * 1024)
|
||||
}
|
||||
if settings.Get().PeersListenPort > 0 {
|
||||
bt.config.ListenPort = settings.Get().PeersListenPort
|
||||
}
|
||||
|
||||
log.Println("Configure client:", settings.Get())
|
||||
}
|
||||
|
||||
func (bt *BTServer) AddTorrent(magnet metainfo.Magnet, infobytes []byte, onAdd func(*Torrent)) (*Torrent, error) {
|
||||
torr, err := NewTorrent(magnet, infobytes, bt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if onAdd != nil {
|
||||
go func() {
|
||||
if torr.GotInfo() {
|
||||
onAdd(torr)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
go torr.GotInfo()
|
||||
}
|
||||
|
||||
return torr, nil
|
||||
}
|
||||
|
||||
func (bt *BTServer) List() []*Torrent {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
list := make([]*Torrent, 0)
|
||||
for _, t := range bt.torrents {
|
||||
list = append(list, t)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (bt *BTServer) GetTorrent(hash metainfo.Hash) *Torrent {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
|
||||
if t, ok := bt.torrents[hash]; ok {
|
||||
return t
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) {
|
||||
if torr, ok := bt.torrents[hash]; ok {
|
||||
torr.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (bt *BTServer) BTState() *BTState {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
|
||||
btState := new(BTState)
|
||||
btState.LocalPort = bt.client.LocalPort()
|
||||
btState.PeerID = fmt.Sprintf("%x", bt.client.PeerID())
|
||||
btState.BannedIPs = len(bt.client.BadPeerIPs())
|
||||
for _, dht := range bt.client.DhtServers() {
|
||||
btState.DHTs = append(btState.DHTs, dht)
|
||||
}
|
||||
for _, t := range bt.torrents {
|
||||
btState.Torrents = append(btState.Torrents, t)
|
||||
}
|
||||
return btState
|
||||
}
|
||||
|
||||
func (bt *BTServer) CacheState(hash metainfo.Hash) *state.CacheState {
|
||||
st := bt.GetTorrent(hash)
|
||||
if st == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cacheState := bt.storage.GetStats(hash)
|
||||
return cacheState
|
||||
}
|
||||
|
||||
func (bt *BTServer) WriteState(w io.Writer) {
|
||||
bt.client.WriteStatus(w)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"server/settings"
|
||||
"server/utils"
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/anacrolix/missinggo/httptoo"
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
func (bt *BTServer) View(torr *Torrent, file *torrent.File, c echo.Context) error {
|
||||
go settings.SetViewed(torr.Hash().HexString(), file.Path())
|
||||
reader := torr.NewReader(file, 0)
|
||||
|
||||
log.Println("Connect client")
|
||||
c.Response().Header().Set("Connection", "close")
|
||||
c.Response().Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", torr.Hash().HexString(), file.Path())))
|
||||
|
||||
http.ServeContent(c.Response(), c.Request(), file.Path(), time.Time{}, reader)
|
||||
|
||||
log.Println("Disconnect client")
|
||||
torr.CloseReader(reader)
|
||||
return c.NoContent(http.StatusOK)
|
||||
}
|
||||
|
||||
func (bt *BTServer) Play(torr *Torrent, file *torrent.File, preload int64, c echo.Context) error {
|
||||
if torr.status == TorrentAdded {
|
||||
if !torr.GotInfo() {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info")
|
||||
}
|
||||
}
|
||||
if torr.status == TorrentGettingInfo {
|
||||
if !torr.WaitInfo() {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info")
|
||||
}
|
||||
}
|
||||
|
||||
if torr.PreloadedBytes == 0 {
|
||||
torr.Preload(file, preload)
|
||||
}
|
||||
|
||||
redirectUrl := c.Scheme() + "://" + c.Request().Host + "/torrent/view/" + torr.Hash().HexString() + "/" + utils.CleanFName(file.Path())
|
||||
return c.Redirect(http.StatusFound, redirectUrl)
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/dht"
|
||||
)
|
||||
|
||||
type BTState struct {
|
||||
LocalPort int
|
||||
PeerID string
|
||||
BannedIPs int
|
||||
DHTs []*dht.Server
|
||||
|
||||
Torrents []*Torrent
|
||||
}
|
||||
|
||||
type TorrentStats struct {
|
||||
Name string
|
||||
Hash string
|
||||
|
||||
TorrentStatus TorrentStatus
|
||||
TorrentStatusString string
|
||||
|
||||
LoadedSize int64
|
||||
TorrentSize int64
|
||||
|
||||
PreloadedBytes int64
|
||||
PreloadSize int64
|
||||
|
||||
DownloadSpeed float64
|
||||
UploadSpeed float64
|
||||
|
||||
TotalPeers int
|
||||
PendingPeers int
|
||||
ActivePeers int
|
||||
ConnectedSeeders int
|
||||
HalfOpenPeers int
|
||||
|
||||
BytesWritten int64
|
||||
BytesWrittenData int64
|
||||
BytesRead int64
|
||||
BytesReadData int64
|
||||
BytesReadUsefulData int64
|
||||
ChunksWritten int64
|
||||
ChunksRead int64
|
||||
ChunksReadUseful int64
|
||||
ChunksReadWasted int64
|
||||
PiecesDirtiedGood int64
|
||||
PiecesDirtiedBad int64
|
||||
|
||||
FileStats []TorrentFileStat
|
||||
}
|
||||
|
||||
type TorrentFileStat struct {
|
||||
Id int
|
||||
Path string
|
||||
Length int64
|
||||
}
|
||||
106
src/server/torr/btserver.go
Normal file
106
src/server/torr/btserver.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"server/settings"
|
||||
"server/torr/storage/torrstor"
|
||||
"server/torr/utils"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
)
|
||||
|
||||
type BTServer struct {
|
||||
config *torrent.ClientConfig
|
||||
client *torrent.Client
|
||||
|
||||
storage *torrstor.Storage
|
||||
|
||||
torrents map[metainfo.Hash]*Torrent
|
||||
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewBTS() *BTServer {
|
||||
bts := new(BTServer)
|
||||
bts.torrents = make(map[metainfo.Hash]*Torrent)
|
||||
return bts
|
||||
}
|
||||
|
||||
func (bt *BTServer) Connect() error {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
var err error
|
||||
bt.configure()
|
||||
bt.client, err = torrent.NewClient(bt.config)
|
||||
bt.torrents = make(map[metainfo.Hash]*Torrent)
|
||||
return err
|
||||
}
|
||||
|
||||
func (bt *BTServer) Disconnect() {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
if bt.client != nil {
|
||||
bt.client.Close()
|
||||
bt.client = nil
|
||||
utils.FreeOSMemGC()
|
||||
}
|
||||
}
|
||||
|
||||
func (bt *BTServer) Reconnect() error {
|
||||
bt.Disconnect()
|
||||
return bt.Connect()
|
||||
}
|
||||
|
||||
func (bt *BTServer) configure() {
|
||||
bt.storage = torrstor.NewStorage(settings.BTsets.CacheSize)
|
||||
|
||||
blocklist, _ := utils.ReadBlockedIP()
|
||||
|
||||
userAgent := "uTorrent/3.5.5"
|
||||
peerID := "-UT3550-"
|
||||
cliVers := "µTorrent 3.5.5"
|
||||
|
||||
bt.config = torrent.NewDefaultClientConfig()
|
||||
|
||||
bt.config.Debug = settings.BTsets.EnableDebug
|
||||
bt.config.DisableIPv6 = settings.BTsets.EnableIPv6 == false
|
||||
bt.config.DisableTCP = settings.BTsets.DisableTCP
|
||||
bt.config.DisableUTP = settings.BTsets.DisableUTP
|
||||
bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP
|
||||
bt.config.NoDHT = settings.BTsets.DisableDHT
|
||||
bt.config.NoUpload = settings.BTsets.DisableUpload
|
||||
// bt.config.EncryptionPolicy = torrent.EncryptionPolicy{
|
||||
// DisableEncryption: settings.BTsets.Encryption == 1,
|
||||
// ForceEncryption: settings.BTsets.Encryption == 2,
|
||||
// }
|
||||
bt.config.IPBlocklist = blocklist
|
||||
bt.config.DefaultStorage = bt.storage
|
||||
bt.config.Bep20 = peerID
|
||||
bt.config.PeerID = utils.PeerIDRandom(peerID)
|
||||
bt.config.HTTPUserAgent = userAgent
|
||||
bt.config.ExtendedHandshakeClientVersion = cliVers
|
||||
bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
|
||||
if settings.BTsets.DhtConnectionLimit > 0 {
|
||||
bt.config.ConnTracker.SetMaxEntries(settings.BTsets.DhtConnectionLimit)
|
||||
}
|
||||
if settings.BTsets.DownloadRateLimit > 0 {
|
||||
bt.config.DownloadRateLimiter = utils.Limit(settings.BTsets.DownloadRateLimit * 1024)
|
||||
}
|
||||
if settings.BTsets.UploadRateLimit > 0 {
|
||||
bt.config.UploadRateLimiter = utils.Limit(settings.BTsets.UploadRateLimit * 1024)
|
||||
}
|
||||
if settings.BTsets.PeersListenPort > 0 {
|
||||
bt.config.ListenPort = settings.BTsets.PeersListenPort
|
||||
}
|
||||
|
||||
log.Println("Configure client:", settings.BTsets)
|
||||
}
|
||||
|
||||
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) {
|
||||
if torr, ok := bt.torrents[hash]; ok {
|
||||
torr.Close()
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package reader
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/torrent"
|
||||
"server/torr"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -12,10 +14,16 @@ type Reader struct {
|
||||
file *torrent.File
|
||||
}
|
||||
|
||||
func NewReader(file *torrent.File) *Reader {
|
||||
func NewReader(torr *torr.Torrent, file *torrent.File, readahead int64) *Reader {
|
||||
r := new(Reader)
|
||||
r.file = file
|
||||
r.Reader = file.NewReader()
|
||||
|
||||
if readahead <= 0 {
|
||||
readahead = torr.Torrent.Info().PieceLength
|
||||
}
|
||||
r.SetReadahead(readahead)
|
||||
torr.GetCache().AddReader(r)
|
||||
return r
|
||||
}
|
||||
|
||||
130
src/server/torr/state.go
Normal file
130
src/server/torr/state.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
)
|
||||
|
||||
type BTState struct {
|
||||
LocalPort int
|
||||
PeerID string
|
||||
BannedIPs int
|
||||
DHTs []torrent.DhtServer
|
||||
|
||||
Torrents []*Torrent
|
||||
}
|
||||
|
||||
func (bt *BTServer) BTState() *BTState {
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
|
||||
btState := new(BTState)
|
||||
btState.LocalPort = bt.client.LocalPort()
|
||||
btState.PeerID = fmt.Sprintf("%x", bt.client.PeerID())
|
||||
btState.BannedIPs = len(bt.client.BadPeerIPs())
|
||||
btState.DHTs = bt.client.DhtServers()
|
||||
|
||||
for _, t := range bt.torrents {
|
||||
btState.Torrents = append(btState.Torrents, t)
|
||||
}
|
||||
return btState
|
||||
}
|
||||
|
||||
type TorrentStats struct {
|
||||
Name string
|
||||
Hash string
|
||||
|
||||
TorrentStatus TorrentStatus
|
||||
TorrentStatusString string
|
||||
|
||||
LoadedSize int64
|
||||
TorrentSize int64
|
||||
|
||||
PreloadedBytes int64
|
||||
PreloadSize int64
|
||||
|
||||
DownloadSpeed float64
|
||||
UploadSpeed float64
|
||||
|
||||
TotalPeers int
|
||||
PendingPeers int
|
||||
ActivePeers int
|
||||
ConnectedSeeders int
|
||||
HalfOpenPeers int
|
||||
|
||||
BytesWritten int64
|
||||
BytesWrittenData int64
|
||||
BytesRead int64
|
||||
BytesReadData int64
|
||||
BytesReadUsefulData int64
|
||||
ChunksWritten int64
|
||||
ChunksRead int64
|
||||
ChunksReadUseful int64
|
||||
ChunksReadWasted int64
|
||||
PiecesDirtiedGood int64
|
||||
PiecesDirtiedBad int64
|
||||
|
||||
FileStats []TorrentFileStat
|
||||
}
|
||||
|
||||
type TorrentFileStat struct {
|
||||
Id int
|
||||
Path string
|
||||
Length int64
|
||||
}
|
||||
|
||||
func (t *Torrent) Stats() TorrentStats {
|
||||
t.muTorrent.Lock()
|
||||
defer t.muTorrent.Unlock()
|
||||
|
||||
st := TorrentStats{}
|
||||
|
||||
st.Name = t.Name()
|
||||
st.Hash = t.hash.HexString()
|
||||
st.TorrentStatus = t.status
|
||||
st.TorrentStatusString = t.status.String()
|
||||
|
||||
if t.Torrent != nil {
|
||||
st.LoadedSize = t.Torrent.BytesCompleted()
|
||||
st.TorrentSize = t.Length()
|
||||
st.PreloadedBytes = t.PreloadedBytes
|
||||
st.PreloadSize = t.PreloadSize
|
||||
st.DownloadSpeed = t.DownloadSpeed
|
||||
st.UploadSpeed = t.UploadSpeed
|
||||
|
||||
tst := t.Torrent.Stats()
|
||||
st.BytesWritten = tst.BytesWritten.Int64()
|
||||
st.BytesWrittenData = tst.BytesWrittenData.Int64()
|
||||
st.BytesRead = tst.BytesRead.Int64()
|
||||
st.BytesReadData = tst.BytesReadData.Int64()
|
||||
st.BytesReadUsefulData = tst.BytesReadUsefulData.Int64()
|
||||
st.ChunksWritten = tst.ChunksWritten.Int64()
|
||||
st.ChunksRead = tst.ChunksRead.Int64()
|
||||
st.ChunksReadUseful = tst.ChunksReadUseful.Int64()
|
||||
st.ChunksReadWasted = tst.ChunksReadWasted.Int64()
|
||||
st.PiecesDirtiedGood = tst.PiecesDirtiedGood.Int64()
|
||||
st.PiecesDirtiedBad = tst.PiecesDirtiedBad.Int64()
|
||||
st.TotalPeers = tst.TotalPeers
|
||||
st.PendingPeers = tst.PendingPeers
|
||||
st.ActivePeers = tst.ActivePeers
|
||||
st.ConnectedSeeders = tst.ConnectedSeeders
|
||||
st.HalfOpenPeers = tst.HalfOpenPeers
|
||||
|
||||
files := t.Files()
|
||||
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].Path() < files[j].Path()
|
||||
})
|
||||
|
||||
for i, f := range files {
|
||||
st.FileStats = append(st.FileStats, TorrentFileStat{
|
||||
Id: i,
|
||||
Path: f.Path(),
|
||||
Length: f.Length(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return st
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package filecache
|
||||
@@ -1,69 +0,0 @@
|
||||
package filecache
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"server/settings"
|
||||
"server/torr/storage"
|
||||
"server/torr/storage/state"
|
||||
|
||||
"github.com/anacrolix/missinggo/filecache"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
storage2 "github.com/anacrolix/torrent/storage"
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
storage.Storage
|
||||
|
||||
caches map[metainfo.Hash]*filecache.Cache
|
||||
capacity int64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewStorage(capacity int64) storage.Storage {
|
||||
stor := new(Storage)
|
||||
stor.capacity = capacity
|
||||
stor.caches = make(map[metainfo.Hash]*filecache.Cache)
|
||||
return stor
|
||||
}
|
||||
|
||||
func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage2.TorrentImpl, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
path := filepath.Join(settings.Path, "cache", infoHash.String())
|
||||
cache, err := filecache.NewCache(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache.SetCapacity(s.capacity)
|
||||
s.caches[infoHash] = cache
|
||||
return storage2.NewResourcePieces(cache.AsResourceProvider()).OpenTorrent(info, infoHash)
|
||||
}
|
||||
|
||||
func (s *Storage) GetStats(hash metainfo.Hash) *state.CacheState {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Clean() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Storage) CloseHash(hash metainfo.Hash) {
|
||||
if s.caches == nil {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
}
|
||||
|
||||
func (s *Storage) Close() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package state
|
||||
|
||||
type CacheState struct {
|
||||
Hash string
|
||||
Capacity int64
|
||||
Filled int64
|
||||
PiecesLength int64
|
||||
PiecesCount int
|
||||
Pieces map[int]ItemState
|
||||
}
|
||||
|
||||
type ItemState struct {
|
||||
Id int
|
||||
Accessed int64
|
||||
BufferSize int64
|
||||
Completed bool
|
||||
Hash string
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"server/torr/storage/state"
|
||||
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
"github.com/anacrolix/torrent/storage"
|
||||
)
|
||||
@@ -10,6 +8,5 @@ import (
|
||||
type Storage interface {
|
||||
storage.ClientImpl
|
||||
|
||||
GetStats(hash metainfo.Hash) *state.CacheState
|
||||
CloseHash(hash metainfo.Hash)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package memcache
|
||||
package torrstor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -53,7 +53,6 @@ func (b *BufferPool) GetBuffer(p *Piece) (buff []byte, index int) {
|
||||
buff = buf.buf
|
||||
index = id
|
||||
b.frees--
|
||||
//fmt.Printf("Get buffer: %v %v %v %p\n", id, p.Id, b.frees, buff)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package memcache
|
||||
package torrstor
|
||||
|
||||
import (
|
||||
"log"
|
||||
@@ -7,8 +7,7 @@ import (
|
||||
|
||||
"server/settings"
|
||||
"server/torr/reader"
|
||||
"server/torr/storage/state"
|
||||
"server/utils"
|
||||
"server/torr/utils"
|
||||
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
"github.com/anacrolix/torrent/storage"
|
||||
@@ -101,30 +100,6 @@ func (c *Cache) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cache) GetState() state.CacheState {
|
||||
cState := state.CacheState{}
|
||||
cState.Capacity = c.capacity
|
||||
cState.PiecesLength = c.pieceLength
|
||||
cState.PiecesCount = c.pieceCount
|
||||
cState.Hash = c.hash.HexString()
|
||||
|
||||
stats := make(map[int]state.ItemState, 0)
|
||||
c.muPiece.Lock()
|
||||
var fill int64 = 0
|
||||
for _, value := range c.pieces {
|
||||
stat := value.Stat()
|
||||
if stat.BufferSize > 0 {
|
||||
fill += stat.BufferSize
|
||||
stats[stat.Id] = stat
|
||||
}
|
||||
}
|
||||
c.filled = fill
|
||||
c.muPiece.Unlock()
|
||||
cState.Filled = c.filled
|
||||
cState.Pieces = stats
|
||||
return cState
|
||||
}
|
||||
|
||||
func (c *Cache) cleanPieces() {
|
||||
if c.isRemove {
|
||||
return
|
||||
@@ -220,7 +195,7 @@ func (c *Cache) ReadersLen() int {
|
||||
func (c *Cache) AdjustRA(readahead int64) {
|
||||
c.muReader.Lock()
|
||||
defer c.muReader.Unlock()
|
||||
if settings.Get().CacheSize == 0 {
|
||||
if settings.BTsets.CacheSize == 0 {
|
||||
c.capacity = readahead * 3
|
||||
}
|
||||
for r, _ := range c.readers {
|
||||
@@ -1,4 +1,4 @@
|
||||
package memcache
|
||||
package torrstor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/torr/storage/state"
|
||||
|
||||
"github.com/anacrolix/torrent/storage"
|
||||
)
|
||||
|
||||
@@ -103,13 +101,10 @@ func (p *Piece) Release() {
|
||||
p.complete = false
|
||||
}
|
||||
|
||||
func (p *Piece) Stat() state.ItemState {
|
||||
itm := state.ItemState{
|
||||
Id: p.Id,
|
||||
Hash: p.Hash,
|
||||
Accessed: p.accessed,
|
||||
Completed: p.complete,
|
||||
BufferSize: p.Size,
|
||||
}
|
||||
return itm
|
||||
func WriteToDisk(b []byte, off int64) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func ReadFromDisk(b []byte, off int64) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package memcache
|
||||
package torrstor
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"server/torr/storage"
|
||||
"server/torr/storage/state"
|
||||
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
storage2 "github.com/anacrolix/torrent/storage"
|
||||
@@ -34,16 +33,6 @@ func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (stor
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (s *Storage) GetStats(hash metainfo.Hash) *state.CacheState {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if c, ok := s.caches[hash]; ok {
|
||||
st := c.GetState()
|
||||
return &st
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) CloseHash(hash metainfo.Hash) {
|
||||
if s.caches == nil {
|
||||
return
|
||||
31
src/server/torr/stream.go
Normal file
31
src/server/torr/stream.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package torr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/missinggo/httptoo"
|
||||
)
|
||||
|
||||
func (t *Torrent) Stream(fileIndex int, req *http.Request, resp http.ResponseWriter) error {
|
||||
files := t.Files()
|
||||
if fileIndex < 0 || fileIndex >= len(files) {
|
||||
return errors.New("file index out of range")
|
||||
}
|
||||
file := files[fileIndex]
|
||||
reader := t.NewReader(file, 0)
|
||||
|
||||
log.Println("Connect client")
|
||||
|
||||
resp.Header().Set("Connection", "close")
|
||||
resp.Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", t.Hash().HexString(), file.Path())))
|
||||
|
||||
http.ServeContent(resp, req, file.Path(), time.Time{}, reader)
|
||||
|
||||
log.Println("Disconnect client")
|
||||
t.CloseReader(reader)
|
||||
return nil
|
||||
}
|
||||
@@ -3,15 +3,15 @@ package torr
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/settings"
|
||||
"server/utils"
|
||||
"server/torr/utils"
|
||||
utils2 "server/utils"
|
||||
|
||||
"server/torr/reader"
|
||||
"server/torr/storage/memcache"
|
||||
"server/torr/storage/torrstor"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
@@ -51,10 +51,9 @@ type Torrent struct {
|
||||
status TorrentStatus
|
||||
|
||||
muTorrent sync.Mutex
|
||||
muReader sync.Mutex
|
||||
|
||||
bt *BTServer
|
||||
cache *memcache.Cache
|
||||
cache *torrstor.Cache
|
||||
|
||||
lastTimeSpeed time.Time
|
||||
DownloadSpeed float64
|
||||
@@ -74,29 +73,25 @@ type Torrent struct {
|
||||
progressTicker *time.Ticker
|
||||
}
|
||||
|
||||
func NewTorrent(magnet metainfo.Magnet, infobytes []byte, bt *BTServer) (*Torrent, error) {
|
||||
switch settings.Get().RetrackersMode {
|
||||
case 1:
|
||||
magnet.Trackers = append(magnet.Trackers, utils.GetDefTrackers()...)
|
||||
case 2:
|
||||
magnet.Trackers = nil
|
||||
case 3:
|
||||
magnet.Trackers = utils.GetDefTrackers()
|
||||
}
|
||||
goTorrent, _, err := bt.client.AddTorrentSpec(&torrent.TorrentSpec{
|
||||
InfoBytes: infobytes,
|
||||
Trackers: [][]string{magnet.Trackers},
|
||||
DisplayName: magnet.DisplayName,
|
||||
InfoHash: magnet.InfoHash,
|
||||
})
|
||||
func NewTorrent(spec *torrent.TorrentSpec, bt *BTServer) (*Torrent, error) {
|
||||
|
||||
switch settings.BTsets.RetrackersMode {
|
||||
case 1:
|
||||
spec.Trackers = append(spec.Trackers, [][]string{utils.GetDefTrackers()}...)
|
||||
case 2:
|
||||
spec.Trackers = nil
|
||||
case 3:
|
||||
spec.Trackers = [][]string{utils.GetDefTrackers()}
|
||||
}
|
||||
|
||||
goTorrent, _, err := bt.client.AddTorrentSpec(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bt.mu.Lock()
|
||||
defer bt.mu.Unlock()
|
||||
if tor, ok := bt.torrents[magnet.InfoHash]; ok {
|
||||
if tor, ok := bt.torrents[spec.InfoHash]; ok {
|
||||
return tor, nil
|
||||
}
|
||||
|
||||
@@ -105,12 +100,12 @@ func NewTorrent(magnet metainfo.Magnet, infobytes []byte, bt *BTServer) (*Torren
|
||||
torr.status = TorrentAdded
|
||||
torr.lastTimeSpeed = time.Now()
|
||||
torr.bt = bt
|
||||
torr.hash = magnet.InfoHash
|
||||
torr.hash = spec.InfoHash
|
||||
torr.closed = goTorrent.Closed()
|
||||
|
||||
go torr.watch()
|
||||
|
||||
bt.torrents[magnet.InfoHash] = torr
|
||||
bt.torrents[spec.InfoHash] = torr
|
||||
return torr, nil
|
||||
}
|
||||
|
||||
@@ -119,6 +114,7 @@ func (t *Torrent) WaitInfo() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Close torrent if not info while 10 minutes
|
||||
tm := time.NewTimer(time.Minute * 10)
|
||||
|
||||
select {
|
||||
@@ -185,17 +181,22 @@ func (t *Torrent) progressEvent() {
|
||||
t.UploadSpeed = 0
|
||||
}
|
||||
t.muTorrent.Unlock()
|
||||
|
||||
t.lastTimeSpeed = time.Now()
|
||||
if t.BytesReadUsefulData > settings.Get().PreloadBufferSize {
|
||||
adj := int64((int(t.cache.GetState().PiecesLength) * t.Torrent.Stats().ActivePeers) / (1 + t.cache.ReadersLen()))
|
||||
t.updateRA()
|
||||
}
|
||||
|
||||
func (t *Torrent) updateRA() {
|
||||
if t.BytesReadUsefulData > settings.BTsets.PreloadBufferSize {
|
||||
pieceLen := t.Torrent.Info().PieceLength
|
||||
adj := pieceLen * int64(t.Torrent.Stats().ActivePeers) / int64(1+t.cache.ReadersLen())
|
||||
switch {
|
||||
case adj < t.cache.GetState().PiecesLength:
|
||||
adj = t.cache.GetState().PiecesLength
|
||||
case adj > t.cache.GetState().PiecesLength*4:
|
||||
adj = t.cache.GetState().PiecesLength * 4
|
||||
case adj < pieceLen:
|
||||
adj = pieceLen
|
||||
case adj > pieceLen*4:
|
||||
adj = pieceLen * 4
|
||||
}
|
||||
t.cache.AdjustRA(adj)
|
||||
//log.Println("Status:", t.Name(), "S:", fmt.Sprintf("%8s", utils.Format(t.DownloadSpeed)), "P:", fmt.Sprintf("%2d", t.Torrent.Stats().ActivePeers), "/", fmt.Sprintf("%2d", t.Torrent.Stats().TotalPeers), "R:", t.cache.ReadersLen(), "RA:", utils.Format(float64(adj)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,31 +228,20 @@ func (t *Torrent) Length() int64 {
|
||||
}
|
||||
|
||||
func (t *Torrent) NewReader(file *torrent.File, readahead int64) *reader.Reader {
|
||||
t.muReader.Lock()
|
||||
|
||||
if t.status == TorrentClosed {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer t.muReader.Unlock()
|
||||
reader := reader.NewReader(file)
|
||||
if readahead <= 0 {
|
||||
readahead = t.cache.GetState().PiecesLength
|
||||
}
|
||||
reader.SetReadahead(readahead)
|
||||
t.cache.AddReader(reader)
|
||||
reader := reader.NewReader(t, file, readahead)
|
||||
return reader
|
||||
}
|
||||
|
||||
func (t *Torrent) CloseReader(reader *reader.Reader) {
|
||||
t.muReader.Lock()
|
||||
reader.Close()
|
||||
t.cache.RemReader(reader)
|
||||
t.expiredTime = time.Now().Add(time.Second * time.Duration(settings.Get().TorrentDisconnectTimeout))
|
||||
t.muReader.Unlock()
|
||||
t.expiredTime = time.Now().Add(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout))
|
||||
}
|
||||
|
||||
func (t *Torrent) GetCache() *memcache.Cache {
|
||||
func (t *Torrent) GetCache() *torrstor.Cache {
|
||||
return t.cache
|
||||
}
|
||||
|
||||
@@ -262,6 +252,8 @@ func (t *Torrent) Preload(file *torrent.File, size int64) {
|
||||
|
||||
if t.status == TorrentGettingInfo {
|
||||
t.WaitInfo()
|
||||
// wait change status
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
t.muTorrent.Lock()
|
||||
@@ -271,7 +263,7 @@ func (t *Torrent) Preload(file *torrent.File, size int64) {
|
||||
}
|
||||
|
||||
if size == 0 {
|
||||
size = settings.Get().PreloadBufferSize
|
||||
size = settings.BTsets.PreloadBufferSize
|
||||
}
|
||||
if size == 0 {
|
||||
t.muTorrent.Unlock()
|
||||
@@ -325,7 +317,7 @@ func (t *Torrent) Preload(file *torrent.File, size int64) {
|
||||
for t.status == TorrentPreload {
|
||||
t.expiredTime = time.Now().Add(time.Minute * 5)
|
||||
t.PreloadedBytes = t.Torrent.BytesCompleted()
|
||||
log.Println("Preload:", file.Torrent().InfoHash().HexString(), bytes.Format(t.PreloadedBytes), "/", bytes.Format(t.PreloadSize), "Speed:", utils.Format(t.DownloadSpeed), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
||||
log.Println("Preload:", file.Torrent().InfoHash().HexString(), bytes.Format(t.PreloadedBytes), "/", bytes.Format(t.PreloadSize), "Speed:", utils2.Format(t.DownloadSpeed), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
||||
if t.PreloadedBytes >= t.PreloadSize {
|
||||
return
|
||||
}
|
||||
@@ -357,66 +349,9 @@ func (t *Torrent) Close() {
|
||||
t.bt.mu.Lock()
|
||||
defer t.bt.mu.Unlock()
|
||||
|
||||
t.muReader.Lock()
|
||||
defer t.muReader.Unlock()
|
||||
|
||||
if _, ok := t.bt.torrents[t.hash]; ok {
|
||||
delete(t.bt.torrents, t.hash)
|
||||
}
|
||||
|
||||
t.drop()
|
||||
}
|
||||
|
||||
func (t *Torrent) Stats() TorrentStats {
|
||||
t.muTorrent.Lock()
|
||||
defer t.muTorrent.Unlock()
|
||||
|
||||
st := TorrentStats{}
|
||||
|
||||
st.Name = t.Name()
|
||||
st.Hash = t.hash.HexString()
|
||||
st.TorrentStatus = t.status
|
||||
st.TorrentStatusString = t.status.String()
|
||||
|
||||
if t.Torrent != nil {
|
||||
st.LoadedSize = t.Torrent.BytesCompleted()
|
||||
st.TorrentSize = t.Length()
|
||||
st.PreloadedBytes = t.PreloadedBytes
|
||||
st.PreloadSize = t.PreloadSize
|
||||
st.DownloadSpeed = t.DownloadSpeed
|
||||
st.UploadSpeed = t.UploadSpeed
|
||||
|
||||
tst := t.Torrent.Stats()
|
||||
st.BytesWritten = tst.BytesWritten.Int64()
|
||||
st.BytesWrittenData = tst.BytesWrittenData.Int64()
|
||||
st.BytesRead = tst.BytesRead.Int64()
|
||||
st.BytesReadData = tst.BytesReadData.Int64()
|
||||
st.BytesReadUsefulData = tst.BytesReadUsefulData.Int64()
|
||||
st.ChunksWritten = tst.ChunksWritten.Int64()
|
||||
st.ChunksRead = tst.ChunksRead.Int64()
|
||||
st.ChunksReadUseful = tst.ChunksReadUseful.Int64()
|
||||
st.ChunksReadWasted = tst.ChunksReadWasted.Int64()
|
||||
st.PiecesDirtiedGood = tst.PiecesDirtiedGood.Int64()
|
||||
st.PiecesDirtiedBad = tst.PiecesDirtiedBad.Int64()
|
||||
st.TotalPeers = tst.TotalPeers
|
||||
st.PendingPeers = tst.PendingPeers
|
||||
st.ActivePeers = tst.ActivePeers
|
||||
st.ConnectedSeeders = tst.ConnectedSeeders
|
||||
st.HalfOpenPeers = tst.HalfOpenPeers
|
||||
|
||||
files := t.Files()
|
||||
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].Path() < files[j].Path()
|
||||
})
|
||||
|
||||
for i, f := range files {
|
||||
st.FileStats = append(st.FileStats, TorrentFileStat{
|
||||
Id: i,
|
||||
Path: f.Path(),
|
||||
Length: f.Length(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return st
|
||||
}
|
||||
35
src/server/torr/utils/blockedIP.go
Normal file
35
src/server/torr/utils/blockedIP.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"server/settings"
|
||||
|
||||
"github.com/anacrolix/torrent/iplist"
|
||||
)
|
||||
|
||||
func ReadBlockedIP() (ranger iplist.Ranger, err error) {
|
||||
buf, err := ioutil.ReadFile(filepath.Join(settings.Path, "blocklist"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(buf)))
|
||||
var ranges []iplist.Range
|
||||
for scanner.Scan() {
|
||||
r, ok, err := iplist.ParseBlocklistP2PLine(scanner.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
ranges = append(ranges, r)
|
||||
}
|
||||
}
|
||||
err = scanner.Err()
|
||||
if len(ranges) > 0 {
|
||||
ranger = iplist.New(ranges)
|
||||
}
|
||||
return
|
||||
}
|
||||
15
src/server/torr/utils/freemem.go
Normal file
15
src/server/torr/utils/freemem.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
func FreeOSMem() {
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
|
||||
func FreeOSMemGC() {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
103
src/server/torr/utils/torrent.go
Normal file
103
src/server/torr/utils/torrent.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
var defTrackers = []string{
|
||||
"http://retracker.local",
|
||||
|
||||
"http://bt4.t-ru.org/ann?magnet",
|
||||
"http://retracker.mgts.by:80/announce",
|
||||
"http://tracker.city9x.com:2710/announce",
|
||||
"http://tracker.electro-torrent.pl:80/announce",
|
||||
"http://tracker.internetwarriors.net:1337/announce",
|
||||
"http://tracker2.itzmx.com:6961/announce",
|
||||
"udp4://46.148.18.250:2710",
|
||||
"udp://opentor.org:2710",
|
||||
"udp://public.popcorn-tracker.org:6969/announce",
|
||||
"udp://tracker.opentrackr.org:1337/announce",
|
||||
|
||||
"http://bt.svao-ix.ru/announce",
|
||||
|
||||
"udp://explodie.org:6969/announce",
|
||||
|
||||
//https://github.com/ngosang/trackerslist/blob/master/trackers_best_ip.txt 18.12.2019
|
||||
"udp4://62.138.0.158:6969/announce",
|
||||
"udp4://188.241.58.209:6969/announce",
|
||||
"udp4://93.158.213.92:1337/announce",
|
||||
"udp4://62.210.97.59:1337/announce",
|
||||
"udp4://151.80.120.113:2710/announce",
|
||||
"udp4://151.80.120.115:2710/announce",
|
||||
"udp4://165.231.0.116:80/announce",
|
||||
"udp4://208.83.20.20:6969/announce",
|
||||
"udp4://5.206.54.49:6969/announce",
|
||||
"udp4://35.156.19.129:6969/announce",
|
||||
"udp4://37.235.174.46:2710/announce",
|
||||
"udp4://185.181.60.67:80/announce",
|
||||
"udp4://54.37.235.149:6969/announce",
|
||||
"udp4://89.234.156.205:451/announce",
|
||||
"udp4://159.100.245.181:6969/announce",
|
||||
"udp4://142.44.243.4:1337/announce",
|
||||
"udp4://51.15.40.114:80/announce",
|
||||
"udp4://176.113.71.19:6961/announce",
|
||||
"udp4://212.47.227.58:6969/announce",
|
||||
}
|
||||
|
||||
var loadedTrackers []string
|
||||
|
||||
func GetDefTrackers() []string {
|
||||
loadNewTracker()
|
||||
if len(loadedTrackers) == 0 {
|
||||
return defTrackers
|
||||
}
|
||||
return loadedTrackers
|
||||
}
|
||||
|
||||
func loadNewTracker() {
|
||||
if len(loadedTrackers) > 0 {
|
||||
return
|
||||
}
|
||||
resp, err := http.Get("https://newtrackon.com/api/stable")
|
||||
if err == nil {
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
if err == nil {
|
||||
arr := strings.Split(string(buf), "\n")
|
||||
var ret []string
|
||||
for _, s := range arr {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) > 0 {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
loadedTrackers = ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PeerIDRandom(peer string) string {
|
||||
randomBytes := make([]byte, 32)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return peer + base32.StdEncoding.EncodeToString(randomBytes)[:20-len(peer)]
|
||||
}
|
||||
|
||||
func Limit(i int) *rate.Limiter {
|
||||
l := rate.NewLimiter(rate.Inf, 0)
|
||||
if i > 0 {
|
||||
b := i
|
||||
if b < 16*1024 {
|
||||
b = 16 * 1024
|
||||
}
|
||||
l = rate.NewLimiter(rate.Limit(i), b)
|
||||
}
|
||||
return l
|
||||
}
|
||||
Reference in New Issue
Block a user