package torrent
import (
- "bitbucket.org/anacrolix/go.torrent/dht"
- "bitbucket.org/anacrolix/go.torrent/util"
"bufio"
"crypto/rand"
"crypto/sha1"
"syscall"
"time"
+ "bitbucket.org/anacrolix/go.torrent/dht"
+ . "bitbucket.org/anacrolix/go.torrent/util"
+
"github.com/anacrolix/libtorgo/metainfo"
"github.com/nsf/libtorgo/bencode"
if !t.haveInfo() {
return errors.New("missing metadata")
}
- me.DownloadStrategy.TorrentPrioritize(t, off, len_)
+ me.downloadStrategy.TorrentPrioritize(t, off, len_)
for _, cn := range t.Conns {
me.replenishConnRequests(t, cn)
}
}
type Client struct {
- DataDir string
- HalfOpenLimit int
- PeerId [20]byte
- Listener net.Listener
- DisableTrackers bool
- DownloadStrategy DownloadStrategy
- DHT *dht.Server
+ dataDir string
+ halfOpenLimit int
+ peerID [20]byte
+ listener net.Listener
+ disableTrackers bool
+ downloadStrategy DownloadStrategy
+ dHT *dht.Server
mu sync.Mutex
event sync.Cond
dataWaiter chan struct{}
}
+func (me *Client) ListenAddr() net.Addr {
+ return me.listener.Addr()
+}
+
func (cl *Client) WriteStatus(w io.Writer) {
cl.mu.Lock()
defer cl.mu.Unlock()
- if cl.Listener != nil {
- fmt.Fprintf(w, "Listening on %s\n", cl.Listener.Addr())
+ if cl.listener != nil {
+ fmt.Fprintf(w, "Listening on %s\n", cl.listener.Addr())
} else {
fmt.Fprintf(w, "No listening torrent port!\n")
}
- fmt.Fprintf(w, "Peer ID: %q\n", cl.PeerId)
+ fmt.Fprintf(w, "Peer ID: %q\n", cl.peerID)
fmt.Fprintf(w, "Half open outgoing connections: %d\n", cl.halfOpen)
- if cl.DHT != nil {
- fmt.Fprintf(w, "DHT nodes: %d\n", cl.DHT.NumNodes())
+ if cl.dHT != nil {
+ fmt.Fprintf(w, "DHT nodes: %d\n", cl.dHT.NumNodes())
+ fmt.Fprintf(w, "DHT Server ID: %x\n", cl.dHT.IDString())
}
fmt.Fprintln(w)
for _, t := range cl.torrents {
return t.Data.ReadAt(p, off)
}
-// Starts the client. Defaults are applied. The client will begin accepting
-// connections and tracking.
-func (c *Client) Start() {
- c.event.L = &c.mu
- c.torrents = make(map[InfoHash]*torrent)
- if c.HalfOpenLimit == 0 {
- c.HalfOpenLimit = 10
+func NewClient(cfg *Config) (cl *Client, err error) {
+ if cfg == nil {
+ cfg = &Config{}
}
- o := copy(c.PeerId[:], BEP20)
- _, err := rand.Read(c.PeerId[o:])
+
+ cl = &Client{
+ disableTrackers: cfg.DisableTrackers,
+ downloadStrategy: cfg.DownloadStrategy,
+ halfOpenLimit: 100,
+ dataDir: cfg.DataDir,
+
+ quit: make(chan struct{}),
+ torrents: make(map[InfoHash]*torrent),
+ }
+ cl.event.L = &cl.mu
+
+ o := copy(cl.peerID[:], BEP20)
+ _, err = rand.Read(cl.peerID[o:])
if err != nil {
panic("error generating peer id")
}
- c.quit = make(chan struct{})
- if c.DownloadStrategy == nil {
- c.DownloadStrategy = &DefaultDownloadStrategy{}
+
+ if cl.downloadStrategy == nil {
+ cl.downloadStrategy = &DefaultDownloadStrategy{}
+ }
+
+ cl.listener, err = net.Listen("tcp", cfg.ListenAddr)
+ if err != nil {
+ return
}
- if c.Listener != nil {
- go c.acceptConnections()
+ if cl.listener != nil {
+ go cl.acceptConnections()
}
+
+ if !cfg.NoDHT {
+ cl.dHT, err = dht.NewServer(&dht.ServerConfig{
+ Addr: cfg.ListenAddr,
+ })
+ if err != nil {
+ return
+ }
+ }
+
+ return
}
func (cl *Client) stopped() bool {
func (cl *Client) acceptConnections() {
for {
- conn, err := cl.Listener.Accept()
+ conn, err := cl.listener.Accept()
select {
case <-cl.quit:
if conn != nil {
// Start the process of connecting to the given peer for the given torrent if
// appropriate.
func (me *Client) initiateConn(peer Peer, torrent *torrent) {
- if peer.Id == me.PeerId {
+ if peer.Id == me.peerID {
return
}
me.halfOpen++
}
func (cl *Client) incomingPeerPort() int {
- if cl.Listener == nil {
+ if cl.listener == nil {
return 0
}
- _, p, err := net.SplitHostPort(cl.Listener.Addr().String())
+ _, p, err := net.SplitHostPort(cl.listener.Addr().String())
if err != nil {
panic(err)
}
func (cl *Client) connCancel(t *torrent, cn *connection, r request) (ok bool) {
ok = cn.Cancel(r)
if ok {
- cl.DownloadStrategy.DeleteRequest(t, r)
+ cl.downloadStrategy.DeleteRequest(t, r)
}
return
}
if !cn.RequestPending(r) {
return
}
- cl.DownloadStrategy.DeleteRequest(t, r)
+ cl.downloadStrategy.DeleteRequest(t, r)
delete(cn.Requests, r)
}
func (me *Client) openNewConns() {
for _, t := range me.torrents {
for len(t.Peers) != 0 {
- if me.halfOpen >= me.HalfOpenLimit {
+ if me.halfOpen >= me.halfOpenLimit {
return
}
p := t.Peers[0]
}
func (cl *Client) setMetaData(t *torrent, md metainfo.Info, bytes []byte) (err error) {
- err = t.setMetadata(md, cl.DataDir, bytes)
+ err = t.setMetadata(md, cl.dataDir, bytes)
if err != nil {
return
}
}
}()
- cl.DownloadStrategy.TorrentStarted(t)
+ cl.downloadStrategy.TorrentStarted(t)
return
}
return
}
me.torrents[t.InfoHash] = t
- if !me.DisableTrackers {
+ if !me.disableTrackers {
go me.announceTorrent(t)
}
- if me.DHT != nil {
+ if me.dHT != nil {
go me.announceTorrentDHT(t)
}
return
}
func (cl *Client) listenerAnnouncePort() (port int16) {
- l := cl.Listener
+ l := cl.listener
if l == nil {
return
}
func (cl *Client) announceTorrentDHT(t *torrent) {
for {
- ps, err := cl.DHT.GetPeers(string(t.InfoHash[:]))
+ ps, err := cl.dHT.GetPeers(string(t.InfoHash[:]))
if err != nil {
log.Printf("error getting peers from dht: %s", err)
return
Event: tracker.Started,
NumWant: -1,
Port: cl.listenerAnnouncePort(),
- PeerId: cl.PeerId,
+ PeerId: cl.peerID,
InfoHash: t.InfoHash,
}
newAnnounce:
}
func (cl *Client) assertRequestHeat() {
- dds, ok := cl.DownloadStrategy.(*DefaultDownloadStrategy)
+ dds, ok := cl.downloadStrategy.(*DefaultDownloadStrategy)
if !ok {
return
}
if !t.haveInfo() {
return
}
- me.DownloadStrategy.FillRequests(t, c)
+ me.downloadStrategy.FillRequests(t, c)
//me.assertRequestHeat()
if len(c.Requests) == 0 && !c.PeerChoked {
c.SetInterested(false)
}
// Unprioritize the chunk.
- me.DownloadStrategy.TorrentGotChunk(t, req)
+ me.downloadStrategy.TorrentGotChunk(t, req)
// Cancel pending requests for this chunk.
cancelled := false
p.EverHashed = true
if correct {
p.PendingChunkSpecs = nil
- me.DownloadStrategy.TorrentGotPiece(t, int(piece))
+ me.downloadStrategy.TorrentGotPiece(t, int(piece))
me.dataReady(dataSpec{
t.InfoHash,
request{
"testing"
)
+func TestClientDefault(t *testing.T) {
+ cl, err := NewClient(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cl.Stop()
+}
+
func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
t.SkipNow()
}
package main
import (
- "bitbucket.org/anacrolix/go.torrent/dht"
- "bitbucket.org/anacrolix/go.torrent/tracker"
- _ "bitbucket.org/anacrolix/go.torrent/util/profile"
"flag"
"fmt"
"io"
"net"
"os"
"os/signal"
+ "time"
+
+ "bitbucket.org/anacrolix/go.torrent/dht"
+ "bitbucket.org/anacrolix/go.torrent/util"
+ _ "bitbucket.org/anacrolix/go.torrent/util/profile"
)
type pingResponse struct {
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
infoHash = flag.String("infoHash", "", "torrent infohash")
- s dht.Server
+ s *dht.Server
)
func loadTable() error {
log.Fatal("require 20 byte infohash")
}
var err error
- s.Socket, err = net.ListenUDP("udp4", func() *net.UDPAddr {
- addr, err := net.ResolveUDPAddr("udp4", *serveAddr)
- if err != nil {
- log.Fatalf("error resolving serve addr: %s", err)
- }
- return addr
- }())
+ s, err = dht.NewServer(&dht.ServerConfig{
+ Addr: *serveAddr,
+ })
if err != nil {
log.Fatal(err)
}
- s.Init()
err = loadTable()
if err != nil {
log.Fatalf("error loading table: %s", err)
}
- log.Printf("dht server on %s, ID is %q", s.Socket.LocalAddr(), s.IDString())
+ log.Printf("dht server on %s, ID is %q", s.LocalAddr(), s.IDString())
setupSignals()
}
}
func main() {
- go func() {
- defer s.StopServing()
- if err := s.Bootstrap(); err != nil {
- log.Printf("error bootstrapping: %s", err)
- return
- }
- saveTable()
+ seen := make(map[util.CompactPeer]struct{})
+ for {
ps, err := s.GetPeers(*infoHash)
if err != nil {
log.Fatal(err)
}
- seen := make(map[tracker.CompactPeer]struct{})
- for sl := range ps.Values {
- for _, p := range sl {
- if _, ok := seen[p]; ok {
- continue
+ go func() {
+ for sl := range ps.Values {
+ for _, p := range sl {
+ if _, ok := seen[p]; ok {
+ continue
+ }
+ seen[p] = struct{}{}
+ fmt.Println((&net.UDPAddr{
+ IP: p.IP[:],
+ Port: int(p.Port),
+ }).String())
}
- seen[p] = struct{}{}
- fmt.Println((&net.UDPAddr{
- IP: p.IP[:],
- Port: int(p.Port),
- }).String())
}
- }
- }()
- err := s.Serve()
+ }()
+ time.Sleep(15 * time.Second)
+ }
if err := saveTable(); err != nil {
log.Printf("error saving node table: %s", err)
}
- if err != nil {
- log.Fatalf("error serving dht: %s", err)
- }
}
package main
import (
- "bitbucket.org/anacrolix/go.torrent/dht"
"flag"
"log"
"net"
"os"
+
+ "bitbucket.org/anacrolix/go.torrent/dht"
)
type pingResponse struct {
os.Stderr.WriteString("u must specify addrs of nodes to ping e.g. router.bittorrent.com:6881\n")
os.Exit(2)
}
- s := dht.Server{}
- var err error
- s.Socket, err = net.ListenUDP("udp4", nil)
+ s, err := dht.NewServer(nil)
if err != nil {
log.Fatal(err)
}
- log.Printf("dht server on %s", s.Socket.LocalAddr())
- s.Init()
- go func() {
- err := s.Serve()
- if err != nil {
- log.Fatal(err)
- }
- }()
+ log.Printf("dht server on %s", s.LocalAddr())
pingResponses := make(chan pingResponse)
for _, netloc := range pingStrAddrs {
addr, err := net.ResolveUDPAddr("udp4", netloc)
package main
import (
- "bitbucket.org/anacrolix/go.torrent/dht"
"flag"
"fmt"
"io"
"log"
- "net"
"os"
"os/signal"
+
+ "bitbucket.org/anacrolix/go.torrent/dht"
)
type pingResponse struct {
tableFileName = flag.String("tableFile", "", "name of file for storing node info")
serveAddr = flag.String("serveAddr", ":0", "local UDP address")
- s dht.Server
+ s *dht.Server
)
func loadTable() error {
log.SetFlags(log.LstdFlags | log.Lshortfile)
flag.Parse()
var err error
- s.Socket, err = net.ListenUDP("udp4", func() *net.UDPAddr {
- addr, err := net.ResolveUDPAddr("udp4", *serveAddr)
- if err != nil {
- log.Fatalf("error resolving serve addr: %s", err)
- }
- return addr
- }())
+ s, err = dht.NewServer(&dht.ServerConfig{
+ Addr: *serveAddr,
+ })
if err != nil {
log.Fatal(err)
}
- s.Init()
err = loadTable()
if err != nil {
log.Fatalf("error loading table: %s", err)
}
- log.Printf("dht server on %s, ID is %q", s.Socket.LocalAddr(), s.IDString())
+ log.Printf("dht server on %s, ID is %q", s.LocalAddr(), s.IDString())
setupSignals()
}
}
func main() {
- go func() {
- err := s.Bootstrap()
- if err != nil {
- log.Printf("error bootstrapping: %s", err)
- s.StopServing()
- } else {
- log.Print("bootstrapping complete")
- }
- }()
- err := s.Serve()
+ select {}
if err := saveTable(); err != nil {
log.Printf("error saving node table: %s", err)
}
- if err != nil {
- log.Fatalf("error serving dht: %s", err)
- }
}
package main
import (
- "bitbucket.org/anacrolix/go.torrent/dht"
- "bitbucket.org/anacrolix/go.torrent/util"
"flag"
"fmt"
"log"
"os"
"strings"
+ "bitbucket.org/anacrolix/go.torrent/util"
+
"github.com/anacrolix/libtorgo/metainfo"
"bitbucket.org/anacrolix/go.torrent"
flag.Parse()
}
-func makeListener() net.Listener {
- l, err := net.Listen("tcp", *listenAddr)
- if err != nil {
- log.Fatal(err)
- }
- return l
-}
-
func main() {
if *httpAddr != "" {
util.LoggedHTTPServe(*httpAddr)
}
- dhtServer := &dht.Server{
- Socket: func() *net.UDPConn {
- addr, err := net.ResolveUDPAddr("udp4", *listenAddr)
- if err != nil {
- log.Fatalf("error resolving dht listen addr: %s", err)
- }
- s, err := net.ListenUDP("udp4", addr)
- if err != nil {
- log.Fatalf("error creating dht socket: %s", err)
- }
- return s
- }(),
- }
- err := dhtServer.Init()
- if err != nil {
- log.Fatalf("error initing dht server: %s", err)
- }
- go func() {
- err := dhtServer.Serve()
- if err != nil {
- log.Fatalf("error serving dht: %s", err)
- }
- }()
- go func() {
- err := dhtServer.Bootstrap()
- if err != nil {
- log.Printf("error bootstrapping dht server: %s", err)
- }
- }()
- client := torrent.Client{
+ client, err := torrent.NewClient(&torrent.Config{
DataDir: *downloadDir,
- Listener: makeListener(),
DisableTrackers: *disableTrackers,
- DHT: dhtServer,
+ ListenAddr: *listenAddr,
+ })
+ if err != nil {
+ log.Fatalf("error creating client: %s", err)
}
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
client.WriteStatus(w)
})
- client.Start()
defer client.Stop()
if flag.NArg() == 0 {
fmt.Fprintln(os.Stderr, "no torrents specified")
flag.StringVar(&mountDir, "mountDir", "", "location the torrent contents are made available")
}
-func makeListener() net.Listener {
- l, err := net.Listen("tcp", *listenAddr)
- if err != nil {
- log.Fatal(err)
- }
- return l
-}
-
func resolveTestPeerAddr() {
if *testPeer == "" {
return
// TODO: Think about the ramifications of exiting not due to a signal.
setSignalHandlers()
defer conn.Close()
- client := &torrent.Client{
+ client, err := torrent.NewClient(&torrent.Config{
DataDir: downloadDir,
DisableTrackers: *disableTrackers,
DownloadStrategy: torrent.NewResponsiveDownloadStrategy(*readaheadBytes),
- Listener: makeListener(),
- }
+ ListenAddr: *listenAddr,
+ })
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
client.WriteStatus(w)
})
- client.Start()
dw, err := dirwatch.New(torrentPath)
if err != nil {
log.Fatal(err)
--- /dev/null
+package torrent
+
+type Config struct {
+ DataDir string
+ ListenAddr string
+ DisableTrackers bool
+ DownloadStrategy DownloadStrategy
+ NoDHT bool
+}
package dht
import (
- "bitbucket.org/anacrolix/go.torrent/tracker"
- "bitbucket.org/anacrolix/go.torrent/util"
"crypto"
_ "crypto/sha1"
"encoding/binary"
"errors"
"fmt"
- "github.com/nsf/libtorgo/bencode"
"io"
"log"
"net"
"os"
"sync"
"time"
+
+ "bitbucket.org/anacrolix/go.torrent/util"
+ "github.com/nsf/libtorgo/bencode"
)
type Server struct {
- ID string
- Socket *net.UDPConn
+ id string
+ socket *net.UDPConn
transactions []*transaction
transactionIDInt uint64
nodes map[string]*Node // Keyed by *net.UDPAddr.String().
closed chan struct{}
}
+type ServerConfig struct {
+ Addr string
+}
+
+func (s *Server) LocalAddr() net.Addr {
+ return s.socket.LocalAddr()
+}
+
+func makeSocket(addr string) (socket *net.UDPConn, err error) {
+ addr_, err := net.ResolveUDPAddr("", addr)
+ if err != nil {
+ return
+ }
+ socket, err = net.ListenUDP("udp", addr_)
+ return
+}
+
+func NewServer(c *ServerConfig) (s *Server, err error) {
+ s = &Server{}
+ s.socket, err = makeSocket(c.Addr)
+ if err != nil {
+ return
+ }
+ err = s.init()
+ if err != nil {
+ return
+ }
+ go func() {
+ panic(s.serve())
+ }()
+ go func() {
+ err := s.bootstrap()
+ if err != nil {
+ panic(err)
+ }
+ }()
+ return
+}
+
func (s *Server) String() string {
- return fmt.Sprintf("dht server on %s", s.Socket.LocalAddr())
+ return fmt.Sprintf("dht server on %s", s.socket.LocalAddr())
}
type Node struct {
}
func (s *Server) setDefaults() (err error) {
- if s.Socket == nil {
- var addr *net.UDPAddr
- addr, err = net.ResolveUDPAddr("", ":6882")
- if err != nil {
- return
- }
- s.Socket, err = net.ListenUDP("udp", addr)
- if err != nil {
- return
- }
- }
- if s.ID == "" {
+ if s.id == "" {
var id [20]byte
h := crypto.SHA1.New()
ss, err := os.Hostname()
if err != nil {
log.Print(err)
}
- ss += s.Socket.LocalAddr().String()
+ ss += s.socket.LocalAddr().String()
h.Write([]byte(ss))
if b := h.Sum(id[:0:20]); len(b) != 20 {
panic(len(b))
if len(id) != 20 {
panic(len(id))
}
- s.ID = string(id[:])
+ s.id = string(id[:])
}
s.nodes = make(map[string]*Node, 10000)
return
}
-func (s *Server) Init() (err error) {
+func (s *Server) init() (err error) {
err = s.setDefaults()
if err != nil {
return
return
}
-func (s *Server) Serve() error {
+func (s *Server) serve() error {
for {
var b [0x10000]byte
- n, addr, err := s.Socket.ReadFromUDP(b[:])
+ n, addr, err := s.socket.ReadFromUDP(b[:])
if err != nil {
return err
}
}
func (s *Server) writeToNode(b []byte, node *net.UDPAddr) (err error) {
- n, err := s.Socket.WriteTo(b, node)
+ n, err := s.socket.WriteTo(b, node)
if err != nil {
err = fmt.Errorf("error writing %d bytes to %s: %s", len(b), node, err)
return
}
func (s *Server) IDString() string {
- if len(s.ID) != 20 {
+ if len(s.id) != 20 {
panic("bad node id")
}
- return s.ID
+ return s.id
}
func (s *Server) timeoutTransaction(t *transaction) {
return
}
-type getPeersResponse struct {
- Values []tracker.CompactPeer `bencode:"values"`
- Nodes util.CompactPeers `bencode:"nodes"`
-}
-
type peerStream struct {
mu sync.Mutex
- Values chan []tracker.CompactPeer
+ Values chan []util.CompactPeer
stop chan struct{}
}
case <-ps.stop:
default:
close(ps.stop)
- close(ps.Values)
}
ps.mu.Unlock()
}
-func extractValues(m Msg) (vs []tracker.CompactPeer) {
+func extractValues(m Msg) (vs []util.CompactPeer) {
r, ok := m["r"]
if !ok {
return
if !ok {
return
}
- // log.Fatal(m)
vl, ok := v.([]interface{})
if !ok {
panic(v)
}
- vs = make([]tracker.CompactPeer, 0, len(vl))
+ vs = make([]util.CompactPeer, 0, len(vl))
for _, i := range vl {
- // log.Printf("%T", i)
s, ok := i.(string)
if !ok {
panic(i)
}
- var cp tracker.CompactPeer
+ var cp util.CompactPeer
err := cp.UnmarshalBinary([]byte(s))
if err != nil {
log.Printf("error decoding values list element: %s", err)
func (s *Server) GetPeers(infoHash string) (ps *peerStream, err error) {
ps = &peerStream{
- Values: make(chan []tracker.CompactPeer),
+ Values: make(chan []util.CompactPeer),
stop: make(chan struct{}),
}
done := make(chan struct{})
case <-s.closed:
}
}
- ps.Close()
+ close(ps.Values)
}()
return
}
}
// Populates the node table.
-func (s *Server) Bootstrap() (err error) {
+func (s *Server) bootstrap() (err error) {
s.mu.Lock()
defer s.mu.Unlock()
if len(s.nodes) == 0 {
var outstanding sync.WaitGroup
for _, node := range s.nodes {
var t *transaction
- t, err = s.findNode(node.addr, s.ID)
+ t, err = s.findNode(node.addr, s.id)
if err != nil {
return
}
}
func (s *Server) StopServing() {
- s.Socket.Close()
+ s.socket.Close()
s.mu.Lock()
select {
case <-s.closed:
"io/ioutil"
"log"
"net"
+ "net/http"
+ _ "net/http/pprof"
"os"
"path/filepath"
"testing"
"time"
+ "bitbucket.org/anacrolix/go.torrent"
"bitbucket.org/anacrolix/go.torrent/testutil"
+ "bitbucket.org/anacrolix/go.torrent/util"
+ "github.com/anacrolix/libtorgo/metainfo"
"bazil.org/fuse"
fusefs "bazil.org/fuse/fs"
- "bitbucket.org/anacrolix/go.torrent"
- "github.com/anacrolix/libtorgo/metainfo"
)
+func init() {
+ go http.ListenAndServe(":6061", nil)
+}
+
func TestTCPAddrString(t *testing.T) {
ta := &net.TCPAddr{
IP: net.IPv4(127, 0, 0, 1),
metaInfoBuf := &bytes.Buffer{}
testutil.CreateMetaInfo(name, metaInfoBuf)
tl.Metainfo, err = metainfo.Load(metaInfoBuf)
+ log.Printf("%x", tl.Metainfo.Info.Pieces)
return
}
t.Log(err)
}
}()
- client := torrent.Client{
+ client, err := torrent.NewClient(&torrent.Config{
DataDir: filepath.Join(layout.BaseDir, "incomplete"),
DisableTrackers: true,
- }
- client.Start()
+ NoDHT: true,
+ })
log.Printf("%+v", *layout.Metainfo)
client.AddTorrent(layout.Metainfo)
- fs := New(&client)
+ fs := New(client)
fuseConn, err := fuse.Mount(layout.MountDir)
if err != nil {
t.Fatal(err)
if err != nil {
t.Fatal(err)
}
- seeder := torrent.Client{
- DataDir: layout.Completed,
- Listener: func() net.Listener {
- conn, err := net.Listen("tcp", ":0")
- if err != nil {
- panic(err)
- }
- return conn
- }(),
+ seeder, err := torrent.NewClient(&torrent.Config{
+ DataDir: layout.Completed,
DisableTrackers: true,
- }
- defer seeder.Listener.Close()
- seeder.Start()
+ NoDHT: true,
+ })
+ http.HandleFunc("/seeder", func(w http.ResponseWriter, req *http.Request) {
+ seeder.WriteStatus(w)
+ })
defer seeder.Stop()
err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%x", layout.Metainfo.Info.Hash))
if err != nil {
t.Fatal(err)
}
- leecher := torrent.Client{
+ leecher, err := torrent.NewClient(&torrent.Config{
DataDir: filepath.Join(layout.BaseDir, "download"),
- DownloadStrategy: &torrent.ResponsiveDownloadStrategy{},
+ DownloadStrategy: torrent.NewResponsiveDownloadStrategy(0),
DisableTrackers: true,
- }
- leecher.Start()
+ NoDHT: true,
+ })
+ http.HandleFunc("/leecher", func(w http.ResponseWriter, req *http.Request) {
+ leecher.WriteStatus(w)
+ })
defer leecher.Stop()
leecher.AddTorrent(layout.Metainfo)
- leecher.AddPeers(torrent.BytesInfoHash(layout.Metainfo.Info.Hash), []torrent.Peer{func() torrent.Peer {
- tcpAddr := seeder.Listener.Addr().(*net.TCPAddr)
+ var ih torrent.InfoHash
+ util.CopyExact(ih[:], layout.Metainfo.Info.Hash)
+ leecher.AddPeers(ih, []torrent.Peer{func() torrent.Peer {
+ tcpAddr := seeder.ListenAddr().(*net.TCPAddr)
return torrent.Peer{
IP: tcpAddr.IP,
Port: tcpAddr.Port,
}
}()})
- fs := New(&leecher)
+ fs := New(leecher)
mountDir := layout.MountDir
fuseConn, err := fuse.Mount(layout.MountDir)
if err != nil {