downloader: handle race between adding magnet link and files from webseed (#9045)

This commit is contained in:
Alex Sharov 2023-12-21 10:59:26 +07:00 committed by GitHub
parent 8c822256db
commit 56c5f656d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 20 deletions

View File

@ -582,7 +582,7 @@ func (d *Downloader) AddNewSeedableFile(ctx context.Context, name string) error
if err != nil {
return fmt.Errorf("AddNewSeedableFile: %w", err)
}
err = addTorrentFile(ctx, ts, d.torrentClient, d.webseeds)
_, _, err = addTorrentFile(ctx, ts, d.torrentClient, d.webseeds)
if err != nil {
return fmt.Errorf("addTorrentFile: %w", err)
}
@ -619,11 +619,13 @@ func (d *Downloader) AddMagnetLink(ctx context.Context, infoHash metainfo.Hash,
if err != nil {
return err
}
spec.DisallowDataDownload = true
t, _, err := d.torrentClient.AddTorrentSpec(spec)
t, ok, err := addTorrentFile(ctx, spec, d.torrentClient, d.webseeds)
if err != nil {
return err
}
if !ok {
return nil
}
d.wg.Add(1)
go func(t *torrent.Torrent) {
defer d.wg.Done()
@ -672,7 +674,7 @@ func (d *Downloader) addTorrentFilesFromDisk(quiet bool) error {
return err
}
for i, ts := range files {
err := addTorrentFile(d.ctx, ts, d.torrentClient, d.webseeds)
_, _, err := addTorrentFile(d.ctx, ts, d.torrentClient, d.webseeds)
if err != nil {
return err
}

View File

@ -306,29 +306,56 @@ func loadTorrent(torrentFilePath string) (*torrent.TorrentSpec, error) {
// added first time - pieces verification process will start (disk IO heavy) - Progress
// kept in `piece completion storage` (surviving reboot). Once it done - no disk IO needed again.
// Don't need call torrent.VerifyData manually
func addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) error {
func addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) (t *torrent.Torrent, ok bool, err error) {
ts.ChunkSize = downloadercfg.DefaultNetworkChunkSize
ts.DisallowDataDownload = true
ts.DisableInitialPieceCheck = true
//re-try on panic, with 0 ChunkSize (lib doesn't allow change this field for existing torrents)
defer func() {
rec := recover()
if rec != nil {
ts.ChunkSize = 0
t, ok, err = _addTorrentFile(ctx, ts, torrentClient, webseeds)
}
}()
t, ok, err = _addTorrentFile(ctx, ts, torrentClient, webseeds)
if err != nil {
ts.ChunkSize = 0
return _addTorrentFile(ctx, ts, torrentClient, webseeds)
}
return t, ok, err
}
func _addTorrentFile(ctx context.Context, ts *torrent.TorrentSpec, torrentClient *torrent.Client, webseeds *WebSeeds) (t *torrent.Torrent, ok bool, err error) {
select {
case <-ctx.Done():
return ctx.Err()
return nil, false, ctx.Err()
default:
}
wsUrls, ok := webseeds.ByFileName(ts.DisplayName)
if ok {
ts.Webseeds = append(ts.Webseeds, wsUrls...)
ts.Webseeds, _ = webseeds.ByFileName(ts.DisplayName)
var have bool
t, have = torrentClient.Torrent(ts.InfoHash)
if !have {
t, _, err := torrentClient.AddTorrentSpec(ts)
if err != nil {
return nil, false, fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err)
}
return t, true, nil
}
_, ok = torrentClient.Torrent(ts.InfoHash)
if !ok { // can set ChunkSize only for new torrents
ts.ChunkSize = downloadercfg.DefaultNetworkChunkSize
} else {
ts.ChunkSize = 0
select {
case <-t.GotInfo():
t.AddWebSeeds(ts.Webseeds)
default:
t, _, err = torrentClient.AddTorrentSpec(ts)
if err != nil {
return nil, false, fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err)
}
}
ts.DisallowDataDownload = true
_, _, err := torrentClient.AddTorrentSpec(ts)
if err != nil {
return fmt.Errorf("addTorrentFile %s: %w", ts.DisplayName, err)
}
return nil
return t, true, nil
}
func savePeerID(db kv.RwDB, peerID torrent.PeerID) error {