From a1e17b1cf305628772c84433adaf7e9a98eb420c Mon Sep 17 00:00:00 2001 From: YouROK <8yourok8@mail.ru> Date: Fri, 6 Nov 2020 15:40:58 +0300 Subject: [PATCH] init 1.2.x --- .gitignore | 2 + build-all.sh | 17 +- src/main/test.go | 143 ---- src/server/Server.go | 33 - src/server/log/log.go | 9 + src/server/server.go | 26 + src/server/settings/DB.go | 54 -- src/server/settings/Info.go | 66 -- src/server/settings/Settings.go | 125 --- src/server/settings/Torrent.go | 269 ------- src/server/settings/UsableFiles.go | 88 --- src/server/settings/Viewed.go | 103 --- src/server/settings/db.go | 179 +++++ src/server/settings/settings.go | 16 + src/server/settings/torrbt.go | 77 ++ src/server/torr/BTServer.go | 185 ----- src/server/torr/Play.go | 51 -- src/server/torr/State.go | 57 -- src/server/torr/btserver.go | 106 +++ .../torr/reader/{Reader.go => reader.go} | 10 +- src/server/torr/state.go | 130 ++++ src/server/torr/storage/filecache/Cache.go | 1 - src/server/torr/storage/filecache/Storage.go | 69 -- src/server/torr/storage/state/state.go | 18 - .../torr/storage/{Storage.go => storage.go} | 3 - .../Buffer.go => torrstor/buffer.go} | 3 +- .../{memcache/Cache.go => torrstor/cache.go} | 31 +- .../{memcache/Piece.go => torrstor/piece.go} | 19 +- .../Storage.go => torrstor/storage.go} | 13 +- src/server/torr/stream.go | 31 + src/server/torr/{Torrent.go => torrent.go} | 141 +--- .../BlockedIP.go => torr/utils/blockedIP.go} | 0 src/server/torr/utils/freemem.go | 15 + .../Torrent.go => torr/utils/torrent.go} | 29 - src/server/utils/{Prallel.go => prallel.go} | 0 src/server/utils/{Utils.go => strings.go} | 21 - src/server/version/Version.go | 4 - src/server/version/version.go | 4 + src/server/web/About.go | 15 - src/server/web/Info.go | 115 --- src/server/web/Server.go | 159 ---- src/server/web/Settings.go | 52 -- src/server/web/Torrent.go | 720 ------------------ src/server/web/TorrentState.go | 67 -- src/server/web/helpers/Buffer.go | 42 - src/server/web/helpers/M3u.go | 53 -- src/server/web/helpers/Magnet.go | 101 --- src/server/web/helpers/Mime.go | 89 --- src/server/web/helpers/Torrent.go | 70 -- src/server/web/mods/Mods.go | 22 - src/server/web/templates/AboutPage.go | 122 --- src/server/web/templates/ApiJS.go | 133 ---- src/server/web/templates/CachePage.go | 173 ----- src/server/web/templates/FavIcon.go | 3 - src/server/web/templates/MainPage.go | 300 -------- src/server/web/templates/SettingsPage.go | 244 ------ src/server/web/templates/Template.go | 45 -- 57 files changed, 670 insertions(+), 4003 deletions(-) delete mode 100644 src/main/test.go delete mode 100644 src/server/Server.go create mode 100644 src/server/log/log.go create mode 100644 src/server/server.go delete mode 100644 src/server/settings/DB.go delete mode 100644 src/server/settings/Info.go delete mode 100644 src/server/settings/Settings.go delete mode 100644 src/server/settings/Torrent.go delete mode 100644 src/server/settings/UsableFiles.go delete mode 100644 src/server/settings/Viewed.go create mode 100644 src/server/settings/db.go create mode 100644 src/server/settings/settings.go create mode 100644 src/server/settings/torrbt.go delete mode 100644 src/server/torr/BTServer.go delete mode 100644 src/server/torr/Play.go delete mode 100644 src/server/torr/State.go create mode 100644 src/server/torr/btserver.go rename src/server/torr/reader/{Reader.go => reader.go} (79%) create mode 100644 src/server/torr/state.go delete mode 100644 src/server/torr/storage/filecache/Cache.go delete mode 100644 src/server/torr/storage/filecache/Storage.go delete mode 100644 src/server/torr/storage/state/state.go rename src/server/torr/storage/{Storage.go => storage.go} (70%) rename src/server/torr/storage/{memcache/Buffer.go => torrstor/buffer.go} (94%) rename src/server/torr/storage/{memcache/Cache.go => torrstor/cache.go} (85%) rename src/server/torr/storage/{memcache/Piece.go => torrstor/piece.go} (88%) rename src/server/torr/storage/{memcache/Storage.go => torrstor/storage.go} (83%) create mode 100644 src/server/torr/stream.go rename src/server/torr/{Torrent.go => torrent.go} (63%) rename src/server/{utils/BlockedIP.go => torr/utils/blockedIP.go} (100%) create mode 100644 src/server/torr/utils/freemem.go rename src/server/{utils/Torrent.go => torr/utils/torrent.go} (78%) rename src/server/utils/{Prallel.go => prallel.go} (100%) rename src/server/utils/{Utils.go => strings.go} (76%) delete mode 100644 src/server/version/Version.go create mode 100644 src/server/version/version.go delete mode 100644 src/server/web/About.go delete mode 100644 src/server/web/Info.go delete mode 100644 src/server/web/Server.go delete mode 100644 src/server/web/Settings.go delete mode 100644 src/server/web/Torrent.go delete mode 100644 src/server/web/TorrentState.go delete mode 100644 src/server/web/helpers/Buffer.go delete mode 100644 src/server/web/helpers/M3u.go delete mode 100644 src/server/web/helpers/Magnet.go delete mode 100644 src/server/web/helpers/Mime.go delete mode 100644 src/server/web/helpers/Torrent.go delete mode 100644 src/server/web/mods/Mods.go delete mode 100644 src/server/web/templates/AboutPage.go delete mode 100644 src/server/web/templates/ApiJS.go delete mode 100644 src/server/web/templates/CachePage.go delete mode 100644 src/server/web/templates/FavIcon.go delete mode 100644 src/server/web/templates/MainPage.go delete mode 100644 src/server/web/templates/SettingsPage.go delete mode 100644 src/server/web/templates/Template.go diff --git a/.gitignore b/.gitignore index 01e8676..81458b3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ pkg/ bin/ dist/ toolchains/ +/src/crawshaw.io/ +/src/go.etcd.io/ diff --git a/build-all.sh b/build-all.sh index 1557437..585af0c 100755 --- a/build-all.sh +++ b/build-all.sh @@ -23,7 +23,22 @@ PLATFORMS_ARM="linux" type setopt >/dev/null 2>&1 export GOPATH="${PWD}" -GOBIN="/usr/local/go_111/bin/go" +GOBIN="/usr/local/go/bin/go" + +[ -d src/github.com/alexflint/go-arg ] && go get -v github.com/alexflint/go-arg +[ -d src/github.com/anacrolix/dht ] && go get -v github.com/anacrolix/dht +[ -d src/github.com/anacrolix/missinggo/httptoo ] && go get -v github.com/anacrolix/missinggo/httptoo +[ -d src/github.com/anacrolix/torrent ] && go get -v github.com/anacrolix/torrent +[ -d src/github.com/anacrolix/torrent/iplist ] && go get -v github.com/anacrolix/torrent/iplist +[ -d src/github.com/anacrolix/torrent/metainfo ] && go get -v github.com/anacrolix/torrent/metainfo +[ -d src/github.com/anacrolix/utp ] && go get -v github.com/anacrolix/utp +[ -d src/github.com/labstack/echo ] && go get -v github.com/labstack/echo +[ -d src/github.com/labstack/echo/middleware ] && go get -v github.com/labstack/echo/middleware +[ -d src/github.com/labstack/gommon/bytes ] && go get -v github.com/labstack/gommon/bytes +[ -d src/github.com/pion/webrtc/v2 ] && go get -v github.com/pion/webrtc/v2 +[ -d src/go.etcd.io/bbolt ] && go get -v go.etcd.io/bbolt + +#ln -s . src/github.com/pion/webrtc/v2 $GOBIN version diff --git a/src/main/test.go b/src/main/test.go deleted file mode 100644 index ba18244..0000000 --- a/src/main/test.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "sync" - "time" - - "server/utils" - "server/version" - - "github.com/anacrolix/torrent" -) - -/* -{ - "Name": "TorrServer", - "Version": "1.1.71", - "BuildDate": "17.05.2019", - "Links": { - "android-386": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-android-386", - "android-amd64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-android-amd64", - "android-arm64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-android-arm64", - "android-arm7": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-android-arm7", - "darwin-amd64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-darwin-amd64", - "linux-386": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-386", - "linux-amd64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-amd64", - "linux-arm5": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-arm5", - "linux-arm6": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-arm6", - "linux-arm64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-arm64", - "linux-arm7": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-arm7", - "linux-mips": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-mips", - "linux-mips64": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-mips64", - "linux-mips64le": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-mips64le", - "linux-mipsle": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-linux-mipsle", - "windows-386.exe": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-windows-386.exe", - "windows-amd64.exe": "https://github.com/YouROK/TorrServer/releases/download/1.1.71/TorrServer-windows-amd64.exe" - } -} -*/ - -type release struct { - Version string - Links map[string]string -} - -func mkReleasesJS() { - var releases []release - for i := 65; i <= version.VerInt; i++ { - links := map[string]string{ - "android-386": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-android-386", i), - "android-amd64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-android-amd64", i), - "android-arm64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-android-arm64", i), - "android-arm7": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-android-arm7", i), - "darwin-amd64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-darwin-amd64", i), - "linux-386": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-386", i), - "linux-amd64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-amd64", i), - "linux-arm5": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-arm5", i), - "linux-arm6": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-arm6", i), - "linux-arm64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-arm64", i), - "linux-arm7": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-arm7", i), - "linux-mips": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-mips", i), - "linux-mips64": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-mips64", i), - "linux-mips64le": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-mips64le", i), - "linux-mipsle": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-linux-mipsle", i), - "windows-386.exe": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-windows-386.exe", i), - "windows-amd64.exe": fmt.Sprintf("https://github.com/YouROK/TorrServer/releases/download/1.1.%d/TorrServer-windows-amd64.exe", i), - } - rel := release{ - Version: fmt.Sprintf("1.1.%d", i), - Links: links, - } - releases = append(releases, rel) - } - buf, _ := json.MarshalIndent(releases, "", " ") - if len(buf) > 0 { - ioutil.WriteFile("/home/yourok/surge/torrserve/releases.json", buf, 0666) - } -} - -func test() { - config := torrent.NewDefaultClientConfig() - - config.EstablishedConnsPerTorrent = 20 - config.HalfOpenConnsPerTorrent = 65 - config.DisableIPv6 = true - config.NoDHT = true - - client, err := torrent.NewClient(config) - if err != nil { - log.Fatal(err) - } - - //Ubuntu - t, err := client.AddMagnet("magnet:?xt=urn:btih:e4be9e4db876e3e3179778b03e906297be5c8dbe&dn=ubuntu-18.04-desktop-amd64.iso&tr=http%3a%2f%2ftorrent.ubuntu.com%3a6969%2fannounce&tr=http%3a%2f%2fipv6.torrent.ubuntu.com%3a6969%2fannounce") - if err != nil { - log.Fatal(err) - } - <-t.GotInfo() - file := t.Files()[0] - - reader := file.NewReader() - var wa sync.WaitGroup - wa.Add(1) - - go func() { - buf := make([]byte, t.Info().PieceLength) - for { - _, err := reader.Read(buf) - if err != nil { - break - } - } - wa.Done() - }() - - go func() { - cl := t.Closed() - lastTimeSpeed := time.Now() - DownloadSpeed := 0.0 - BytesReadUsefulData := int64(0) - for { - select { - case <-cl: - return - default: - client.WriteStatus(os.Stdout) - st := t.Stats() - deltaDlBytes := st.BytesReadUsefulData.Int64() - BytesReadUsefulData - deltaTime := time.Since(lastTimeSpeed).Seconds() - DownloadSpeed = float64(deltaDlBytes) / deltaTime - BytesReadUsefulData = st.BytesReadUsefulData.Int64() - lastTimeSpeed = time.Now() - fmt.Println("DL speed:", utils.Format(DownloadSpeed)) - } - time.Sleep(time.Second) - } - }() - wa.Wait() -} diff --git a/src/server/Server.go b/src/server/Server.go deleted file mode 100644 index bad60a0..0000000 --- a/src/server/Server.go +++ /dev/null @@ -1,33 +0,0 @@ -package server - -import ( - "fmt" - - "server/settings" - "server/web" -) - -func Start(settingsPath, port string) { - settings.Path = settingsPath - err := settings.ReadSettings() - if err != nil { - fmt.Println("Error read settings:", err) - } - if port == "" { - port = "8090" - } - server.Start(port) -} - -func WaitServer() string { - err := server.Wait() - if err != nil { - return err.Error() - } - return "" -} - -func Stop() { - go server.Stop() - settings.CloseDB() -} diff --git a/src/server/log/log.go b/src/server/log/log.go new file mode 100644 index 0000000..348bda1 --- /dev/null +++ b/src/server/log/log.go @@ -0,0 +1,9 @@ +package log + +import ( + "log" +) + +func TLogln(v ...interface{}) { + log.Println(v...) +} diff --git a/src/server/server.go b/src/server/server.go new file mode 100644 index 0000000..8573c44 --- /dev/null +++ b/src/server/server.go @@ -0,0 +1,26 @@ +package server + +import ( + "server/settings" +) + +func Start(settingsPath, port string, roSets bool) { + settings.InitSets(settingsPath, roSets) + if port == "" { + port = "8090" + } + //server.Start(port) +} + +func WaitServer() string { + //err := server.Wait() + // if err != nil { + // return err.Error() + // } + return "" +} + +func Stop() { + // go server.Stop() + settings.CloseDB() +} diff --git a/src/server/settings/DB.go b/src/server/settings/DB.go deleted file mode 100644 index 329aff5..0000000 --- a/src/server/settings/DB.go +++ /dev/null @@ -1,54 +0,0 @@ -package settings - -import ( - "fmt" - "path/filepath" - - bolt "go.etcd.io/bbolt" -) - -var ( - db *bolt.DB - dbViewedName = []byte("Viewed") - dbInfosName = []byte("Infos") - dbTorrentsName = []byte("Torrents") - dbSettingsName = []byte("Settings") - Path string -) - -func openDB() error { - if db != nil { - return nil - } - - var err error - var ro = Get().ReadOnlyMode - db, err = bolt.Open(filepath.Join(Path, "torrserver.db"), 0666, &bolt.Options{ReadOnly: ro}) - if err != nil { - fmt.Println(err) - return err - } - - err = db.Update(func(tx *bolt.Tx) error { - _, err = tx.CreateBucketIfNotExists(dbSettingsName) - if err != nil { - return fmt.Errorf("could not create Settings bucket: %v", err) - } - _, err = tx.CreateBucketIfNotExists(dbTorrentsName) - if err != nil { - return fmt.Errorf("could not create Torrents bucket: %v", err) - } - return nil - }) - if err != nil { - CloseDB() - } - return err -} - -func CloseDB() { - if db != nil { - db.Close() - db = nil - } -} diff --git a/src/server/settings/Info.go b/src/server/settings/Info.go deleted file mode 100644 index afd9280..0000000 --- a/src/server/settings/Info.go +++ /dev/null @@ -1,66 +0,0 @@ -package settings - -import ( - "fmt" - "strings" - - bolt "go.etcd.io/bbolt" -) - -func AddInfo(hash, info string) error { - err := openDB() - if err != nil { - return err - } - - infoe := GetInfo(hash) - if infoe != "{}" { - return nil // already filled - } - - hash = strings.ToUpper(hash) - return db.Update(func(tx *bolt.Tx) error { - dbt, err := tx.CreateBucketIfNotExists([]byte(dbInfosName)) - if err != nil { - return err - } - - dbi, err := dbt.CreateBucketIfNotExists([]byte(hash)) - if err != nil { - return err - } - - err = dbi.Put([]byte("Info"), []byte(info)) - if err != nil { - return fmt.Errorf("error save torrent info %v", err) - } - return nil - }) -} - -func GetInfo(hash string) string { - err := openDB() - if err != nil { - return "{}" - } - - hash = strings.ToUpper(hash) - ret := "{}" - err = db.View(func(tx *bolt.Tx) error { - hdb := tx.Bucket(dbInfosName) - if hdb == nil { - return fmt.Errorf("could not find torrent info") - } - hdb = hdb.Bucket([]byte(hash)) - if hdb != nil { - info := hdb.Get([]byte("Info")) - if info == nil { - return fmt.Errorf("error get torrent info") - } - ret = string(info) - return nil - } - return nil - }) - return ret -} diff --git a/src/server/settings/Settings.go b/src/server/settings/Settings.go deleted file mode 100644 index be52e33..0000000 --- a/src/server/settings/Settings.go +++ /dev/null @@ -1,125 +0,0 @@ -package settings - -import ( - "encoding/json" - "fmt" - "time" - - bolt "go.etcd.io/bbolt" -) - -var ( - sets *Settings - StartTime time.Time -) - -func init() { - sets = new(Settings) - sets.CacheSize = 200 * 1024 * 1024 - sets.EnableDebug = false - sets.PreloadBufferSize = 20 * 1024 * 1024 - sets.ConnectionsLimit = 20 - sets.DhtConnectionLimit = 500 - sets.RetrackersMode = 1 - sets.TorrentDisconnectTimeout = 30 - StartTime = time.Now() -} - -type Settings struct { - CacheSize int64 // in byte, def 200 mb - PreloadBufferSize int64 // in byte, buffer for preload - - RetrackersMode int //0 - don`t add, 1 - add retrackers, 2 - remove retrackers - - //BT Config - EnableIPv6 bool - EnableDebug bool - DisableTCP bool - DisableUTP bool - DisableUPNP bool - DisableDHT bool - DisableUpload bool - ReadOnlyMode bool - Encryption int // 0 - Enable, 1 - disable, 2 - force - DownloadRateLimit int // in kb, 0 - inf - UploadRateLimit int // in kb, 0 - inf - ConnectionsLimit int - DhtConnectionLimit int // 0 - inf - PeersListenPort int - - TorrentDisconnectTimeout int // in seconds -} - -func Get() *Settings { - return sets -} - -func (s *Settings) String() string { - buf, _ := json.MarshalIndent(sets, "", " ") - return string(buf) -} - -func ReadSettings() error { - err := openDB() - if err != nil { - return err - } - buf := make([]byte, 0) - err = db.View(func(tx *bolt.Tx) error { - sdb := tx.Bucket(dbSettingsName) - if sdb == nil { - return fmt.Errorf("error load settings") - } - - buf = sdb.Get([]byte("json")) - if buf == nil { - return fmt.Errorf("error load settings") - } - return nil - }) - err = json.Unmarshal(buf, sets) - if err != nil { - return err - } - if sets.ConnectionsLimit <= 0 { - sets.ConnectionsLimit = 20 - } - if sets.DhtConnectionLimit < 0 { - sets.DhtConnectionLimit = 1000 - } - if sets.CacheSize < 0 { - sets.CacheSize = 200 * 1024 * 1024 - } - - if sets.TorrentDisconnectTimeout < 1 { - sets.TorrentDisconnectTimeout = 1 - } - return nil -} - -func SaveSettings() error { - err := openDB() - if err != nil { - return err - } - - buf, err := json.Marshal(sets) - if err != nil { - return err - } - - return db.Update(func(tx *bolt.Tx) error { - setsDB, err := tx.CreateBucketIfNotExists(dbSettingsName) - if err != nil { - return err - } - return setsDB.Put([]byte("json"), []byte(buf)) - }) -} - -func SetRDB() { - SaveSettings() - fmt.Println("Enable Read-only DB mode") - CloseDB() - sets.ReadOnlyMode = true -} diff --git a/src/server/settings/Torrent.go b/src/server/settings/Torrent.go deleted file mode 100644 index 99ff154..0000000 --- a/src/server/settings/Torrent.go +++ /dev/null @@ -1,269 +0,0 @@ -package settings - -import ( - "encoding/binary" - "fmt" - - bolt "go.etcd.io/bbolt" -) - -type Torrent struct { - Name string - Magnet string - InfoBytes []byte - Hash string - Size int64 - Timestamp int64 - - Files []File -} - -type File struct { - Name string - Id int - Size int64 -} - -func SaveTorrentDB(torrent *Torrent) error { - err := openDB() - if err != nil { - return err - } - - return db.Update(func(tx *bolt.Tx) error { - dbt, err := tx.CreateBucketIfNotExists(dbTorrentsName) - if err != nil { - return fmt.Errorf("could not create Torrents bucket: %v", err) - } - fmt.Println("Save torrent:", torrent.Name) - hdb, err := dbt.CreateBucketIfNotExists([]byte(torrent.Hash)) - if err != nil { - return fmt.Errorf("could not create Torrent bucket: %v", err) - } - - err = hdb.Put([]byte("Name"), []byte(torrent.Name)) - if err != nil { - return fmt.Errorf("error save torrent: %v", err) - } - err = hdb.Put([]byte("Link"), []byte(torrent.Magnet)) - if err != nil { - return fmt.Errorf("error save torrent: %v", err) - } - err = hdb.Put([]byte("InfoBytes"), torrent.InfoBytes) - if err != nil { - return fmt.Errorf("error save torrent: %v", err) - } - err = hdb.Put([]byte("Size"), i2b(torrent.Size)) - if err != nil { - return fmt.Errorf("error save torrent: %v", err) - } - err = hdb.Put([]byte("Timestamp"), i2b(torrent.Timestamp)) - if err != nil { - return fmt.Errorf("error save torrent: %v", err) - } - - fdb, err := hdb.CreateBucketIfNotExists([]byte("Files")) - if err != nil { - return fmt.Errorf("error save torrent files: %v", err) - } - - for _, f := range torrent.Files { - ffdb, err := fdb.CreateBucketIfNotExists([]byte(f.Name)) - if err != nil { - return fmt.Errorf("error save torrent files: %v", err) - } - - err = ffdb.Put([]byte("Id"), i2b(int64(f.Id))) - if err != nil { - return fmt.Errorf("error save torrent files: %v", err) - } - - err = ffdb.Put([]byte("Size"), i2b(f.Size)) - if err != nil { - return fmt.Errorf("error save torrent files: %v", err) - } - } - - return nil - }) -} - -func RemoveTorrentDB(hash string) error { - err := openDB() - if err != nil { - return err - } - - return db.Update(func(tx *bolt.Tx) error { - dbt := tx.Bucket(dbTorrentsName) - if dbt == nil { - return fmt.Errorf("could not find torrent") - } - - return dbt.DeleteBucket([]byte(hash)) - }) -} - -func LoadTorrentDB(hash string) (*Torrent, error) { - err := openDB() - if err != nil { - return nil, err - } - - var torr *Torrent - err = db.View(func(tx *bolt.Tx) error { - hdb := tx.Bucket(dbTorrentsName) - if hdb == nil { - return fmt.Errorf("could not find torrent") - } - hdb = hdb.Bucket([]byte(hash)) - if hdb != nil { - torr = new(Torrent) - torr.Hash = string(hash) - 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("InfoBytes")) - if len(tmp) > 0 { - torr.InfoBytes = tmp - } else { - torr.InfoBytes = nil - } - - 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) - - fdb := hdb.Bucket([]byte("Files")) - if fdb == nil { - return fmt.Errorf("error load torrent files") - } - cf := fdb.Cursor() - for fn, _ := cf.First(); fn != nil; fn, _ = cf.Next() { - file := File{Name: string(fn)} - ffdb := fdb.Bucket(fn) - if ffdb == nil { - return fmt.Errorf("error load torrent files") - } - - tmp := ffdb.Get([]byte("Id")) - if tmp == nil { - return fmt.Errorf("error load torrent file") - } - file.Id = int(b2i(tmp)) - - tmp = ffdb.Get([]byte("Size")) - if tmp == nil { - return fmt.Errorf("error load torrent file") - } - file.Size = b2i(tmp) - - torr.Files = append(torr.Files, file) - } - SortFiles(torr.Files) - } - return nil - }) - return torr, err -} - -func LoadTorrentsDB() ([]*Torrent, error) { - err := openDB() - if err != nil { - return nil, err - } - - torrs := make([]*Torrent, 0) - err = db.View(func(tx *bolt.Tx) error { - tdb := tx.Bucket(dbTorrentsName) - c := tdb.Cursor() - for h, _ := c.First(); h != nil; h, _ = c.Next() { - hdb := tdb.Bucket(h) - if hdb != nil { - torr := new(Torrent) - 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) - - fdb := hdb.Bucket([]byte("Files")) - if fdb == nil { - return fmt.Errorf("error load torrent files") - } - cf := fdb.Cursor() - for fn, _ := cf.First(); fn != nil; fn, _ = cf.Next() { - file := File{Name: string(fn)} - ffdb := fdb.Bucket(fn) - if ffdb == nil { - return fmt.Errorf("error load torrent files") - } - - tmp := ffdb.Get([]byte("Id")) - if tmp == nil { - return fmt.Errorf("error load torrent file") - } - file.Id = int(b2i(tmp)) - - tmp = ffdb.Get([]byte("Size")) - if tmp == nil { - return fmt.Errorf("error load torrent file") - } - file.Size = b2i(tmp) - - torr.Files = append(torr.Files, file) - } - SortFiles(torr.Files) - torrs = append(torrs, torr) - } - } - return nil - }) - return torrs, err -} - -func i2b(v int64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(v)) - return b -} - -func b2i(v []byte) int64 { - return int64(binary.BigEndian.Uint64(v)) -} diff --git a/src/server/settings/UsableFiles.go b/src/server/settings/UsableFiles.go deleted file mode 100644 index 42a1c45..0000000 --- a/src/server/settings/UsableFiles.go +++ /dev/null @@ -1,88 +0,0 @@ -package settings - -import ( - "path/filepath" - "sort" - "strings" -) - -var ( - uFiles = map[string]interface{}{ - ".3g2": nil, - ".3gp": nil, - ".aaf": nil, - ".asf": nil, - ".avchd": nil, - ".avi": nil, - ".drc": nil, - ".flv": nil, - ".m2v": nil, - ".m4p": nil, - ".m4v": nil, - ".mkv": nil, - ".mng": nil, - ".mov": nil, - ".mp2": nil, - ".mp4": nil, - ".mpe": nil, - ".mpeg": nil, - ".mpg": nil, - ".mpv": nil, - ".mxf": nil, - ".nsv": nil, - ".ogg": nil, - ".ogv": nil, - ".ts": nil, - ".m2ts": nil, - ".mts": nil, - ".qt": nil, - ".rm": nil, - ".rmvb": nil, - ".roq": nil, - ".svi": nil, - ".vob": nil, - ".webm": nil, - ".wmv": nil, - ".yuv": nil, - - ".aac": nil, - ".aiff": nil, - ".ape": nil, - ".au": nil, - ".flac": nil, - ".gsm": nil, - ".it": nil, - ".m3u": nil, - ".m4a": nil, - ".mid": nil, - ".mod": nil, - ".mp3": nil, - ".mpa": nil, - ".pls": nil, - ".ra": nil, - ".s3m": nil, - ".sid": nil, - ".wav": nil, - ".wma": nil, - ".xm": nil, - } -) - -func SortFiles(files []File) { - sort.Slice(files, func(i, j int) bool { - if haveUsable(files[i].Name) && !haveUsable(files[j].Name) { - return true - } - if !haveUsable(files[i].Name) && haveUsable(files[j].Name) { - return false - } - - return files[i].Name < files[j].Name - }) -} - -func haveUsable(name string) bool { - ext := strings.ToLower(filepath.Ext(name)) - _, ok := uFiles[ext] - return ok -} diff --git a/src/server/settings/Viewed.go b/src/server/settings/Viewed.go deleted file mode 100644 index d18f305..0000000 --- a/src/server/settings/Viewed.go +++ /dev/null @@ -1,103 +0,0 @@ -package settings - -import ( - "fmt" - - bolt "go.etcd.io/bbolt" -) - -func SetViewed(hash, filename string) error { - err := openDB() - if err != nil { - return err - } - - return db.Update(func(tx *bolt.Tx) error { - dbt, err := tx.CreateBucketIfNotExists(dbViewedName) - if err != nil { - return fmt.Errorf("error save viewed %v", err) - } - hdb, err := dbt.CreateBucketIfNotExists([]byte(hash)) - if err != nil { - return fmt.Errorf("error save viewed %v", err) - } - - err = hdb.Put([]byte(filename), []byte{1}) - if err != nil { - return fmt.Errorf("error save viewed %v", err) - } - return nil - }) -} - -func RemTorrentViewed(hash string) error { - err := openDB() - if err != nil { - return err - } - - return db.Update(func(tx *bolt.Tx) error { - dbt := tx.Bucket(dbViewedName) - if dbt == nil { - return nil - } - err = dbt.DeleteBucket([]byte(hash)) - if err == nil || err == bolt.ErrBucketNotFound { - return nil - } - - return err - }) -} - -func GetViewed(hash, filename string) bool { - err := openDB() - if err != nil { - return false - } - viewed := false - err = db.View(func(tx *bolt.Tx) error { - hdb := tx.Bucket(dbViewedName) - if hdb == nil { - return fmt.Errorf("error get viewed") - } - hdb = hdb.Bucket([]byte(hash)) - if hdb != nil { - vw := hdb.Get([]byte(filename)) - viewed = vw != nil && vw[0] == 1 - } - return nil - }) - return viewed -} - -func GetViewedList() map[string][]string { - err := openDB() - if err != nil { - return nil - } - - var list = make(map[string][]string) - - err = db.View(func(tx *bolt.Tx) error { - rdb := tx.Bucket(dbViewedName) - if rdb == nil { - return fmt.Errorf("could not find torrent") - } - - rdb.ForEach(func(hash, _ []byte) error { - hdb := rdb.Bucket(hash) - fdb := hdb.Bucket([]byte("Files")) - fdb.ForEach(func(fileName, _ []byte) error { - vw := fdb.Get(fileName) - if vw != nil && vw[0] == 1 { - list[string(hash)] = append(list[string(hash)], string(fileName)) - } - return nil - }) - return nil - }) - return nil - }) - return list -} diff --git a/src/server/settings/db.go b/src/server/settings/db.go new file mode 100644 index 0000000..0159905 --- /dev/null +++ b/src/server/settings/db.go @@ -0,0 +1,179 @@ +package settings + +import ( + "path/filepath" + "strings" + + bolt "go.etcd.io/bbolt" + "server/log" +) + +type TDB struct { + Path string + ReadOnly bool + db *bolt.DB +} + +func NewTDB(path string, readOnly bool) *TDB { + db, err := bolt.Open(filepath.Join(path, "config.db"), 0666, nil) + if err != nil { + log.TLogln(err) + return nil + } + + tdb := new(TDB) + tdb.db = db + tdb.Path = path + tdb.ReadOnly = readOnly + return tdb +} + +func (v *TDB) CloseDB() { + if v.db != nil { + v.db.Close() + v.db = nil + } +} + +func (v *TDB) Get(xpath, name string) []byte { + spath := strings.Split(xpath, "/") + if len(spath) == 0 { + return nil + } + var ret []byte + err := v.db.View(func(tx *bolt.Tx) error { + buckt := tx.Bucket([]byte(spath[0])) + if buckt == nil { + return nil + } + + for i, p := range spath { + if i == 0 { + continue + } + buckt = buckt.Bucket([]byte(p)) + if buckt == nil { + return nil + } + } + + ret = buckt.Get([]byte(name)) + return nil + }) + + if err != nil { + log.TLogln("Error get sets", xpath+"/"+name, ", error:", err) + } + + return ret +} + +func (v *TDB) Set(xpath, name string, value []byte) { + if v.ReadOnly { + return + } + + spath := strings.Split(xpath, "/") + if len(spath) == 0 { + return + } + err := v.db.Update(func(tx *bolt.Tx) error { + buckt, err := tx.CreateBucketIfNotExists([]byte(spath[0])) + if err != nil { + return err + } + + for i, p := range spath { + if i == 0 { + continue + } + buckt, err = buckt.CreateBucketIfNotExists([]byte(p)) + if err != nil { + return err + } + } + + return buckt.Put([]byte(name), value) + }) + + if err != nil { + log.TLogln("Error put sets", xpath+"/"+name, ", error:", err) + log.TLogln("value:", value) + } + + return +} + +func (v *TDB) List(xpath string) []string { + spath := strings.Split(xpath, "/") + if len(spath) == 0 { + return nil + } + var ret []string + err := v.db.View(func(tx *bolt.Tx) error { + buckt := tx.Bucket([]byte(spath[0])) + if buckt == nil { + return nil + } + + for i, p := range spath { + if i == 0 { + continue + } + buckt = buckt.Bucket([]byte(p)) + if buckt == nil { + return nil + } + } + + buckt.ForEach(func(_, v []byte) error { + if len(v) > 0 { + ret = append(ret, string(v)) + } + return nil + }) + + return nil + }) + + if err != nil { + log.TLogln("Error list sets", xpath, ", error:", err) + } + + return ret +} + +func (v *TDB) Rem(xpath, name string) { + if v.ReadOnly { + return + } + + spath := strings.Split(xpath, "/") + if len(spath) == 0 { + return + } + err := v.db.Update(func(tx *bolt.Tx) error { + buckt := tx.Bucket([]byte(spath[0])) + if buckt == nil { + return nil + } + + for i, p := range spath { + if i == 0 { + continue + } + buckt = buckt.Bucket([]byte(p)) + if buckt == nil { + return nil + } + } + + return buckt.Delete([]byte(name)) + }) + + if err != nil { + log.TLogln("Error rem sets", xpath+"/"+name, ", error:", err) + } + + return +} diff --git a/src/server/settings/settings.go b/src/server/settings/settings.go new file mode 100644 index 0000000..25ba802 --- /dev/null +++ b/src/server/settings/settings.go @@ -0,0 +1,16 @@ +package settings + +var ( + tdb *TDB + Path string +) + +func InitSets(path string, readOnly bool) { + Path = path + tdb = NewTDB(path, readOnly) + loadBTSets() +} + +func CloseDB() { + tdb.CloseDB() +} diff --git a/src/server/settings/torrbt.go b/src/server/settings/torrbt.go new file mode 100644 index 0000000..040c823 --- /dev/null +++ b/src/server/settings/torrbt.go @@ -0,0 +1,77 @@ +package settings + +import ( + "encoding/json" + + "server/log" +) + +type BTSets struct { + CacheSize int64 // in byte, def 200 mb + PreloadBufferSize int64 // in byte, buffer for preload + + SaveOnDisk bool // save on disk? + ContentPath string // path to save content + + RetrackersMode int // 0 - don`t add, 1 - add retrackers (def), 2 - remove retrackers 3 - replace retrackers + TorrentDisconnectTimeout int // in seconds + EnableDebug bool // print logs + + // BT Config + EnableIPv6 bool + DisableTCP bool + DisableUTP bool + DisableUPNP bool + DisableDHT bool + DisableUpload bool + Encryption int // ???? 0 - Enable, 1 - disable, 2 - force + DownloadRateLimit int // in kb, 0 - inf + UploadRateLimit int // in kb, 0 - inf + ConnectionsLimit int + DhtConnectionLimit int // 0 - inf + PeersListenPort int +} + +func (v *BTSets) String() string { + buf, _ := json.Marshal(v) + return string(buf) +} + +var ( + BTsets = loadBTSets() +) + +func SetBTSets(sets *BTSets) { + if tdb.ReadOnly { + return + } + BTsets = sets + buf, err := json.Marshal(BTsets) + if err != nil { + log.TLogln("Error marshal btsets", err) + return + } + tdb.Set("Settings", "BitTorr", buf) +} + +func loadBTSets() *BTSets { + buf := tdb.Get("Settings", "BitTorr") + if len(buf) > 0 { + err := json.Unmarshal(buf, &BTsets) + if err == nil { + return BTsets + } + log.TLogln("Error unmarshal btsets", err) + } + + sets := new(BTSets) + sets.EnableDebug = false + + sets.CacheSize = 200 * 1024 * 1024 // 200mb + sets.PreloadBufferSize = 20 * 1024 * 1024 + sets.ConnectionsLimit = 20 + sets.DhtConnectionLimit = 500 + sets.RetrackersMode = 1 + sets.TorrentDisconnectTimeout = 30 + return sets +} diff --git a/src/server/torr/BTServer.go b/src/server/torr/BTServer.go deleted file mode 100644 index f19f013..0000000 --- a/src/server/torr/BTServer.go +++ /dev/null @@ -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) -} diff --git a/src/server/torr/Play.go b/src/server/torr/Play.go deleted file mode 100644 index 8d5061a..0000000 --- a/src/server/torr/Play.go +++ /dev/null @@ -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) -} diff --git a/src/server/torr/State.go b/src/server/torr/State.go deleted file mode 100644 index 530644d..0000000 --- a/src/server/torr/State.go +++ /dev/null @@ -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 -} diff --git a/src/server/torr/btserver.go b/src/server/torr/btserver.go new file mode 100644 index 0000000..8912ab8 --- /dev/null +++ b/src/server/torr/btserver.go @@ -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() + } +} diff --git a/src/server/torr/reader/Reader.go b/src/server/torr/reader/reader.go similarity index 79% rename from src/server/torr/reader/Reader.go rename to src/server/torr/reader/reader.go index 3833eef..dfcd325 100644 --- a/src/server/torr/reader/Reader.go +++ b/src/server/torr/reader/reader.go @@ -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 } diff --git a/src/server/torr/state.go b/src/server/torr/state.go new file mode 100644 index 0000000..6dc225e --- /dev/null +++ b/src/server/torr/state.go @@ -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 +} diff --git a/src/server/torr/storage/filecache/Cache.go b/src/server/torr/storage/filecache/Cache.go deleted file mode 100644 index c3381cd..0000000 --- a/src/server/torr/storage/filecache/Cache.go +++ /dev/null @@ -1 +0,0 @@ -package filecache diff --git a/src/server/torr/storage/filecache/Storage.go b/src/server/torr/storage/filecache/Storage.go deleted file mode 100644 index 60f65e0..0000000 --- a/src/server/torr/storage/filecache/Storage.go +++ /dev/null @@ -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 -} diff --git a/src/server/torr/storage/state/state.go b/src/server/torr/storage/state/state.go deleted file mode 100644 index 1ec9680..0000000 --- a/src/server/torr/storage/state/state.go +++ /dev/null @@ -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 -} diff --git a/src/server/torr/storage/Storage.go b/src/server/torr/storage/storage.go similarity index 70% rename from src/server/torr/storage/Storage.go rename to src/server/torr/storage/storage.go index e80cc3a..87dfbd5 100644 --- a/src/server/torr/storage/Storage.go +++ b/src/server/torr/storage/storage.go @@ -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) } diff --git a/src/server/torr/storage/memcache/Buffer.go b/src/server/torr/storage/torrstor/buffer.go similarity index 94% rename from src/server/torr/storage/memcache/Buffer.go rename to src/server/torr/storage/torrstor/buffer.go index b63111d..adf1c55 100644 --- a/src/server/torr/storage/memcache/Buffer.go +++ b/src/server/torr/storage/torrstor/buffer.go @@ -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 } } diff --git a/src/server/torr/storage/memcache/Cache.go b/src/server/torr/storage/torrstor/cache.go similarity index 85% rename from src/server/torr/storage/memcache/Cache.go rename to src/server/torr/storage/torrstor/cache.go index b6c98c7..58cfbfa 100644 --- a/src/server/torr/storage/memcache/Cache.go +++ b/src/server/torr/storage/torrstor/cache.go @@ -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 { diff --git a/src/server/torr/storage/memcache/Piece.go b/src/server/torr/storage/torrstor/piece.go similarity index 88% rename from src/server/torr/storage/memcache/Piece.go rename to src/server/torr/storage/torrstor/piece.go index f21f75b..e829d2f 100644 --- a/src/server/torr/storage/memcache/Piece.go +++ b/src/server/torr/storage/torrstor/piece.go @@ -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 } diff --git a/src/server/torr/storage/memcache/Storage.go b/src/server/torr/storage/torrstor/storage.go similarity index 83% rename from src/server/torr/storage/memcache/Storage.go rename to src/server/torr/storage/torrstor/storage.go index 2a54fff..e44a836 100644 --- a/src/server/torr/storage/memcache/Storage.go +++ b/src/server/torr/storage/torrstor/storage.go @@ -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 diff --git a/src/server/torr/stream.go b/src/server/torr/stream.go new file mode 100644 index 0000000..03de85f --- /dev/null +++ b/src/server/torr/stream.go @@ -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 +} diff --git a/src/server/torr/Torrent.go b/src/server/torr/torrent.go similarity index 63% rename from src/server/torr/Torrent.go rename to src/server/torr/torrent.go index 51efd6a..d19dfc0 100644 --- a/src/server/torr/Torrent.go +++ b/src/server/torr/torrent.go @@ -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 -} diff --git a/src/server/utils/BlockedIP.go b/src/server/torr/utils/blockedIP.go similarity index 100% rename from src/server/utils/BlockedIP.go rename to src/server/torr/utils/blockedIP.go diff --git a/src/server/torr/utils/freemem.go b/src/server/torr/utils/freemem.go new file mode 100644 index 0000000..00b6a1e --- /dev/null +++ b/src/server/torr/utils/freemem.go @@ -0,0 +1,15 @@ +package utils + +import ( + "runtime" + "runtime/debug" +) + +func FreeOSMem() { + debug.FreeOSMemory() +} + +func FreeOSMemGC() { + runtime.GC() + debug.FreeOSMemory() +} diff --git a/src/server/utils/Torrent.go b/src/server/torr/utils/torrent.go similarity index 78% rename from src/server/utils/Torrent.go rename to src/server/torr/utils/torrent.go index e42804f..e7ac494 100644 --- a/src/server/utils/Torrent.go +++ b/src/server/torr/utils/torrent.go @@ -2,16 +2,11 @@ package utils import ( "encoding/base32" - "errors" "io/ioutil" "math/rand" "net/http" "strings" - "time" - "server/settings" - - "github.com/anacrolix/torrent" "golang.org/x/time/rate" ) @@ -95,30 +90,6 @@ func PeerIDRandom(peer string) string { return peer + base32.StdEncoding.EncodeToString(randomBytes)[:20-len(peer)] } -func GotInfo(t *torrent.Torrent, timeout int) error { - gi := t.GotInfo() - select { - case <-gi: - return nil - case <-time.Tick(time.Second * time.Duration(timeout)): - return errors.New("timeout load torrent info") - } -} - -func GetReadahead() int64 { - readahead := settings.Get().CacheSize - (138412032) //132mb - if readahead < 69206016 { //66mb - readahead = int64(float64(settings.Get().CacheSize) * 0.33) - if readahead < 66*1024*1024 { - readahead = int64(settings.Get().CacheSize) - if readahead > 66*1024*1024 { - readahead = 66 * 1024 * 1024 - } - } - } - return readahead -} - func Limit(i int) *rate.Limiter { l := rate.NewLimiter(rate.Inf, 0) if i > 0 { diff --git a/src/server/utils/Prallel.go b/src/server/utils/prallel.go similarity index 100% rename from src/server/utils/Prallel.go rename to src/server/utils/prallel.go diff --git a/src/server/utils/Utils.go b/src/server/utils/strings.go similarity index 76% rename from src/server/utils/Utils.go rename to src/server/utils/strings.go index 86937eb..929ef40 100644 --- a/src/server/utils/Utils.go +++ b/src/server/utils/strings.go @@ -3,8 +3,6 @@ package utils import ( "fmt" "regexp" - "runtime" - "runtime/debug" "strconv" "strings" ) @@ -18,15 +16,6 @@ func CleanFName(file string) string { return ret } -func FreeOSMem() { - debug.FreeOSMemory() -} - -func FreeOSMemGC() { - runtime.GC() - debug.FreeOSMemory() -} - const ( _ = 1.0 << (10 * iota) // ignore first value by assigning to blank identifier KB @@ -68,13 +57,3 @@ func Format(b float64) string { return fmt.Sprintf("%.2f%s", value, multiple) } - -// -//func IsCyrillic(str string) bool { -// for _, r := range str { -// if unicode.Is(unicode.Cyrillic, r) { -// return true -// } -// } -// return false -//} diff --git a/src/server/version/Version.go b/src/server/version/Version.go deleted file mode 100644 index a72a189..0000000 --- a/src/server/version/Version.go +++ /dev/null @@ -1,4 +0,0 @@ -package version - -const Version = "1.1.77" -const VerInt = 77 diff --git a/src/server/version/version.go b/src/server/version/version.go new file mode 100644 index 0000000..9cf13c4 --- /dev/null +++ b/src/server/version/version.go @@ -0,0 +1,4 @@ +package version + +const Version = "1.2.78" +const VerInt = 78 diff --git a/src/server/web/About.go b/src/server/web/About.go deleted file mode 100644 index 222e5d0..0000000 --- a/src/server/web/About.go +++ /dev/null @@ -1,15 +0,0 @@ -package server - -import ( - "net/http" - - "github.com/labstack/echo" -) - -func initAbout(e *echo.Echo) { - e.GET("/about", aboutPage) -} - -func aboutPage(c echo.Context) error { - return c.Render(http.StatusOK, "aboutPage", nil) -} diff --git a/src/server/web/Info.go b/src/server/web/Info.go deleted file mode 100644 index 3db7b1e..0000000 --- a/src/server/web/Info.go +++ /dev/null @@ -1,115 +0,0 @@ -package server - -import ( - "fmt" - "net/http" - "sort" - - "server/utils" - - "github.com/anacrolix/torrent/metainfo" - "github.com/labstack/echo" - "github.com/labstack/gommon/bytes" -) - -func initInfo(e *echo.Echo) { - server.GET("/cache", cachePage) - server.GET("/stat", statePage) - server.GET("/btstat", btStatePage) -} - -func btStatePage(c echo.Context) error { - bts.WriteState(c.Response()) - return c.NoContent(http.StatusOK) -} - -func cachePage(c echo.Context) error { - return c.Render(http.StatusOK, "cachePage", nil) -} - -func statePage(c echo.Context) error { - state := bts.BTState() - - msg := "" - - msg += fmt.Sprintf("Listen port: %d
\n", state.LocalPort) - msg += fmt.Sprintf("Peer ID: %+q
\n", state.PeerID) - msg += fmt.Sprintf("Banned IPs: %d
\n", state.BannedIPs) - - for _, dht := range state.DHTs { - msg += fmt.Sprintf("%s DHT server at %s:
\n", dht.Addr().Network(), dht.Addr().String()) - dhtStats := dht.Stats() - msg += fmt.Sprintf("\t # Nodes: %d (%d good, %d banned)
\n", dhtStats.Nodes, dhtStats.GoodNodes, dhtStats.BadNodes) - msg += fmt.Sprintf("\t Server ID: %x
\n", dht.ID()) - msg += fmt.Sprintf("\t Announces: %d
\n", dhtStats.SuccessfulOutboundAnnouncePeerQueries) - msg += fmt.Sprintf("\t Outstanding transactions: %d
\n", dhtStats.OutstandingTransactions) - } - - sort.Slice(state.Torrents, func(i, j int) bool { - return state.Torrents[i].Hash().HexString() < state.Torrents[j].Hash().HexString() - }) - msg += "Torrents:
\n" - for _, t := range state.Torrents { - st := t.Stats() - msg += fmt.Sprintf("Name: %v
\n", st.Name) - msg += fmt.Sprintf("Hash: %v
\n", st.Hash) - msg += fmt.Sprintf("Status: %v
\n", st.TorrentStatus) - msg += fmt.Sprintf("Loaded Size: %v
\n", bytes.Format(st.LoadedSize)) - msg += fmt.Sprintf("Torrent Size: %v
\n
\n", bytes.Format(st.TorrentSize)) - - msg += fmt.Sprintf("Preloaded Bytes: %v
\n", bytes.Format(st.PreloadedBytes)) - msg += fmt.Sprintf("Preload Size: %v
\n
\n", bytes.Format(st.PreloadSize)) - - msg += fmt.Sprintf("Download Speed: %v/Sec
\n", utils.Format(st.DownloadSpeed)) - msg += fmt.Sprintf("Upload Speed: %v/Sec
\n
\n", utils.Format(st.UploadSpeed)) - - msg += fmt.Sprintf("\t TotalPeers: %v
\n", st.TotalPeers) - msg += fmt.Sprintf("\t PendingPeers: %v
\n", st.PendingPeers) - msg += fmt.Sprintf("\t ActivePeers: %v
\n", st.ActivePeers) - msg += fmt.Sprintf("\t ConnectedSeeders: %v
\n", st.ConnectedSeeders) - msg += fmt.Sprintf("\t HalfOpenPeers: %v
\n", st.HalfOpenPeers) - - msg += fmt.Sprintf("\t BytesWritten: %v (%v)
\n", st.BytesWritten, bytes.Format(st.BytesWritten)) - msg += fmt.Sprintf("\t BytesWrittenData: %v (%v)
\n", st.BytesWrittenData, bytes.Format(st.BytesWrittenData)) - msg += fmt.Sprintf("\t BytesRead: %v (%v)
\n", st.BytesRead, bytes.Format(st.BytesRead)) - msg += fmt.Sprintf("\t BytesReadData: %v (%v)
\n", st.BytesReadData, bytes.Format(st.BytesReadData)) - msg += fmt.Sprintf("\t BytesReadUsefulData: %v (%v)
\n", st.BytesReadUsefulData, bytes.Format(st.BytesReadUsefulData)) - msg += fmt.Sprintf("\t ChunksWritten: %v
\n", st.ChunksWritten) - msg += fmt.Sprintf("\t ChunksRead: %v
\n", st.ChunksRead) - msg += fmt.Sprintf("\t ChunksReadUseful: %v
\n", st.ChunksReadUseful) - msg += fmt.Sprintf("\t ChunksReadWasted: %v
\n", st.ChunksReadWasted) - msg += fmt.Sprintf("\t PiecesDirtiedGood: %v
\n", st.PiecesDirtiedGood) - msg += fmt.Sprintf("\t PiecesDirtiedBad: %v
\n
\n", st.PiecesDirtiedBad) - if len(st.FileStats) > 0 { - msg += fmt.Sprintf("\t Files:
\n") - for _, f := range st.FileStats { - msg += fmt.Sprintf("\t \t %v Size:%v
\n", f.Path, bytes.Format(f.Length)) - } - } - - hash := metainfo.NewHashFromHex(st.Hash) - cState := bts.CacheState(hash) - if cState != nil { - msg += fmt.Sprintf("CacheType:
\n") - msg += fmt.Sprintf("Capacity: %v
\n", bytes.Format(cState.Capacity)) - msg += fmt.Sprintf("Filled: %v
\n", bytes.Format(cState.Filled)) - msg += fmt.Sprintf("PiecesLength: %v
\n", bytes.Format(cState.PiecesLength)) - msg += fmt.Sprintf("PiecesCount: %v
\n", cState.PiecesCount) - for _, p := range cState.Pieces { - msg += fmt.Sprintf("\t Piece: %v\t  Access: %v\t  Buffer size: %d(%s)\t  Complete: %v\t  Hash: %s\n
", p.Id, p.Accessed, p.BufferSize, bytes.Format(int64(p.BufferSize)), p.Completed, p.Hash) - } - } - msg += "


\n\n" - } - //msg += ` - // - // - //` - return c.HTML(http.StatusOK, msg) -} diff --git a/src/server/web/Server.go b/src/server/web/Server.go deleted file mode 100644 index a789bc8..0000000 --- a/src/server/web/Server.go +++ /dev/null @@ -1,159 +0,0 @@ -package server - -import ( - "fmt" - "log" - "net" - "net/http" - "os" - "runtime" - "sync" - "time" - - "server/settings" - "server/torr" - "server/version" - "server/web/mods" - "server/web/templates" - - "github.com/labstack/echo" - "github.com/labstack/echo/middleware" -) - -var ( - server *echo.Echo - bts *torr.BTServer - - mutex sync.Mutex - fnMutex sync.Mutex - err error -) - -func Start(port string) { - runtime.GOMAXPROCS(runtime.NumCPU()) - - fmt.Println("Start web server, version:", version.Version) - - bts = torr.NewBTS() - err := bts.Connect() - if err != nil { - fmt.Println("Error start torrent client:", err) - return - } - - mutex.Lock() - server = echo.New() - server.HideBanner = true - server.HidePort = true - server.HTTPErrorHandler = HTTPErrorHandler - - //server.Use(middleware.Logger()) - server.Use(middleware.Recover()) - server.Use(ServerHeaderSet) - - templates.InitTemplate(server) - initTorrent(server) - initSettings(server) - initInfo(server) - initAbout(server) - mods.InitMods(server) - - server.GET("/", mainPage) - server.GET("/echo", echoPage) - server.POST("/shutdown", shutdownPage) - server.GET("/js/api.js", templates.ApiJS) - - go func() { - defer mutex.Unlock() - - server.Listener, err = net.Listen("tcp", "0.0.0.0:"+port) - if err == nil { - err = server.Start("0.0.0.0:" + port) - } - server = nil - if err != nil { - fmt.Println("Error start web server:", err) - } - }() -} - -func Stop() { - fnMutex.Lock() - defer fnMutex.Unlock() - if server != nil { - fmt.Println("Stop web server") - server.Close() - server = nil - if bts != nil { - bts.Disconnect() - bts = nil - } - } -} - -func Wait() error { - mutex.Lock() - mutex.Unlock() - return err -} - -func mainPage(c echo.Context) error { - return c.Render(http.StatusOK, "mainPage", nil) -} - -func echoPage(c echo.Context) error { - return c.String(http.StatusOK, version.Version) -} - -func shutdownPage(c echo.Context) error { - go func() { - Stop() - settings.CloseDB() - time.Sleep(time.Second * 2) - os.Exit(5) - }() - return c.NoContent(http.StatusOK) -} - -func ServerHeaderSet(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - c.Response().Header().Set("Access-Control-Allow-Origin", "*") - return next(c) - } -} - -func HTTPErrorHandler(err error, c echo.Context) { - var ( - code = http.StatusInternalServerError - msg interface{} - ) - - if he, ok := err.(*echo.HTTPError); ok { - code = he.Code - msg = he.Message - if he.Internal != nil { - msg = fmt.Sprintf("%v, %v", err, he.Internal) - } - } else { - msg = http.StatusText(code) - } - if _, ok := msg.(string); ok { - msg = echo.Map{"message": msg} - } - - if code != 404 && c.Request().URL.Path != "/torrent/stat" { - log.Println("Web server error:", err, c.Request().URL) - } - - // Send response - if !c.Response().Committed { - if c.Request().Method == echo.HEAD { // Issue #608 - err = c.NoContent(code) - } else { - err = c.JSON(code, msg) - } - if err != nil { - c.Logger().Error(err) - } - } -} diff --git a/src/server/web/Settings.go b/src/server/web/Settings.go deleted file mode 100644 index 32dfc6a..0000000 --- a/src/server/web/Settings.go +++ /dev/null @@ -1,52 +0,0 @@ -package server - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "server/settings" - - "github.com/labstack/echo" -) - -func initSettings(e *echo.Echo) { - e.GET("/settings", settingsPage) - e.POST("/settings/read", settingsRead) - e.POST("/settings/write", settingsWrite) -} - -func settingsPage(c echo.Context) error { - return c.Render(http.StatusOK, "settingsPage", nil) -} - -func settingsRead(c echo.Context) error { - return c.JSON(http.StatusOK, settings.Get()) -} - -func settingsWrite(c echo.Context) error { - err := getJsSettings(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - settings.SaveSettings() - return c.JSON(http.StatusOK, "Ok") -} - -func getJsSettings(c echo.Context) error { - buf, _ := ioutil.ReadAll(c.Request().Body) - decoder := json.NewDecoder(bytes.NewBuffer(buf)) - err := decoder.Decode(settings.Get()) - if err != nil { - if ute, ok := err.(*json.UnmarshalTypeError); ok { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, offset=%v", ute.Type, ute.Value, ute.Offset)) - } else if se, ok := err.(*json.SyntaxError); ok { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())) - } else { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - } - return nil -} diff --git a/src/server/web/Torrent.go b/src/server/web/Torrent.go deleted file mode 100644 index b757793..0000000 --- a/src/server/web/Torrent.go +++ /dev/null @@ -1,720 +0,0 @@ -package server - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "sort" - "strconv" - "strings" - "time" - - "server/settings" - "server/torr" - "server/utils" - "server/web/helpers" - - "github.com/anacrolix/missinggo/httptoo" - "github.com/anacrolix/torrent/metainfo" - "github.com/labstack/echo" -) - -func initTorrent(e *echo.Echo) { - e.POST("/torrent/add", torrentAdd) - e.POST("/torrent/upload", torrentUpload) - e.POST("/torrent/get", torrentGet) - e.POST("/torrent/rem", torrentRem) - e.POST("/torrent/list", torrentList) - e.POST("/torrent/stat", torrentStat) - e.POST("/torrent/cache", torrentCache) - e.POST("/torrent/drop", torrentDrop) - - e.POST("/torrent/viewed/add", torrentViewedAdd) - e.POST("/torrent/viewed/remove", torrentViewedRem) - e.GET("/torrent/viewed/list", torrentViewedList) - - e.GET("/torrent/restart", torrentRestart) - - e.GET("/torrent/playlist.m3u", torrentPlayListAll) - - e.GET("/torrent/play", torrentPlay) - e.HEAD("/torrent/play", torrentPlay) - e.GET("/torrent/play/*", torrentPlay) - e.HEAD("/torrent/play/*", torrentPlay) - - e.GET("/torrent/view/:hash/:file", torrentView) - e.HEAD("/torrent/view/:hash/:file", torrentView) - e.GET("/torrent/preload/:hash/:file", torrentPreload) - e.GET("/torrent/preload/:size/:hash/:file", torrentPreloadSize) -} - -type TorrentJsonRequest struct { - Link string `json:",omitempty"` - Hash string `json:",omitempty"` - Title string `json:",omitempty"` - Info string `json:",omitempty"` - DontSave bool `json:",omitempty"` -} - -type TorrentJsonResponse struct { - Name string - Magnet string - Hash string - AddTime int64 - Length int64 - Status torr.TorrentStatus - Playlist string - Info string - Files []TorFile `json:",omitempty"` -} - -type TorFile struct { - Name string - Link string - Play string - Preload string - Size int64 - Viewed bool -} - -func torrentAdd(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - if jreq.Link == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Link must be non-empty") - } - - magnet, infoBytes, err := helpers.GetMagnet(jreq.Link) - if err != nil { - fmt.Println("Error get magnet:", jreq.Hash, err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - if jreq.Title != "" { - magnet.DisplayName = jreq.Title - } - - tor := bts.GetTorrent(magnet.InfoHash) - if tor != nil { - return c.String(http.StatusOK, magnet.InfoHash.HexString()) - } - - torDb, err := settings.LoadTorrentDB(magnet.InfoHash.HexString()) - if err == nil && torDb != nil { - infoBytes = torDb.InfoBytes - } - - err = helpers.Add(bts, *magnet, infoBytes, !jreq.DontSave) - if err != nil { - fmt.Println("Error add torrent:", jreq.Hash, err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - if jreq.Info != "" { - go func() { - settings.AddInfo(magnet.InfoHash.HexString(), jreq.Info) - }() - } - - return c.String(http.StatusOK, magnet.InfoHash.HexString()) -} - -func torrentUpload(c echo.Context) error { - form, err := c.MultipartForm() - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - defer form.RemoveAll() - - _, dontSave := form.Value["DontSave"] - magnets := map[*metainfo.Magnet][]byte{} - - for _, file := range form.File { - torrFile, err := file[0].Open() - if err != nil { - return err - } - defer torrFile.Close() - - mi, err := metainfo.Load(torrFile) - if err != nil { - fmt.Println("Error upload torrent", err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - info, err := mi.UnmarshalInfo() - if err != nil { - fmt.Println("Error upload torrent", err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - magnet := mi.Magnet(info.Name, mi.HashInfoBytes()) - magnets[&magnet] = mi.InfoBytes - } - - ret := make([]string, 0) - for magnet, infobytes := range magnets { - er := helpers.Add(bts, *magnet, infobytes, !dontSave) - if er != nil { - err = er - fmt.Println("Error add torrent:", magnet.String(), er) - } - ret = append(ret, magnet.InfoHash.HexString()) - } - - return c.JSON(http.StatusOK, ret) -} - -func torrentGet(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - tor, err := settings.LoadTorrentDB(jreq.Hash) - if err != nil { - fmt.Println("Error get torrent:", jreq.Hash, err) - // return echo.NewHTTPError(http.StatusBadRequest, err.Error()) // Handle R/O DB - } - - torrStatus := torr.TorrentAdded - if tor == nil { - hash := metainfo.NewHashFromHex(jreq.Hash) - ts := bts.GetTorrent(hash) - if ts != nil { - torrStatus = ts.Status() - tor = toTorrentDB(ts) - } - } - - if tor == nil { - fmt.Println("Error get: torrent not found", jreq.Hash) - return echo.NewHTTPError(http.StatusBadRequest, "Error get: torrent not found "+jreq.Hash) - } - - js, err := getTorrentJS(tor) - if err != nil { - fmt.Println("Error get torrent:", tor.Hash, err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - js.Status = torrStatus - return c.JSON(http.StatusOK, js) -} - -func torrentRem(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - settings.RemoveTorrentDB(jreq.Hash) - bts.RemoveTorrent(metainfo.NewHashFromHex(jreq.Hash)) - - return c.JSON(http.StatusOK, nil) -} - -func torrentList(c echo.Context) error { - buf, _ := ioutil.ReadAll(c.Request().Body) - jsstr := string(buf) - decoder := json.NewDecoder(bytes.NewBufferString(jsstr)) - jsreq := struct { - Request int - }{} - decoder.Decode(&jsreq) - - reqType := jsreq.Request - - js := make([]TorrentJsonResponse, 0) - list, _ := settings.LoadTorrentsDB() - - for _, tor := range list { - jsTor, err := getTorrentJS(tor) - if err != nil { - fmt.Println("Error get torrent:", err) - } else { - js = append(js, *jsTor) - } - } - - sort.Slice(js, func(i, j int) bool { - if js[i].AddTime == js[j].AddTime { - return js[i].Name < js[j].Name - } - return js[i].AddTime > js[j].AddTime - }) - - slist := bts.List() - - find := func(tjs []TorrentJsonResponse, t *torr.Torrent) bool { - for _, j := range tjs { - if t.Hash().HexString() == j.Hash { - return true - } - } - return false - } - - for _, st := range slist { - if !find(js, st) { - tdb := toTorrentDB(st) - jsTor, err := getTorrentJS(tdb) - if err != nil { - fmt.Println("Error get torrent:", err) - } else { - jsTor.Status = st.Status() - js = append(js, *jsTor) - } - } - } - - if reqType == 1 { - ret := make([]TorrentJsonResponse, 0) - for _, r := range js { - if r.Status == torr.TorrentWorking || len(r.Files) > 0 { - ret = append(ret, r) - } - } - return c.JSON(http.StatusOK, ret) - } else if reqType == 2 { - ret := make([]TorrentJsonResponse, 0) - for _, r := range js { - if r.Status == torr.TorrentGettingInfo { - ret = append(ret, r) - } - } - return c.JSON(http.StatusOK, ret) - } - - return c.JSON(http.StatusOK, js) -} - -func torrentStat(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - hash := metainfo.NewHashFromHex(jreq.Hash) - tor := bts.GetTorrent(hash) - if tor == nil { - return echo.NewHTTPError(http.StatusNotFound) - } - stat := tor.Stats() - - return c.JSON(http.StatusOK, stat) -} - -func torrentCache(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - hash := metainfo.NewHashFromHex(jreq.Hash) - stat := bts.CacheState(hash) - if stat == nil { - return echo.NewHTTPError(http.StatusNotFound) - } - - return c.JSON(http.StatusOK, stat) -} - -func preload(hashHex, fileLink string, size int64) *echo.HTTPError { - if size > 0 { - hash := metainfo.NewHashFromHex(hashHex) - tor := bts.GetTorrent(hash) - if tor == nil { - torrDb, err := settings.LoadTorrentDB(hashHex) - if err != nil || torrDb == nil { - return echo.NewHTTPError(http.StatusBadRequest, "Torrent not found: "+hashHex) - } - m, err := metainfo.ParseMagnetURI(torrDb.Magnet) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error parser magnet in db: "+hashHex) - } - tor, err = bts.AddTorrent(m, torrDb.InfoBytes, nil) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - } - - if !tor.WaitInfo() { - return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info") - } - - file := helpers.FindFileLink(fileLink, tor.Torrent) - if file == nil { - return echo.NewHTTPError(http.StatusNotFound, "file in torrent not found: "+fileLink) - } - tor.Preload(file, size) - } - return nil -} - -func torrentPreload(c echo.Context) error { - hashHex, err := url.PathUnescape(c.Param("hash")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - fileLink, err := url.PathUnescape(c.Param("file")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - if hashHex == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - if fileLink == "" { - return echo.NewHTTPError(http.StatusBadRequest, "File link must be non-empty") - } - - errHttp := preload(hashHex, fileLink, settings.Get().PreloadBufferSize) - if err != nil { - return errHttp - } - - return c.NoContent(http.StatusOK) -} - -func torrentPreloadSize(c echo.Context) error { - hashHex, err := url.PathUnescape(c.Param("hash")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - fileLink, err := url.PathUnescape(c.Param("file")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - szPreload, err := url.PathUnescape(c.Param("size")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - if hashHex == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - if fileLink == "" { - return echo.NewHTTPError(http.StatusBadRequest, "File link must be non-empty") - } - - var size = settings.Get().PreloadBufferSize - if szPreload != "" { - sz, err := strconv.Atoi(szPreload) - if err == nil && sz > 0 { - size = int64(sz) * 1024 * 1024 - } - } - - errHttp := preload(hashHex, fileLink, size) - if err != nil { - return errHttp - } - //redirectUrl := c.Scheme() + "://" + c.Request().Host + filepath.Join("/torrent/view/", hashHex, fileLink) - //return c.Redirect(http.StatusFound, redirectUrl) - return c.NoContent(http.StatusOK) -} - -func torrentDrop(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - bts.RemoveTorrent(metainfo.NewHashFromHex(jreq.Hash)) - return c.NoContent(http.StatusOK) -} - -func torrentViewedAdd(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - err = settings.SetViewed(jreq.Hash) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - return c.NoContent(http.StatusOK) -} - -func torrentViewedRem(c echo.Context) error { - jreq, err := getJsReqTorr(c) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - if jreq.Hash == "" { - return echo.NewHTTPError(http.StatusBadRequest, "Hash must be non-empty") - } - - err = settings.RemTorrentViewed(jreq.Hash) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - return c.NoContent(http.StatusOK) -} - -func torrentViewedList(c echo.Context) error { - err = settings.List(jreq.Hash) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - return c.NoContent(http.StatusOK) -} - -func torrentRestart(c echo.Context) error { - fmt.Println("Restart torrent engine") - err := bts.Reconnect() - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - return c.String(http.StatusOK, "Ok") -} - -func torrentPlayListAll(c echo.Context) error { - list, err := settings.LoadTorrentsDB() - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - - m3u := helpers.MakeM3ULists(list, c.Scheme()+"://"+c.Request().Host) - - c.Response().Header().Set("Content-Type", "audio/x-mpegurl") - c.Response().Header().Set("Connection", "close") - c.Response().Header().Set("Content-Disposition", `attachment; filename="playlist.m3u"`) - http.ServeContent(c.Response(), c.Request(), "playlist.m3u", time.Now(), bytes.NewReader([]byte(m3u))) - return c.NoContent(http.StatusOK) -} - -func torrentPlay(c echo.Context) error { - link := c.QueryParam("link") - if link == "" { - return echo.NewHTTPError(http.StatusBadRequest, "link should not be empty") - } - if (settings.Get().EnableDebug) { - fmt.Println("Play:", c.QueryParams()) // mute log flood on play - } - qsave := c.QueryParam("save") - qpreload := c.QueryParam("preload") - qfile := c.QueryParam("file") - qstat := c.QueryParam("stat") - mm3u := c.QueryParam("m3u") - - preload := int64(0) - stat := strings.ToLower(qstat) == "true" - - if qpreload != "" { - preload, _ = strconv.ParseInt(qpreload, 10, 64) - if preload > 0 { - preload *= 1024 * 1024 - } - } - - magnet, infoBytes, err := helpers.GetMagnet(link) - if err != nil { - fmt.Println("Error get magnet:", link, err) - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - tor := bts.GetTorrent(magnet.InfoHash) - if tor == nil { - tor, err = bts.AddTorrent(*magnet, infoBytes, nil) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - } - - if stat { - return c.JSON(http.StatusOK, getTorPlayState(tor)) - } - - if !tor.WaitInfo() { - return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info") - } - - if strings.ToLower(qsave) == "true" { - if t, err := settings.LoadTorrentDB(magnet.InfoHash.HexString()); t == nil && err == nil { - torrDb := toTorrentDB(tor) - if torrDb != nil { - torrDb.InfoBytes = infoBytes - settings.SaveTorrentDB(torrDb) - } - } - } - - if strings.ToLower(mm3u) == "true" { - mt := tor.Torrent.Metainfo() - m3u := helpers.MakeM3UPlayList(tor.Stats(), mt.Magnet(tor.Name(), tor.Hash()).String(), c.Scheme()+"://"+c.Request().Host) - c.Response().Header().Set("Content-Type", "audio/x-mpegurl") - c.Response().Header().Set("Connection", "close") - name := utils.CleanFName(tor.Name()) + ".m3u" - c.Response().Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", tor.Hash().HexString(), name))) - c.Response().Header().Set("Content-Disposition", `attachment; filename="`+name+`"`) - http.ServeContent(c.Response(), c.Request(), name, time.Now(), bytes.NewReader([]byte(m3u))) - return c.NoContent(http.StatusOK) - } - - files := helpers.GetPlayableFiles(tor.Stats()) - - if len(files) == 1 { - file := helpers.FindFile(files[0].Id, tor) - if file == nil { - return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprint("File", files[0], "not found in torrent", tor.Name())) - } - - return bts.Play(tor, file, preload, c) - } - - if qfile == "" && len(files) > 1 { - return c.JSON(http.StatusOK, getTorPlayState(tor)) - } - - fileInd, _ := strconv.Atoi(qfile) - file := helpers.FindFile(fileInd, tor) - if file == nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprint("File index ", fileInd, " not found in torrent ", tor.Name())) - } - return bts.Play(tor, file, preload, c) -} - -func torrentView(c echo.Context) error { - hashHex, err := url.PathUnescape(c.Param("hash")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - fileLink, err := url.PathUnescape(c.Param("file")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - - hash := metainfo.NewHashFromHex(hashHex) - tor := bts.GetTorrent(hash) - if tor == nil { - torrDb, err := settings.LoadTorrentDB(hashHex) - if err != nil || torrDb == nil { - return echo.NewHTTPError(http.StatusBadRequest, "Torrent not found: "+hashHex) - } - - m, err := metainfo.ParseMagnetURI(torrDb.Magnet) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Error parser magnet in db: "+hashHex) - } - - tor, err = bts.AddTorrent(m, torrDb.InfoBytes, nil) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - } - - if !tor.WaitInfo() { - return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info") - } - - file := helpers.FindFileLink(fileLink, tor.Torrent) - if file == nil { - return echo.NewHTTPError(http.StatusNotFound, "File in torrent not found: "+fileLink) - } - return bts.View(tor, file, c) -} - -func toTorrentDB(t *torr.Torrent) *settings.Torrent { - if t == nil { - return nil - } - tor := new(settings.Torrent) - tor.Name = t.Name() - tor.Hash = t.Hash().HexString() - tor.Timestamp = settings.StartTime.Unix() - mi := t.Torrent.Metainfo() - tor.Magnet = mi.Magnet(t.Name(), t.Torrent.InfoHash()).String() - tor.Size = t.Length() - - st := getTorPlayState(t) - - for _, f := range st.FileStats { - tf := settings.File{ - Id: f.Id, - Name: f.Path, - Size: f.Length, - } - tor.Files = append(tor.Files, tf) - } - return tor -} - -func getTorrentJS(tor *settings.Torrent) (*TorrentJsonResponse, error) { - js := new(TorrentJsonResponse) - mag, err := metainfo.ParseMagnetURI(tor.Magnet) - js.Name = tor.Name - if err == nil && len(tor.Name) < len(mag.DisplayName) { - js.Name = mag.DisplayName - } - mag.Trackers = []string{} // remove retrackers for small link size - mag.DisplayName = "" // clear dn from link - long query params may fail in QueryParam("link") - js.Magnet = tor.Magnet - js.Hash = tor.Hash - js.AddTime = tor.Timestamp - js.Length = tor.Size - js.Playlist = "/torrent/play?link=" + url.QueryEscape(mag.String()) + "&m3u=true" - var size int64 = 0 - for _, f := range tor.Files { - size += f.Size - tf := TorFile{ - Name: f.Name, - Link: "/torrent/view/" + js.Hash + "/" + utils.CleanFName(f.Name), - Play: "/torrent/play/" + utils.CleanFName(f.Name) + "?link=" + url.QueryEscape(mag.String()) + "&file=" + fmt.Sprint(f.Id), - Preload: "/torrent/play/" + utils.CleanFName(f.Name) + "?link=" + url.QueryEscape(mag.String()) + "&file=" + fmt.Sprint(f.Id) + "&preload=true", - Size: f.Size, - Viewed: settings.GetViewed(tor.Hash, f.Name), - } - js.Files = append(js.Files, tf) - } - if tor.Size == 0 { - js.Length = size - } - - js.Info = settings.GetInfo(tor.Hash) - - return js, nil -} - -func getJsReqTorr(c echo.Context) (*TorrentJsonRequest, error) { - buf, _ := ioutil.ReadAll(c.Request().Body) - jsstr := string(buf) - decoder := json.NewDecoder(bytes.NewBufferString(jsstr)) - js := new(TorrentJsonRequest) - err := decoder.Decode(js) - if err != nil { - if ute, ok := err.(*json.UnmarshalTypeError); ok { - return nil, echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, offset=%v", ute.Type, ute.Value, ute.Offset)) - } else if se, ok := err.(*json.SyntaxError); ok { - return nil, echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())) - } else { - return nil, echo.NewHTTPError(http.StatusBadRequest, err.Error()) - } - } - return js, nil -} diff --git a/src/server/web/TorrentState.go b/src/server/web/TorrentState.go deleted file mode 100644 index fd4c46a..0000000 --- a/src/server/web/TorrentState.go +++ /dev/null @@ -1,67 +0,0 @@ -package server - -import ( - "server/torr" - "server/web/helpers" -) - -type TorrentStat struct { - Name string - Hash string - - TorrentStatus int - TorrentStatusString string - - LoadedSize int64 - TorrentSize int64 - - PreloadedBytes int64 - PreloadSize int64 - - DownloadSpeed float64 - UploadSpeed float64 - - TotalPeers int - PendingPeers int - ActivePeers int - ConnectedSeeders int - - FileStats []FileStat -} - -type FileStat struct { - Id int - Path string - Length int64 -} - -func getTorPlayState(tor *torr.Torrent) TorrentStat { - tst := tor.Stats() - ts := TorrentStat{} - ts.Name = tst.Name - ts.Hash = tst.Hash - ts.TorrentStatus = int(tst.TorrentStatus) - ts.TorrentStatusString = tst.TorrentStatusString - ts.LoadedSize = tst.LoadedSize - ts.TorrentSize = tst.TorrentSize - ts.PreloadedBytes = tst.PreloadedBytes - ts.PreloadSize = tst.PreloadSize - ts.DownloadSpeed = tst.DownloadSpeed - ts.UploadSpeed = tst.UploadSpeed - ts.TotalPeers = tst.TotalPeers - ts.PendingPeers = tst.PendingPeers - ts.ActivePeers = tst.ActivePeers - ts.ConnectedSeeders = tst.ConnectedSeeders - - files := helpers.GetPlayableFiles(tst) - ts.FileStats = make([]FileStat, len(files)) - for i, f := range files { - ts.FileStats[i] = FileStat{ - Id: f.Id, - Path: f.Path, - Length: f.Length, - } - } - - return ts -} diff --git a/src/server/web/helpers/Buffer.go b/src/server/web/helpers/Buffer.go deleted file mode 100644 index 541d946..0000000 --- a/src/server/web/helpers/Buffer.go +++ /dev/null @@ -1,42 +0,0 @@ -package helpers - -import "bytes" - -type SeekingBuffer struct { - str string - buffer *bytes.Buffer - offset int64 - size int64 -} - -func NewSeekingBuffer(str string) *SeekingBuffer { - return &SeekingBuffer{ - str: str, - buffer: bytes.NewBufferString(str), - offset: 0, - } -} - -func (fb *SeekingBuffer) Read(p []byte) (n int, err error) { - n, err = fb.buffer.Read(p) - fb.offset += int64(n) - return n, err -} - -func (fb *SeekingBuffer) Seek(offset int64, whence int) (ret int64, err error) { - var newoffset int64 - switch whence { - case 0: - newoffset = offset - case 1: - newoffset = fb.offset + offset - case 2: - newoffset = int64(len(fb.str)) - offset - } - if newoffset == fb.offset { - return newoffset, nil - } - fb.buffer = bytes.NewBufferString(fb.str[newoffset:]) - fb.offset = newoffset - return fb.offset, nil -} diff --git a/src/server/web/helpers/M3u.go b/src/server/web/helpers/M3u.go deleted file mode 100644 index d345907..0000000 --- a/src/server/web/helpers/M3u.go +++ /dev/null @@ -1,53 +0,0 @@ -package helpers - -import ( - "fmt" - "net/url" - "path/filepath" - - "server/settings" - "server/torr" - "server/utils" -) - -func MakeM3ULists(torrents []*settings.Torrent, host string) string { - m3u := "#EXTM3U\n" - - for _, t := range torrents { - m3u += "#EXTINF:0 type=\"playlist\"," + t.Name + "\n" - - magnet := t.Magnet - mag, _, err := GetMagnet(magnet) - if err == nil { - mag.Trackers = []string{} // remove retrackers for small link size - mag.DisplayName = "" // clear dn from link - long query params may fail in QueryParam("link") - magnet = mag.String() - } - m3u += host + "/torrent/play?link=" + url.QueryEscape(magnet) + "&m3u=true\n" - } - return m3u -} - -func MakeM3UPlayList(tor torr.TorrentStats, magnet string, host string) string { - m3u := "#EXTM3U\n" - - mag, _, err := GetMagnet(magnet) - if err == nil { - mag.Trackers = []string{} //Remove retrackers for small link size - mag.DisplayName = "" //Remove dn from link (useless) - magnet = mag.String() - } - magnet = url.QueryEscape(magnet) - - for _, f := range tor.FileStats { - if GetMimeType(f.Path) != "*/*" { - fn := filepath.Base(f.Path) - if fn == "" { - fn = f.Path - } - m3u += "#EXTINF:0," + fn + "\n" - m3u += host + "/torrent/play/" + url.QueryEscape(utils.CleanFName(f.Path)) + "?link=" + magnet + "&file=" + fmt.Sprint(f.Id) + "\n" - } - } - return m3u -} diff --git a/src/server/web/helpers/Magnet.go b/src/server/web/helpers/Magnet.go deleted file mode 100644 index fc8f74a..0000000 --- a/src/server/web/helpers/Magnet.go +++ /dev/null @@ -1,101 +0,0 @@ -package helpers - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "runtime" - "strings" - "time" - - "server/settings" - - "github.com/anacrolix/torrent/metainfo" -) - -func GetMagnet(link string) (*metainfo.Magnet, []byte, error) { - url, err := url.Parse(link) - if err != nil { - return nil, nil, err - } - - var mag *metainfo.Magnet - var infoBytes []byte - switch strings.ToLower(url.Scheme) { - case "magnet": - mag, err = getMag(url.String()) - if err == nil { - torDb, err := settings.LoadTorrentDB(mag.InfoHash.HexString()) - if err == nil && torDb != nil { - infoBytes = torDb.InfoBytes - } - } - case "http", "https": - mag, infoBytes, err = getMagFromHttp(url.String()) - case "": - mag, err = getMag("magnet:?xt=urn:btih:" + url.Path) - case "file": - mag, infoBytes, err = getMagFromFile(url.Path) - default: - err = fmt.Errorf("unknown scheme:", url, url.Scheme) - } - if err != nil { - return nil, nil, err - } - - return mag, infoBytes, nil -} - -func getMag(link string) (*metainfo.Magnet, error) { - mag, err := metainfo.ParseMagnetURI(link) - return &mag, err -} - -func getMagFromHttp(url string) (*metainfo.Magnet, []byte, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - client := new(http.Client) - client.Timeout = time.Duration(time.Second * 30) - req.Header.Set("User-Agent", "DWL/1.1.1 (Torrent)") - - resp, err := client.Do(req) - if err != nil { - return nil, nil, err - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return nil, nil, errors.New(resp.Status) - } - - minfo, err := metainfo.Load(resp.Body) - if err != nil { - return nil, nil, err - } - info, err := minfo.UnmarshalInfo() - if err != nil { - return nil, nil, err - } - mag := minfo.Magnet(info.Name, minfo.HashInfoBytes()) - return &mag, minfo.InfoBytes, nil -} - -func getMagFromFile(path string) (*metainfo.Magnet, []byte, error) { - if runtime.GOOS == "windows" && strings.HasPrefix(path, "/") { - path = strings.TrimPrefix(path, "/") - } - minfo, err := metainfo.LoadFromFile(path) - if err != nil { - return nil, nil, err - } - info, err := minfo.UnmarshalInfo() - if err != nil { - return nil, nil, err - } - - mag := minfo.Magnet(info.Name, minfo.HashInfoBytes()) - return &mag, minfo.InfoBytes, nil -} diff --git a/src/server/web/helpers/Mime.go b/src/server/web/helpers/Mime.go deleted file mode 100644 index 4a30efa..0000000 --- a/src/server/web/helpers/Mime.go +++ /dev/null @@ -1,89 +0,0 @@ -package helpers - -import ( - "path/filepath" - - "server/torr" -) - -var extVideo = map[string]interface{}{ - ".3g2": nil, - ".3gp": nil, - ".aaf": nil, - ".asf": nil, - ".avchd": nil, - ".avi": nil, - ".drc": nil, - ".flv": nil, - ".m2ts": nil, - ".ts": nil, - ".m2v": nil, - ".m4p": nil, - ".m4v": nil, - ".mkv": nil, - ".mng": nil, - ".mov": nil, - ".mp2": nil, - ".mp4": nil, - ".mpe": nil, - ".mpeg": nil, - ".mpg": nil, - ".mpv": nil, - ".mxf": nil, - ".nsv": nil, - ".ogg": nil, - ".ogv": nil, - ".qt": nil, - ".rm": nil, - ".rmvb": nil, - ".roq": nil, - ".svi": nil, - ".vob": nil, - ".webm": nil, - ".wmv": nil, - ".yuv": nil, -} - -var extAudio = map[string]interface{}{ - ".aac": nil, - ".aiff": nil, - ".ape": nil, - ".au": nil, - ".flac": nil, - ".gsm": nil, - ".it": nil, - ".m3u": nil, - ".m4a": nil, - ".mid": nil, - ".mod": nil, - ".mp3": nil, - ".mpa": nil, - ".pls": nil, - ".ra": nil, - ".s3m": nil, - ".sid": nil, - ".wav": nil, - ".wma": nil, - ".xm": nil, -} - -func GetMimeType(filename string) string { - ext := filepath.Ext(filename) - if _, ok := extVideo[ext]; ok { - return "video/*" - } - if _, ok := extAudio[ext]; ok { - return "audio/*" - } - return "*/*" -} - -func GetPlayableFiles(st torr.TorrentStats) []torr.TorrentFileStat { - files := make([]torr.TorrentFileStat, 0) - for _, f := range st.FileStats { - if GetMimeType(f.Path) != "*/*" { - files = append(files, f) - } - } - return files -} diff --git a/src/server/web/helpers/Torrent.go b/src/server/web/helpers/Torrent.go deleted file mode 100644 index eb90dd7..0000000 --- a/src/server/web/helpers/Torrent.go +++ /dev/null @@ -1,70 +0,0 @@ -package helpers - -import ( - "fmt" - "sort" - "time" - - "server/settings" - "server/torr" - "server/utils" - - "github.com/anacrolix/torrent" - "github.com/anacrolix/torrent/metainfo" -) - -func Add(bts *torr.BTServer, magnet metainfo.Magnet, infobytes []byte, save bool) error { - fmt.Println("Adding torrent", magnet.String()) - _, err := bts.AddTorrent(magnet, infobytes, func(torr *torr.Torrent) { - if torr, _ := settings.LoadTorrentDB(magnet.InfoHash.HexString()); torr != nil { - return - } - torDb := new(settings.Torrent) - torDb.Name = torr.Name() - torDb.Hash = torr.Hash().HexString() - torDb.Size = torr.Length() - torDb.Magnet = magnet.String() - torDb.InfoBytes = infobytes - torDb.Timestamp = time.Now().Unix() - files := torr.Stats().FileStats - sort.Slice(files, func(i, j int) bool { - return files[i].Path < files[j].Path - }) - for _, f := range files { - ff := settings.File{ - Id: f.Id, - Name: f.Path, - Size: f.Length, - } - torDb.Files = append(torDb.Files, ff) - } - - if save { - err := settings.SaveTorrentDB(torDb) - if err != nil { - fmt.Println("Error add torrent to db:", err) - } - } - }) - if err != nil { - return err - } - return nil -} - -func FindFileLink(fileLink string, torr *torrent.Torrent) *torrent.File { - for _, f := range torr.Files() { - if utils.CleanFName(f.Path()) == fileLink { - return f - } - } - return nil -} - -func FindFile(fileInd int, tor *torr.Torrent) *torrent.File { - files := tor.Files() - if len(files) == 0 || fileInd < 0 || fileInd >= len(files) { - return nil - } - return files[fileInd] -} diff --git a/src/server/web/mods/Mods.go b/src/server/web/mods/Mods.go deleted file mode 100644 index a9d9e1d..0000000 --- a/src/server/web/mods/Mods.go +++ /dev/null @@ -1,22 +0,0 @@ -package mods - -import ( - "github.com/labstack/echo" -) - -func InitMods(e *echo.Echo) { - e.GET("/test", test) -} - -func test(c echo.Context) error { - return c.HTML(200, ` - - - - - - - - -`) -} diff --git a/src/server/web/templates/AboutPage.go b/src/server/web/templates/AboutPage.go deleted file mode 100644 index edebfe7..0000000 --- a/src/server/web/templates/AboutPage.go +++ /dev/null @@ -1,122 +0,0 @@ -package templates - -import "server/version" - -var aboutPage = ` - - - - - - - - - - - - - About - - - - -
- -

TorrServer

-

` + version.Version + `

- -

Поддержка проекта:

- PayPal -
- Yandex.Деньги -
-
-
- -

Инструкция по использованию:

- 4pda.ru -

Спасибо MadAndron

-
-
-
- -

Автор:

- YouROK -
- Email: - 8YouROK8@gmail.com -
- Site: - GitHub.com/YouROK -
- Telegram: - @TorrServe -
-
-
- -

Спасибо всем, кто тестировал и помогал:

- kuzzman -
- Site: - 4pda.ru - tv-box.pp.ua -
-
- MadAndron -
- Site: - 4pda.ru -
-
- SpAwN_LMG -
- Site: - 4pda.ru -
-
- Zivio -
- Site: - 4pda.ru - forum.hdtv.ru -
-
- Tw1cker Руслан Пахнев -
- Site: - 4pda.ru - GitHub.com/Nemiroff -
-
-
- - - -` - -func (t *Template) parseAboutPage() { - parsePage(t, "aboutPage", aboutPage) -} diff --git a/src/server/web/templates/ApiJS.go b/src/server/web/templates/ApiJS.go deleted file mode 100644 index 0413a46..0000000 --- a/src/server/web/templates/ApiJS.go +++ /dev/null @@ -1,133 +0,0 @@ -package templates - -import ( - "net/http" - - "server/settings" - "server/web/helpers" - - "github.com/labstack/echo" -) - -var apijs = ` -function addTorrent(link, save, info, done, fail){ - var reqJson = JSON.stringify({ Link: link, Info: info, DontSave: !save}); - $.post('/torrent/add',reqJson) - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function getTorrent(hash, done, fail){ - var reqJson = JSON.stringify({ Hash: hash}); - $.post('/torrent/get',reqJson) - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function removeTorrent(hash, done, fail){ - var reqJson = JSON.stringify({ Hash: hash}); - $.post('/torrent/rem',reqJson) - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function statTorrent(hash, done, fail){ - var reqJson = JSON.stringify({ Hash: hash}); - $.post('/torrent/stat',reqJson) - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function cacheTorrent(hash, done, fail){ - var reqJson = JSON.stringify({ Hash: hash}); - $.post('/torrent/cache',reqJson) - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function listTorrent(done, fail){ - $.post('/torrent/list') - .done(function( data ) { - if (done) - done(data); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function restartService(done, fail){ - $.get('/torrent/restart') - .done(function( data ) { - if (done) - done(); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function preloadTorrent(preloadLink, done, fail){ - $.get(preloadLink) - .done(function( data ) { - if (done) - done(); - }) - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function shutdownServer(fail){ - $.post('/shutdown') - .fail(function( data ) { - if (fail) - fail(data); - }); -} - -function humanizeSize(size) { - if (typeof size == 'undefined' || size == 0) - return ""; - var i = Math.floor( Math.log(size) / Math.log(1024) ); - return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]; -} -` - -func ApiJS(c echo.Context) error { - http.ServeContent(c.Response(), c.Request(), "api.js", settings.StartTime, helpers.NewSeekingBuffer(apijs)) - return c.NoContent(http.StatusOK) -} diff --git a/src/server/web/templates/CachePage.go b/src/server/web/templates/CachePage.go deleted file mode 100644 index 841b374..0000000 --- a/src/server/web/templates/CachePage.go +++ /dev/null @@ -1,173 +0,0 @@ -package templates - -import ( - "server/version" -) - -var cachePage = ` - - - - - - - - - - - - - TorrServer ` + version.Version + ` - - - - - -
-
-
-
-
- - - - -` - -func (t *Template) parseCachePage() { - parsePage(t, "cachePage", cachePage) -} diff --git a/src/server/web/templates/FavIcon.go b/src/server/web/templates/FavIcon.go deleted file mode 100644 index 13ae5b6..0000000 --- a/src/server/web/templates/FavIcon.go +++ /dev/null @@ -1,3 +0,0 @@ -package templates - -var faviconB64 = "data:image/png;base64,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" diff --git a/src/server/web/templates/MainPage.go b/src/server/web/templates/MainPage.go deleted file mode 100644 index e0629ad..0000000 --- a/src/server/web/templates/MainPage.go +++ /dev/null @@ -1,300 +0,0 @@ -package templates - -import ( - "server/version" -) - -var mainPage = ` - - - - - - - - - - - - - TorrServer ` + version.Version + ` - - - - - -
-
- - -
-
- - -
-
-
- Плейлист всех торрентов -
-
-

Торренты:

-
-
-
- Настройки - Кэш - -
- -
- - - - - - -` - -func (t *Template) parseMainPage() { - parsePage(t, "mainPage", mainPage) -} diff --git a/src/server/web/templates/SettingsPage.go b/src/server/web/templates/SettingsPage.go deleted file mode 100644 index 365d6af..0000000 --- a/src/server/web/templates/SettingsPage.go +++ /dev/null @@ -1,244 +0,0 @@ -package templates - -import "server/version" - -var settingsPage = ` - - - - - - - - - - - - - - TorrServer ` + version.Version + ` Settings - - - - - -
-
-
-
-
Размер кэша
-
- -
-
-
-
-
Размер буфера предзагрузки
-
- -
- Размеры кэша и буфера указываются в мегабайтах -
-
-
-
Таймаут отключения торрента
-
- -
- Время (секунд) после которого закроется торрент, после отключения соединения -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
Шифрование
-
- -
-
-
-
-
Порт для входящих торрент подключений
-
- -
- 0 - случайный порт -
-
-
-
Количество соединений
-
- -
-
-
-
-
Количество соединений DHT (0 - не ограничивать)
-
- -
-
-
-
-
Ограничение загрузки
-
- -
-
-
-
-
Ограничение отдачи
-
- -
- Ограничение устанавливается в Килобайтах, 0 - не ограничивать -
-
-
-
Ретрекеры
-
- -
-
-
-
- - -
-
- - - - - -` - -func (t *Template) parseSettingsPage() { - parsePage(t, "settingsPage", settingsPage) -} diff --git a/src/server/web/templates/Template.go b/src/server/web/templates/Template.go deleted file mode 100644 index 607cfcd..0000000 --- a/src/server/web/templates/Template.go +++ /dev/null @@ -1,45 +0,0 @@ -package templates - -import ( - "html/template" - "io" - - "github.com/labstack/echo" -) - -type Template struct { - templates *template.Template -} - -func InitTemplate(e *echo.Echo) { - temp := new(Template) - - temp.parseMainPage() - temp.parseSettingsPage() - temp.parseAboutPage() - temp.parseCachePage() - - e.Renderer = temp -} - -func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error { - return t.templates.ExecuteTemplate(w, name, data) -} - -func parsePage(temp *Template, name, page string) error { - s := page - var tmpl *template.Template - if temp.templates == nil { - temp.templates = template.New(name) - } - if name == temp.templates.Name() { - tmpl = temp.templates - } else { - tmpl = temp.templates.New(name) - } - _, err := tmpl.Parse(s) - if err != nil { - return err - } - return nil -}