torrentfs: Write client status to HTTP port

This commit is contained in:
Matt Joiner 2014-06-26 17:29:12 +10:00
parent 809aabe531
commit cf31465904
4 changed files with 94 additions and 3 deletions

View File

@ -109,6 +109,15 @@ type Client struct {
dataWaiter chan struct{}
}
func (cl *Client) WriteStatus(w io.Writer) {
cl.mu.Lock()
defer cl.mu.Unlock()
for _, t := range cl.torrents {
fmt.Fprintf(w, "%s: %f%%\n", t.MetaInfo.Name, 100*(1-float32(t.BytesLeft())/float32(t.Length())))
t.WriteStatus(w)
}
}
// Read torrent data at the given offset. Returns ErrDataNotReady if the data
// isn't available.
func (cl *Client) TorrentReadAt(ih InfoHash, off int64, p []byte) (n int, err error) {

View File

@ -26,7 +26,7 @@ var (
mountDir string
disableTrackers = flag.Bool("disableTrackers", false, "disables trackers")
testPeer = flag.String("testPeer", "", "the address for a test peer")
pprofAddr = flag.String("pprofAddr", "", "pprof HTTP server bind address")
httpAddr = flag.String("httpAddr", "", "HTTP server bind address")
readaheadBytes = flag.Int("readaheadBytes", 10*1024*1024, "bytes to readahead in each torrent from the last read piece")
testPeerAddr *net.TCPAddr
)
@ -120,8 +120,8 @@ func main() {
os.Exit(2)
}
log.SetFlags(log.LstdFlags | log.Lshortfile)
if *pprofAddr != "" {
go http.ListenAndServe(*pprofAddr, nil)
if *httpAddr != "" {
go http.ListenAndServe(*httpAddr, nil)
}
conn, err := fuse.Mount(mountDir)
if err != nil {
@ -136,6 +136,9 @@ func main() {
DisableTrackers: *disableTrackers,
DownloadStrategy: &torrent.ResponsiveDownloadStrategy{*readaheadBytes},
}
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
client.WriteStatus(w)
})
client.Start()
addTorrentDir(client, torrentPath)
resolveTestPeerAddr()

View File

@ -3,6 +3,8 @@ package torrent
import (
"container/list"
"encoding"
"fmt"
"io"
"log"
"net"
"sync"
@ -34,6 +36,47 @@ type connection struct {
PeerMaxRequests int // Maximum pending requests the peer allows.
}
func (cn *connection) completedString() string {
if cn.PeerPieces == nil {
return "?"
}
f := float32(cn.piecesPeerHasCount()) / float32(cn.totalPiecesCount())
return fmt.Sprintf("%d%%", int(f*100))
}
func (cn *connection) totalPiecesCount() int {
return len(cn.PeerPieces)
}
func (cn *connection) piecesPeerHasCount() (count int) {
for _, has := range cn.PeerPieces {
if has {
count++
}
}
return
}
func (cn *connection) WriteStatus(w io.Writer) {
fmt.Fprintf(w, "%q: %s-%s: %s completed: ", cn.PeerId, cn.Socket.LocalAddr(), cn.Socket.RemoteAddr(), cn.completedString())
c := func(b byte) {
fmt.Fprintf(w, "%c", b)
}
// https://trac.transmissionbt.com/wiki/PeerStatusText
if len(cn.Requests) != 0 {
c('D')
} else if cn.Interested {
c('d')
}
if !cn.PeerChoked && !cn.Interested {
c('K')
}
if !cn.Choked && !cn.PeerInterested {
c('?')
}
fmt.Fprintln(w)
}
func (c *connection) Close() {
c.mu.Lock()
if c.closed {

View File

@ -3,6 +3,7 @@ package torrent
import (
"container/list"
"fmt"
"io"
"net"
"sort"
@ -38,6 +39,37 @@ type torrent struct {
lastReadPiece int
}
func (t *torrent) pieceStatusChar(index int) byte {
p := t.Pieces[index]
switch {
case p.Complete():
return 'C'
case p.QueuedForHash:
return 'Q'
case p.Hashing:
return 'H'
case t.PiecePartiallyDownloaded(index):
return 'P'
default:
return '.'
}
}
func (t *torrent) WriteStatus(w io.Writer) {
fmt.Fprint(w, "Pieces: ")
for index := range t.Pieces {
fmt.Fprintf(w, "%c", t.pieceStatusChar(index))
}
fmt.Fprintln(w)
fmt.Fprintln(w, "Priorities: ")
for e := t.Priorities.Front(); e != nil; e = e.Next() {
fmt.Fprintf(w, "\t%v\n", e.Value)
}
for _, c := range t.Conns {
c.WriteStatus(w)
}
}
func (t *torrent) String() string {
return t.MetaInfo.Name
}
@ -49,6 +81,10 @@ func (t *torrent) BytesLeft() (left int64) {
return
}
func (t *torrent) PiecePartiallyDownloaded(index int) bool {
return t.PieceNumPendingBytes(pp.Integer(index)) != t.PieceLength(pp.Integer(index))
}
func NumChunksForPiece(chunkSize int, pieceSize int) int {
return (pieceSize + chunkSize - 1) / chunkSize
}