func blockingRead(ctx context.Context, fs *TorrentFS, t *torrent.Torrent, off int64, p []byte) (n int, err error) {
	fs.mu.Lock()
	fs.blockedReads++
	fs.event.Broadcast()
	fs.mu.Unlock()
	var (
		_n   int
		_err error
	)
	readDone := make(chan struct{})
	go func() {
		defer close(readDone)
		r := t.NewReader()
		defer r.Close()
		_, _err = r.Seek(off, os.SEEK_SET)
		if _err != nil {
			return
		}
		_n, _err = io.ReadFull(r, p)
	}()
	select {
	case <-readDone:
		n = _n
		err = _err
	case <-fs.destroyed:
		err = fuse.EIO
	case <-ctx.Done():
		err = fuse.EINTR
	}
	fs.mu.Lock()
	fs.blockedReads--
	fs.event.Broadcast()
	fs.mu.Unlock()
	return
}
func blockingRead(ctx context.Context, fs *TorrentFS, t torrent.Torrent, off int64, p []byte) (n int, err error) {
	fs.mu.Lock()
	fs.blockedReads++
	fs.event.Broadcast()
	fs.mu.Unlock()
	var (
		_n   int
		_err error
	)
	readDone := make(chan struct{})
	go func() {
		r := t.NewReader()
		defer r.Close()
		_n, _err = r.ReadAt(p, off)
		close(readDone)
	}()
	select {
	case <-readDone:
		n = _n
		err = _err
	case <-fs.destroyed:
		err = fuse.EIO
	case <-ctx.Done():
		err = fuse.EINTR
	}
	fs.mu.Lock()
	fs.blockedReads--
	fs.event.Broadcast()
	fs.mu.Unlock()
	return
}
Exemple #3
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.
		for i := 0; i < len(t.Pieces)/100*5; i++ {
			t.Pieces[i].Priority = torrent.PiecePriorityReadahead
		}
	}()

	return
}
Exemple #4
0
func (torrent *Torrent) Update(t *torrent.Torrent) {
	torrent.Name = t.Name()
	torrent.Loaded = t.Info() != nil
	if torrent.Loaded {
		torrent.Size = t.Length()
	}

	totalChunks := 0
	totalCompleted := 0

	tfiles := t.Files()
	if len(tfiles) > 0 && torrent.Files == nil {
		torrent.Files = make([]*File, len(tfiles))
	}
	//merge in files
	for i, f := range tfiles {
		path := f.Path()
		file := torrent.Files[i]
		if file == nil {
			file = &File{Path: path}
			torrent.Files[i] = file
		}
		chunks := f.State()

		file.Size = f.Length()
		file.Chunks = len(chunks)
		completed := 0
		for _, p := range chunks {
			if p.Complete {
				completed++
			}
		}
		file.Completed = completed
		file.Percent = percent(int64(file.Completed), int64(file.Chunks))
		file.f = f

		totalChunks += file.Chunks
		totalCompleted += file.Completed
	}

	//cacluate rate
	now := time.Now()
	bytes := t.BytesCompleted()
	torrent.Percent = percent(bytes, torrent.Size)
	if !torrent.updatedAt.IsZero() {
		dt := float32(now.Sub(torrent.updatedAt))
		db := float32(bytes - torrent.Downloaded)
		rate := db * (float32(time.Second) / dt)
		if rate >= 0 {
			torrent.DownloadRate = rate
		}
	}
	torrent.Downloaded = bytes
	torrent.updatedAt = now
	torrent.t = t
}
Exemple #5
0
func (e *Engine) upsertTorrent(tt torrent.Torrent) *Torrent {
	ih := tt.InfoHash().HexString()
	torrent, ok := e.ts[ih]
	if !ok {
		torrent = &Torrent{InfoHash: ih}
		e.ts[ih] = torrent
	}
	//update torrent fields using underlying torrent
	torrent.Update(tt)
	return torrent
}
Exemple #6
0
func Example_fileReader() {
	var (
		t torrent.Torrent
		f torrent.File
	)
	r := t.NewReader()
	defer r.Close()
	// Access the parts of the torrent pertaining to f. Data will be
	// downloaded as required, per the configuration of the torrent.Reader.
	_ = missinggo.NewSectionReadSeeker(r, f.Offset(), f.Length())
}
Exemple #7
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 #8
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 #9
0
func (c *Client) NewTorrent(torrentPath string) (error, chan bool) {
	c.DropTorrent()
	c.Ready = false
	c.TorrentPath = torrentPath

	readyChan := make(chan bool)

	var t *torrent.Torrent
	client := c.Client

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

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

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

	go func() {
		// Wait for the torrent info and start to download immediately
		<-t.GotInfo()

		c.Ready = true

		// Publish torrent info
		readyChan <- true
	}()

	return nil, readyChan
}
Exemple #10
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, tcp 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,
		DisableTCP: !tcp,
	})

	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 #11
0
func torrentBar(t *torrent.Torrent) {
	bar := uiprogress.AddBar(1)
	bar.AppendCompleted()
	bar.AppendFunc(func(*uiprogress.Bar) (ret string) {
		select {
		case <-t.GotInfo():
		default:
			return "getting info"
		}
		if t.Seeding() {
			return "seeding"
		} else if t.BytesCompleted() == t.Info().TotalLength() {
			return "completed"
		} else {
			return fmt.Sprintf("downloading (%s/%s)", humanize.Bytes(uint64(t.BytesCompleted())), humanize.Bytes(uint64(t.Info().TotalLength())))
		}
	})
	bar.PrependFunc(func(*uiprogress.Bar) string {
		return t.Name()
	})
	go func() {
		<-t.GotInfo()
		bar.Total = int(t.Info().TotalLength())
		for {
			bc := t.BytesCompleted()
			bar.Set(int(bc))
			time.Sleep(time.Second)
		}
	}()
}
Exemple #12
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
	}
}