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