16 "github.com/anacrolix/dht/v2"
17 "github.com/anacrolix/torrent"
18 "github.com/anacrolix/torrent/metainfo"
19 "github.com/dustin/go-humanize"
29 type TorrentStat struct {
30 stats torrent.ConnStats
36 TorrentStats = map[metainfo.Hash]TorrentStat{}
37 TorrentStatsM sync.RWMutex
40 func recreateFIFO(pth string) {
42 if err := syscall.Mkfifo(pth, 0666); err != nil {
47 func shortenName(name string) string {
49 if len(s) > MaxListNameWidth {
50 s = s[:MaxListNameWidth]
55 func fifoList(c *torrent.Client) {
56 pth := path.Join(FIFOsDir, "list")
59 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
61 log.Println("OpenFile:", pth, err)
62 time.Sleep(time.Second)
66 sort.Sort(ByInfoHash(ts))
67 for _, t := range ts {
69 fmt.Fprintf(fd, "%s not ready\n", t.Name())
73 done := t.BytesCompleted() * 100 / t.Length()
78 tx := stats.BytesWrittenData.Int64()
79 tx += TxStats[t.InfoHash()]
80 ratio := float64(tx) / float64(t.Length())
82 prev := TorrentStats[t.InfoHash()]
83 TorrentStatsM.RUnlock()
85 if done < 100 && prev.rxSpeed > 0 {
86 etaRaw := time.Duration((t.Length() - t.BytesCompleted()) / prev.rxSpeed)
91 "%s%s%s %s%40s%s %8s %s%3d%%%s %4.1f %s%d%s/%s%d%s %d/%d/%d/%d %s\n",
92 Blue, t.InfoHash().HexString(), Reset,
93 Green, shortenName(t.Name()), Reset,
94 humanize.IBytes(uint64(t.Length())),
95 percColour, done, Reset,
97 Green, prev.rxSpeed/1024, Reset,
98 Magenta, prev.txSpeed/1024, Reset,
102 stats.ConnectedSeeders,
107 time.Sleep(time.Second)
111 func mustParseInt(s string) int {
112 i, err := strconv.Atoi(s)
119 func fifoPeerList(t *torrent.Torrent) {
120 pth := path.Join(FIFOsDir, PeersDir, t.InfoHash().HexString())
123 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
125 if os.IsNotExist(err) {
128 log.Println("OpenFile:", pth, err)
129 time.Sleep(time.Second)
133 sort.Sort(ByPeerID(pcs))
134 for _, pc := range pcs {
135 cols := strings.Split(pc.CompletedString(), "/")
136 done := (mustParseInt(cols[0]) * 100) / mustParseInt(cols[1])
141 stats := pc.Peer.Stats()
143 "%s%s%s %10s %s%3d%%%s %s%d%s/%s%d%s %s / %s | %s%s%s %q\n",
144 Blue, hex.EncodeToString(pc.PeerID[:]), Reset,
146 doneColour, done, Reset,
147 Green, int(pc.DownloadRate()/1024), Reset,
148 Magenta, int(pc.UploadRate()/1024), Reset,
149 humanize.IBytes(uint64(stats.BytesReadData.Int64())),
150 humanize.IBytes(uint64(stats.BytesWrittenData.Int64())),
151 Green, pc.RemoteAddr, Reset,
156 time.Sleep(time.Second)
160 func fifoFileList(t *torrent.Torrent) {
161 pth := path.Join(FIFOsDir, FilesDir, t.InfoHash().HexString())
164 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
166 if os.IsNotExist(err) {
169 log.Println("OpenFile:", pth, err)
170 time.Sleep(time.Second)
173 for n, f := range t.Files() {
176 done = (f.BytesCompleted() * 100) / f.Length()
183 "%5d %8s %3d%% | %s%s%s\n",
184 n, humanize.IBytes(uint64(f.Length())), done,
185 percColour, f.Path(), Reset,
189 time.Sleep(time.Second)
193 func fifoDHTList(c *torrent.Client) {
194 pth := path.Join(FIFOsDir, "dht")
197 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
199 if os.IsNotExist(err) {
202 log.Println("OpenFile:", pth, err)
203 time.Sleep(time.Second)
206 for _, s := range c.DhtServers() {
207 stats := s.Stats().(dht.ServerStats)
209 fd, "%s%s%s all:%d good:%d await:%d succ:%d bad:%d\n",
210 Green, s.Addr().String(), Reset,
213 stats.OutstandingTransactions,
214 stats.SuccessfulOutboundAnnouncePeerQueries,
219 time.Sleep(time.Second)