func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) tagflag.Parse(&opts, tagflag.SkipBadTypes()) clientConfig := opts.Config if opts.Mmap { clientConfig.TorrentDataOpener = func(info *metainfo.Info) torrent.Data { ret, err := mmap.TorrentData(info, "") if err != nil { log.Fatalf("error opening torrent data for %q: %s", info.Name, err) } return ret } } client, err := torrent.NewClient(&clientConfig) if err != nil { log.Fatalf("error creating client: %s", err) } defer client.Close() http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { client.WriteStatus(w) }) uiprogress.Start() addTorrents(client) if client.WaitAll() { log.Print("downloaded ALL the torrents") } else { log.Fatal("y u no complete torrents?!") } if opts.Seed { select {} } }
func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) var rootGroup struct { Client torrent.Config `group:"Client Options"` TestPeers []string `long:"test-peer" description:"address of peer to inject to every torrent"` MMap bool `long:"mmap" description:"memory-map the torrent files"` } // Don't pass flags.PrintError because it's inconsistent with printing. // https://github.com/jessevdk/go-flags/issues/132 parser := flags.NewParser(&rootGroup, flags.HelpFlag|flags.PassDoubleDash) parser.Usage = "[OPTIONS] (magnet URI or .torrent file path)..." posArgs, err := parser.Parse() if err != nil { fmt.Fprintln(os.Stderr, "Download from the BitTorrent network.") fmt.Println(err) os.Exit(2) } testPeers, err := resolvedPeerAddrs(rootGroup.TestPeers) if err != nil { log.Fatal(err) } if rootGroup.MMap { rootGroup.Client.TorrentDataOpener = func(info *metainfo.Info) torrent.Data { ret, err := mmap.TorrentData(info, "") if err != nil { log.Fatalf("error opening torrent data for %q: %s", info.Name, err) } return ret } } if len(posArgs) == 0 { fmt.Fprintln(os.Stderr, "no torrents specified") return } client, err := torrent.NewClient(&rootGroup.Client) if err != nil { log.Fatalf("error creating client: %s", err) } http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { client.WriteStatus(w) }) defer client.Close() for _, arg := range posArgs { t := func() torrent.Torrent { if strings.HasPrefix(arg, "magnet:") { t, err := client.AddMagnet(arg) if err != nil { log.Fatalf("error adding magnet: %s", err) } return t } else { metaInfo, err := metainfo.LoadFromFile(arg) if err != nil { log.Fatal(err) } t, err := client.AddTorrent(metaInfo) if err != nil { log.Fatal(err) } return t } }() err := t.AddPeers(testPeers) if err != nil { log.Fatal(err) } go func() { <-t.GotInfo() t.DownloadAll() }() } done := make(chan struct{}) go func() { defer close(done) if client.WaitAll() { log.Print("downloaded ALL the torrents") } else { log.Fatal("y u no complete torrents?!") } }() ticker := time.NewTicker(time.Second) waitDone: for { select { case <-done: break waitDone case <-ticker.C: os.Stdout.WriteString(progressLine(client)) } } if rootGroup.Client.Seed { select {} } }
func TestDownloadOnDemand(t *testing.T) { layout, err := newGreetingLayout() if err != nil { t.Fatal(err) } defer layout.Destroy() seeder, err := torrent.NewClient(&torrent.Config{ DataDir: layout.Completed, DisableTrackers: true, NoDHT: true, ListenAddr: ":0", Seed: true, NoDefaultBlocklist: true, // Ensure that the metainfo is obtained over the wire, since we added // the torrent to the seeder by magnet. DisableMetainfoCache: true, }) if err != nil { t.Fatalf("error creating seeder client: %s", err) } seeder.SetIPBlockList(nil) defer seeder.Close() http.HandleFunc("/seeder", func(w http.ResponseWriter, req *http.Request) { seeder.WriteStatus(w) }) _, err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%x", layout.Metainfo.Info.Hash)) if err != nil { t.Fatal(err) } leecher, err := torrent.NewClient(&torrent.Config{ DisableTrackers: true, NoDHT: true, ListenAddr: ":0", DisableTCP: true, NoDefaultBlocklist: true, TorrentDataOpener: func(info *metainfo.Info) data.Data { ret, _ := mmap.TorrentData(info, filepath.Join(layout.BaseDir, "download")) return ret }, // This can be used to check if clients can connect to other clients // with the same ID. // PeerID: seeder.PeerID(), }) leecher.SetIPBlockList(nil) http.HandleFunc("/leecher", func(w http.ResponseWriter, req *http.Request) { leecher.WriteStatus(w) }) defer leecher.Close() leecherTorrent, _ := leecher.AddTorrent(layout.Metainfo) leecherTorrent.AddPeers([]torrent.Peer{func() torrent.Peer { _, port, err := net.SplitHostPort(seeder.ListenAddr().String()) if err != nil { panic(err) } portInt64, err := strconv.ParseInt(port, 0, 0) if err != nil { panic(err) } return torrent.Peer{ IP: func() net.IP { ret, _ := net.ResolveIPAddr("ip", "localhost") return ret.IP }(), Port: int(portInt64), } }()}) fs := New(leecher) defer fs.Destroy() root, _ := fs.Root() node, _ := root.(fusefs.NodeStringLookuper).Lookup(netContext.Background(), "greeting") var attr fuse.Attr node.Attr(netContext.Background(), &attr) size := attr.Size resp := &fuse.ReadResponse{ Data: make([]byte, size), } node.(fusefs.HandleReader).Read(netContext.Background(), &fuse.ReadRequest{ Size: int(size), }, resp) content := resp.Data if string(content) != testutil.GreetingFileContents { t.Fatalf("%q != %q", string(content), testutil.GreetingFileContents) } }
func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) var opts struct { torrent.Config `name:"Client"` Mmap bool `help:"memory-map torrent data"` TestPeer []*net.TCPAddr `short:"p" help:"addresses of some starting peers"` Torrent []string `type:"pos" arity:"+" help:"torrent file path or magnet uri"` } tagflag.Parse(&opts, tagflag.SkipBadTypes()) clientConfig := opts.Config if opts.Mmap { clientConfig.TorrentDataOpener = func(info *metainfo.Info) torrent.Data { ret, err := mmap.TorrentData(info, "") if err != nil { log.Fatalf("error opening torrent data for %q: %s", info.Name, err) } return ret } } torrents := opts.Torrent if len(torrents) == 0 { fmt.Fprintf(os.Stderr, "no torrents specified\n") return } client, err := torrent.NewClient(&clientConfig) if err != nil { log.Fatalf("error creating client: %s", err) } http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { client.WriteStatus(w) }) defer client.Close() for _, arg := range torrents { t := func() torrent.Torrent { if strings.HasPrefix(arg, "magnet:") { t, err := client.AddMagnet(arg) if err != nil { log.Fatalf("error adding magnet: %s", err) } return t } else { metaInfo, err := metainfo.LoadFromFile(arg) if err != nil { fmt.Fprintf(os.Stderr, "error loading torrent file %q: %s\n", arg, err) os.Exit(1) } t, err := client.AddTorrent(metaInfo) if err != nil { log.Fatal(err) } return t } }() err := t.AddPeers(func() (ret []torrent.Peer) { for _, ta := range opts.TestPeer { ret = append(ret, torrent.Peer{ IP: ta.IP, Port: ta.Port, }) } return }()) if err != nil { log.Fatal(err) } go func() { <-t.GotInfo() t.DownloadAll() }() } done := make(chan struct{}) go func() { defer close(done) if client.WaitAll() { log.Print("downloaded ALL the torrents") } else { log.Fatal("y u no complete torrents?!") } }() ticker := time.NewTicker(time.Second) waitDone: for { select { case <-done: break waitDone case <-ticker.C: os.Stdout.WriteString(progressLine(client)) } } if opts.Seed { select {} } }