func TestDownloadOnDemand(t *testing.T) {
	layout, err := newGreetingLayout()
	require.NoError(t, err)
	defer layout.Destroy()
	seeder, err := torrent.NewClient(&torrent.Config{
		DataDir:         layout.Completed,
		DisableTrackers: true,
		NoDHT:           true,
		ListenAddr:      "localhost:0",
		Seed:            true,
		// Ensure that the metainfo is obtained over the wire, since we added
		// the torrent to the seeder by magnet.
		DisableMetainfoCache: true,
	})
	require.NoError(t, err)
	defer seeder.Close()
	testutil.ExportStatusWriter(seeder, "s")
	_, err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.Info.Hash.HexString()))
	require.NoError(t, err)
	leecher, err := torrent.NewClient(&torrent.Config{
		DisableTrackers: true,
		NoDHT:           true,
		ListenAddr:      "localhost:0",
		DisableTCP:      true,
		DefaultStorage:  storage.NewMMap(filepath.Join(layout.BaseDir, "download")),
		// This can be used to check if clients can connect to other clients
		// with the same ID.
		// PeerID: seeder.PeerID(),
	})
	require.NoError(t, err)
	testutil.ExportStatusWriter(leecher, "l")
	defer leecher.Close()
	leecherTorrent, _ := leecher.AddTorrent(layout.Metainfo)
	leecherTorrent.AddPeers([]torrent.Peer{
		torrent.Peer{
			IP:   missinggo.AddrIP(seeder.ListenAddr()),
			Port: missinggo.AddrPort(seeder.ListenAddr()),
		},
	})
	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)
	assert.EqualValues(t, testutil.GreetingFileContents, resp.Data)
}
Exemple #2
0
func (e *Engine) Configure(c Config) error {
	//recieve config
	if e.client != nil {
		e.client.Close()
	}
	tc := torrent.Config{
		DataDir:   c.DownloadDirectory,
		ConfigDir: filepath.Join(c.DownloadDirectory, ".config"),
		NoUpload:  !c.EnableUpload,
		Seed:      c.EnableSeeding,
	}
	client, err := torrent.NewClient(&tc)
	if err != nil {
		return err
	}
	e.mut.Lock()
	e.cacheDir = filepath.Join(tc.ConfigDir, "torrents")
	if files, err := ioutil.ReadDir(e.cacheDir); err == nil {
		for _, f := range files {
			if filepath.Ext(f.Name()) != ".torrent" {
				continue
			}
			tt, err := client.AddTorrentFromFile(filepath.Join(e.cacheDir, f.Name()))
			if err == nil {
				e.upsertTorrent(tt)
			}
		}
	}
	e.config = c
	e.client = client
	e.mut.Unlock()
	//reset
	e.GetTorrents()
	return nil
}
Exemple #3
0
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 {}
	}
}
Exemple #4
0
func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	tagflag.Parse(&flags)
	var clientConfig torrent.Config
	if flags.Mmap {
		clientConfig.DefaultStorage = storage.NewMMap("")
	}
	if flags.Addr != nil {
		clientConfig.ListenAddr = flags.Addr.String()
	}

	client, err := torrent.NewClient(&clientConfig)
	if err != nil {
		log.Fatalf("error creating client: %s", err)
	}
	defer client.Close()
	// Write status on the root path on the default HTTP muxer. This will be
	// bound to localhost somewhere if GOPPROF is set, thanks to the envpprof
	// import.
	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 flags.Seed {
		select {}
	}
}
Exemple #5
0
func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	tagflag.Parse(&opts, tagflag.SkipBadTypes())
	clientConfig := opts.Config
	if opts.Mmap {
		clientConfig.DefaultStorage = storage.NewMMap("")
	}

	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 {}
	}
}
Exemple #6
0
// NewClient creates a new torrent client based on a magnet or a torrent file.
// If the torrent file is on http, we try downloading it.
func NewClient(torrentPath string, port int, seed bool) (client Client, err error) {
	var t torrent.Torrent
	var c *torrent.Client

	client.Port = port

	// Create client.
	c, err = torrent.NewClient(&torrent.Config{
		DataDir:  os.TempDir(),
		NoUpload: !seed,
		Seed:     seed,
	})

	if err != nil {
		return client, ClientError{Type: "creating torrent client", Origin: err}
	}

	client.Client = c

	// Add torrent.

	// Add as magnet url.
	if strings.HasPrefix(torrentPath, "magnet:") {
		if t, err = c.AddMagnet(torrentPath); err != nil {
			return client, ClientError{Type: "adding torrent", Origin: err}
		}
	} else {
		// Otherwise add as a torrent file.

		// If it's online, we try downloading the file.
		if isHTTP.MatchString(torrentPath) {
			if torrentPath, err = downloadFile(torrentPath); err != nil {
				return client, ClientError{Type: "downloading torrent file", Origin: err}
			}
		}

		// Check if the file exists.
		if _, err = os.Stat(torrentPath); err != nil {
			return client, ClientError{Type: "file not found", Origin: err}
		}

		if t, err = c.AddTorrentFromFile(torrentPath); err != nil {
			return client, ClientError{Type: "adding torrent to the client", Origin: err}
		}
	}

	client.Torrent = t

	go func() {
		<-t.GotInfo()
		t.DownloadAll()

		// Prioritize first 5% of the file.
		client.getLargestFile().PrioritizeRegion(0, int64(t.NumPieces()/100*5))
	}()

	go client.addBlocklist()

	return
}
Exemple #7
0
func New(uri string) (*Downloader, string, error) {
	var err error

	var id string
	var client *torrent.Client
	var downloader = &Downloader{}

	id = utils.CalcMd5(uri)

	downloader.Id = id

	client, err = torrent.NewClient(&torrent.Config{
		DataDir:  filepath.Join(os.TempDir(), "gochromecast"),
		NoUpload: true,
		Seed:     true,
	})

	if err != nil {
		return downloader, id, errors.New(
			errors.DOWNLOADER_CANNOT_CREATE_TCLIENT_CODE,
			errors.DOWNLOADER_CANNOT_CREATE_TCLIENT_MESSAGE,
			err,
		)
	}
	downloader.Client = client
	return downloader, id, nil
}
Exemple #8
0
func main() {
	flag.Parse()
	cl, err := torrent.NewClient(nil)
	if err != nil {
		log.Fatalf("error creating client: %s", err)
	}
	wg := sync.WaitGroup{}
	for _, arg := range flag.Args() {
		t, err := cl.AddMagnet(arg)
		if err != nil {
			log.Fatalf("error adding magnet to client: %s", err)
		}
		wg.Add(1)
		go func() {
			defer wg.Done()
			<-t.GotInfo()
			mi := t.Metainfo()
			t.Drop()
			f, err := os.Create(mi.Info.Name + ".torrent")
			if err != nil {
				log.Fatalf("error creating torrent metainfo file: %s", err)
			}
			defer f.Close()
			err = bencode.NewEncoder(f).Encode(mi)
			if err != nil {
				log.Fatalf("error writing torrent metainfo file: %s", err)
			}
		}()
	}
	wg.Wait()
}
Exemple #9
0
// NewClient creates a new torrent client based on a magnet or a torrent file.
// If the torrent file is on http, we try downloading it.
func NewClient(cfg ClientConfig) (client Client, err error) {
	var t *torrent.Torrent
	var c *torrent.Client

	client.Config = cfg

	// Create client.
	c, err = torrent.NewClient(&torrent.Config{
		DataDir:    os.TempDir(),
		NoUpload:   !cfg.Seed,
		Seed:       cfg.Seed,
		DisableTCP: !cfg.TCP,
		ListenAddr: fmt.Sprintf(":%d", cfg.TorrentPort),
	})

	if err != nil {
		return client, ClientError{Type: "creating torrent client", Origin: err}
	}

	client.Client = c

	// Add torrent.

	// Add as magnet url.
	if strings.HasPrefix(cfg.TorrentPath, "magnet:") {
		if t, err = c.AddMagnet(cfg.TorrentPath); err != nil {
			return client, ClientError{Type: "adding torrent", Origin: err}
		}
	} else {
		// Otherwise add as a torrent file.

		// If it's online, we try downloading the file.
		if isHTTP.MatchString(cfg.TorrentPath) {
			if cfg.TorrentPath, err = downloadFile(cfg.TorrentPath); err != nil {
				return client, ClientError{Type: "downloading torrent file", Origin: err}
			}
		}

		if t, err = c.AddTorrentFromFile(cfg.TorrentPath); err != nil {
			return client, ClientError{Type: "adding torrent to the client", Origin: err}
		}
	}

	client.Torrent = t
	client.Torrent.SetMaxEstablishedConns(cfg.MaxConnections)

	go func() {
		<-t.GotInfo()
		t.DownloadAll()

		// Prioritize first 5% of the file.
		client.getLargestFile().PrioritizeRegion(0, int64(t.NumPieces()/100*5))
	}()

	go client.addBlocklist()

	return
}
Exemple #10
0
func Example() {
	c, _ := torrent.NewClient(nil)
	defer c.Close()
	t, _ := c.AddMagnet("magnet:?xt=urn:btih:ZOCMZQIPFFW7OLLMIC5HUB6BPCSDEOQU")
	<-t.GotInfo()
	t.DownloadAll()
	c.WaitAll()
	log.Print("ermahgerd, torrent downloaded")
}
Exemple #11
0
// NewClient creates a new torrent client based on a magnet or a torrent file.
// If the torrent file is on http, we try downloading it.
func NewClient(torrentPath string) (client Client, err error) {
	var t torrent.Torrent
	var c *torrent.Client

	// Create client.
	c, err = torrent.NewClient(&torrent.Config{
		DataDir:  os.TempDir(),
		NoUpload: !(*seed),
	})

	if err != nil {
		return client, ClientError{Type: "creating torrent client", Origin: err}
	}

	client.Client = c

	// Add torrent.

	// Add as magnet url.
	if strings.HasPrefix(torrentPath, "magnet:") {
		if t, err = c.AddMagnet(torrentPath); err != nil {
			return client, ClientError{Type: "adding torrent", Origin: err}
		}
	} else {
		// Otherwise add as a torrent file.

		// If it's online, we try downloading the file.
		if isHTTP.MatchString(torrentPath) {
			if torrentPath, err = downloadFile(torrentPath); err != nil {
				return client, ClientError{Type: "downloading torrent file", Origin: err}
			}
		}

		// Check if the file exists.
		if _, err = os.Stat(torrentPath); err != nil {
			return client, ClientError{Type: "file not found", Origin: err}
		}

		if t, err = c.AddTorrentFromFile(torrentPath); err != nil {
			return client, ClientError{Type: "adding torrent to the client", Origin: err}
		}
	}

	client.Torrent = t

	go func() {
		<-t.GotInfo()
		t.DownloadAll()
	}()

	return
}
Exemple #12
0
func (n *Native) SetConfig(obj interface{}) error {
	//recieve config
	c, ok := obj.(*config)
	if !ok {
		return fmt.Errorf("Invalid config")
	}

	client, err := torrent.NewClient(&c.Config)
	if err != nil {
		return err
	}
	n.client = client
	return nil
}
Exemple #13
0
func NewClient(downloadFolder string) (*Client, error) {
	client, err := torrent.NewClient(&torrent.Config{
		DataDir:    downloadFolder,
		NoUpload:   false,
		Seed:       true,
		DisableTCP: false,
	})
	if err != nil {
		return nil, ClientError{Type: "creating torrent client", Origin: err}
	}

	return &Client{
		Client:         client,
		downloadFolder: downloadFolder,
	}, nil
}
Exemple #14
0
func NewBuiltin(dataDir string) (builtin *Builtin, err error) {
	cfg := &torrent.Config{
		DataDir: dataDir,
		Seed:    true,
		NoDHT:   true,
	}

	client, err := torrent.NewClient(cfg)
	if err != nil {
		return
	}

	builtin = &Builtin{
		Client: client,
	}
	return
}
Exemple #15
0
func (e *Engine) Configure(c Config) error {
	//recieve config
	if e.client != nil {
		e.client.Close()
		time.Sleep(1 * time.Second)
	}
	if c.IncomingPort <= 0 {
		return fmt.Errorf("Invalid incoming port (%d)", c.IncomingPort)
	}
	tc := torrent.Config{
		DataDir:           c.DownloadDirectory,
		ListenAddr:        "0.0.0.0:" + strconv.Itoa(c.IncomingPort),
		NoUpload:          !c.EnableUpload,
		Seed:              c.EnableSeeding,
		DisableEncryption: c.DisableEncryption,
	}
	client, err := torrent.NewClient(&tc)
	if err != nil {
		return err
	}
	e.mut.Lock()
	e.cacheDir = filepath.Join(c.DownloadDirectory, ".config", "magnets")
	os.MkdirAll(e.cacheDir, 0777)
	if files, err := ioutil.ReadDir(e.cacheDir); err == nil {
		for _, f := range files {
			if filepath.Ext(f.Name()) != ".magnet" {
				continue
			}

			b, err := ioutil.ReadFile(filepath.Join(e.cacheDir, f.Name()))
			if err == nil {
				tt, err := client.AddMagnet(string(b[:]))
				if err == nil {
					e.upsertTorrent(tt)
				}
			}
		}
	}
	e.config = c
	e.client = client
	e.mut.Unlock()
	//reset
	e.GetTorrents()
	return nil
}
Exemple #16
0
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)
	}
}
Exemple #17
0
func main() {
	flag.Parse()
	if flag.NArg() != 0 {
		os.Stderr.WriteString("one does not simply pass positional args\n")
		os.Exit(2)
	}
	if *mountDir == "" {
		os.Stderr.WriteString("y u no specify mountpoint?\n")
		os.Exit(2)
	}
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	conn, err := fuse.Mount(*mountDir)
	if err != nil {
		log.Fatal(err)
	}
	defer fuse.Unmount(*mountDir)
	// TODO: Think about the ramifications of exiting not due to a signal.
	defer conn.Close()
	client, err := torrent.NewClient(&torrent.Config{
		DataDir:         *downloadDir,
		DisableTrackers: *disableTrackers,
		ListenAddr:      *listenAddr,
		NoUpload:        true, // Ensure that downloads are responsive.
	})
	if err != nil {
		log.Fatal(err)
	}
	// This is naturally exported via GOPPROF=http.
	http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		client.WriteStatus(w)
	})
	dw, err := dirwatch.New(*torrentPath)
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		for ev := range dw.Events {
			switch ev.Change {
			case dirwatch.Added:
				if ev.TorrentFilePath != "" {
					_, err := client.AddTorrentFromFile(ev.TorrentFilePath)
					if err != nil {
						log.Printf("error adding torrent to client: %s", err)
					}
				} else if ev.MagnetURI != "" {
					_, err := client.AddMagnet(ev.MagnetURI)
					if err != nil {
						log.Printf("error adding magnet: %s", err)
					}
				}
			case dirwatch.Removed:
				T, ok := client.Torrent(ev.InfoHash)
				if !ok {
					break
				}
				T.Drop()
			}
		}
	}()
	resolveTestPeerAddr()
	fs := torrentfs.New(client)
	go exitSignalHandlers(fs)
	go func() {
		for {
			addTestPeer(client)
			time.Sleep(10 * time.Second)
		}
	}()

	if err := fusefs.Serve(conn, fs); err != nil {
		log.Fatal(err)
	}
	<-conn.Ready
	if err := conn.MountError; err != nil {
		log.Fatal(err)
	}
}
Exemple #18
0
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 {}
	}
}
Exemple #19
0
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"`
		Pick      string         `long:"pick" description:"filename to pick"`
	}
	// 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.\n")
		fmt.Println(err)
		os.Exit(2)
	}
	log.Printf("File to pick: %s", rootGroup.Pick)

	testPeers, err := resolvedPeerAddrs(rootGroup.TestPeers)
	if err != nil {
		log.Fatal(err)
	}

	if len(posArgs) == 0 {
		fmt.Fprintln(os.Stderr, "no torrents specified")
		return
	}

	tmpdir, err := ioutil.TempDir("", "torrent-pick-")
	if err != nil {
		log.Fatal(err)
	}

	defer os.RemoveAll(tmpdir)

	rootGroup.Client.DataDir = tmpdir

	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()

	dstName := dstFileName(rootGroup.Pick)

	f, err := os.Create(dstName)
	if err != nil {
		log.Fatal(err)
	}
	dstWriter := bufio.NewWriter(f)

	done := make(chan struct{})
	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() {
			defer close(done)
			<-t.GotInfo()
			for _, file := range t.Files() {
				if file.DisplayPath() != rootGroup.Pick {
					continue
				}
				srcReader := io.NewSectionReader(t.NewReader(), file.Offset(), file.Length())
				io.Copy(dstWriter, srcReader)
				return
			}
			log.Print("file not found")
		}()
	}

	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 {}
	}
}
Exemple #20
0
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 {}
	}
}
Exemple #21
0
// Unmount without first killing the FUSE connection while there are FUSE
// operations blocked inside the filesystem code.
func TestUnmountWedged(t *testing.T) {
	layout, err := newGreetingLayout()
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := layout.Destroy()
		if err != nil {
			t.Log(err)
		}
	}()
	client, err := torrent.NewClient(&torrent.Config{
		DataDir:         filepath.Join(layout.BaseDir, "incomplete"),
		DisableTrackers: true,
		NoDHT:           true,
		ListenAddr:      "redonk",
		DisableTCP:      true,
		DisableUTP:      true,

		NoDefaultBlocklist: true,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()
	client.AddTorrent(layout.Metainfo)
	fs := New(client)
	fuseConn, err := fuse.Mount(layout.MountDir)
	if err != nil {
		msg := fmt.Sprintf("error mounting: %s", err)
		if strings.Contains(err.Error(), "fuse") || err.Error() == "exit status 71" {
			t.Skip(msg)
		}
		t.Fatal(msg)
	}
	go func() {
		server := fusefs.New(fuseConn, &fusefs.Config{
			Debug: func(msg interface{}) {
				t.Log(msg)
			},
		})
		server.Serve(fs)
	}()
	<-fuseConn.Ready
	if err := fuseConn.MountError; err != nil {
		t.Fatalf("mount error: %s", err)
	}
	// Read the greeting file, though it will never be available. This should
	// "wedge" FUSE, requiring the fs object to be forcibly destroyed. The
	// read call will return with a FS error.
	go func() {
		_, err := ioutil.ReadFile(filepath.Join(layout.MountDir, layout.Metainfo.Info.Name))
		if err == nil {
			t.Fatal("expected error reading greeting")
		}
	}()

	// Wait until the read has blocked inside the filesystem code.
	fs.mu.Lock()
	for fs.blockedReads != 1 {
		fs.event.Wait()
	}
	fs.mu.Unlock()

	fs.Destroy()

	for {
		err = fuse.Unmount(layout.MountDir)
		if err != nil {
			t.Logf("error unmounting: %s", err)
			time.Sleep(time.Millisecond)
		} else {
			break
		}
	}

	err = fuseConn.Close()
	if err != nil {
		t.Fatalf("error closing fuse conn: %s", err)
	}
}
func Start() torrent.Client {
	client, err := torrent.NewClient(nil)
	util.CheckError(err)
	return *client
}
Exemple #23
0
// Add Torrent/Magnet
func add(w http.ResponseWriter, r *http.Request) {
	c := Add{}
	if e := json.NewDecoder(r.Body).Decode(&c); e != nil {
		httpd.Error(w, e, "Invalid input.")
		return
	}
	if c.User == "" {
		httpd.Error(w, nil, "No user.")
		return
	}
	if c.Dir == "" {
		httpd.Error(w, nil, "No dir.")
		return
	}
	if strings.Contains(c.Dir, "..") {
		httpd.Error(w, nil, "Dir hack.")
		return
	}

	if _, ok := clients[c.User]; !ok {
		dlDir := fmt.Sprintf(config.C.Basedir + c.Dir)
		if _, e := os.Stat(config.C.Basedir); os.IsNotExist(e) {
			if e := os.Mkdir(dlDir, os.ModeDir); e != nil {
				config.L.Printf("CRIT: %s", e.Error())
				httpd.Error(w, e, "Permission error.")
				return
			}
		}

		// https://github.com/anacrolix/torrent/blob/master/config.go#L9
		cl, e := torrent.NewClient(&torrent.Config{
			DataDir: config.C.Basedir + c.Dir,
			// IPBlocklist => http://john.bitsurge.net/public/biglist.p2p.gz
		})
		if e != nil {
			httpd.Error(w, e, "Client init failed")
			return
		}
		clients[c.User] = cl
	}

	client := clients[c.User]
	var (
		t torrent.Torrent
		e error
	)
	if len(c.Magnet) > 0 {
		t, e = client.AddMagnet(c.Magnet)
		if e != nil {
			httpd.Error(w, e, "Magnet add failed")
			return
		}
	} else if len(c.Torrent) > 0 {
		// strip base64
		b, e := base64.StdEncoding.DecodeString(c.Torrent)
		if e != nil {
			httpd.Error(w, e, "Failed base64 decode torrent input")
			return
		}
		m, e := metainfo.Load(bytes.NewReader(b))
		if e != nil {
			httpd.Error(w, e, "Failed base64 decode torrent input")
			return
		}
		t, e = client.AddTorrent(m)
		if e != nil {
			httpd.Error(w, e, "Failed adding torrent")
			return
		}
	} else {
		httpd.Error(w, nil, "No magnet nor torrent.")
		return
	}

	// queue
	go func() {
		<-t.GotInfo()
		t.DownloadAll()
	}()

	// (cl *Client) AddTorrentSpec(spec *TorrentSpec) (T Torrent, new bool, err error) {
	// TorrentSpecFromMagnetURI(uri string) (spec *TorrentSpec, err error) {
	// TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) (spec *TorrentSpec) {
	// (me *Client) AddMagnet(uri string) (T Torrent, err error) {
	// (me *Client) AddTorrent(mi *metainfo.MetaInfo) (T Torrent, err error) {

	msg := fmt.Sprintf(`{"status": true, "hash": "%s", "text": "Queued."}`, t.InfoHash().HexString())
	w.Header().Set("Content-Type", "application/json")
	if _, e := w.Write([]byte(msg)); e != nil {
		httpd.Error(w, e, "Flush failed")
		return
	}
}