16 "github.com/anacrolix/dht/v2"
17 "github.com/anacrolix/torrent"
18 "github.com/anacrolix/torrent/metainfo"
19 "github.com/dustin/go-humanize"
30 TorrentStats = map[metainfo.Hash]torrent.TorrentStats{}
31 TorrentStatsM sync.RWMutex
34 func recreateFIFO(pth string) {
36 if err := syscall.Mkfifo(pth, 0666); err != nil {
41 func shortenName(name string) string {
43 if len(s) > MaxListNameWidth {
44 s = s[:MaxListNameWidth]
49 func fifoList(c *torrent.Client) {
50 pth := path.Join(FIFOsDir, "list")
53 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
55 log.Println("OpenFile:", pth, err)
56 time.Sleep(time.Second)
60 sort.Sort(ByInfoHash(ts))
61 for _, t := range ts {
63 fmt.Fprintf(fd, "%s not ready\n", t.Name())
67 done := t.BytesCompleted() * 100 / t.Length()
72 tx := stats.BytesWrittenData.Int64()
73 tx += TxStats[t.InfoHash()]
74 ratio := float64(tx) / float64(t.Length())
76 prev := TorrentStats[t.InfoHash()]
77 TorrentStatsM.RUnlock()
78 rxSpeed := stats.BytesReadData.Int64() - prev.BytesReadData.Int64()
79 txSpeed := stats.BytesWrittenData.Int64() - prev.BytesWrittenData.Int64()
81 if done < 100 && rxSpeed > 0 {
82 etaRaw := time.Duration((t.Length() - t.BytesCompleted()) / rxSpeed)
87 "%s%s%s %s%40s%s %8s %s%3d%%%s %4.1f %s%d%s/%s%d%s %d/%d/%d/%d %s\n",
88 Blue, t.InfoHash().HexString(), Reset,
89 Green, shortenName(t.Name()), Reset,
90 humanize.IBytes(uint64(t.Length())),
91 percColour, done, Reset,
93 Green, rxSpeed/1024, Reset,
94 Magenta, txSpeed/1024, Reset,
98 stats.ConnectedSeeders,
103 time.Sleep(time.Second)
107 func mustParseInt(s string) int {
108 i, err := strconv.Atoi(s)
115 func fifoPeerList(t *torrent.Torrent) {
116 pth := path.Join(FIFOsDir, PeersDir, t.InfoHash().HexString())
119 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
121 if os.IsNotExist(err) {
124 log.Println("OpenFile:", pth, err)
125 time.Sleep(time.Second)
129 sort.Sort(ByPeerID(pcs))
130 for _, pc := range pcs {
131 cols := strings.Split(pc.CompletedString(), "/")
132 done := (mustParseInt(cols[0]) * 100) / mustParseInt(cols[1])
137 stats := pc.Peer.Stats()
139 "%s%s%s %10s %s%3d%%%s %s%d%s/%s%d%s %s / %s | %s%s%s %q\n",
140 Blue, hex.EncodeToString(pc.PeerID[:]), Reset,
142 doneColour, done, Reset,
143 Green, int(pc.DownloadRate()/1024), Reset,
144 Magenta, int(pc.UploadRate()/1024), Reset,
145 humanize.IBytes(uint64(stats.BytesReadData.Int64())),
146 humanize.IBytes(uint64(stats.BytesWrittenData.Int64())),
147 Green, pc.RemoteAddr, Reset,
152 time.Sleep(time.Second)
156 func fifoFileList(t *torrent.Torrent) {
157 pth := path.Join(FIFOsDir, FilesDir, t.InfoHash().HexString())
160 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
162 if os.IsNotExist(err) {
165 log.Println("OpenFile:", pth, err)
166 time.Sleep(time.Second)
169 for n, f := range t.Files() {
172 done = (f.BytesCompleted() * 100) / f.Length()
179 "%5d %8s %3d%% | %s%s%s\n",
180 n, humanize.IBytes(uint64(f.Length())), done,
181 percColour, f.Path(), Reset,
185 time.Sleep(time.Second)
189 func fifoDHTList(c *torrent.Client) {
190 pth := path.Join(FIFOsDir, "dht")
193 fd, err := os.OpenFile(pth, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
195 if os.IsNotExist(err) {
198 log.Println("OpenFile:", pth, err)
199 time.Sleep(time.Second)
202 for _, s := range c.DhtServers() {
203 stats := s.Stats().(dht.ServerStats)
205 fd, "%s%s%s all:%d good:%d await:%d succ:%d bad:%d\n",
206 Green, s.Addr().String(), Reset,
209 stats.OutstandingTransactions,
210 stats.SuccessfulOutboundAnnouncePeerQueries,
215 time.Sleep(time.Second)