mafintosh / torrent-stream

The low level streaming torrent engine that peerflix uses
MIT License
1.94k stars 227 forks source link

pause download #138

Open williamoliveira opened 8 years ago

williamoliveira commented 8 years ago

Is there a way to pause the download but leave the rest running?

garethdn commented 8 years ago

I am wondering the same thing, although I don't know what "leave the rest running" means in this context.

I'm trying to manually pause the stream after 60 seconds and resume the stream after a further 30 seconds but pieces of the file continue to be downloaded.

I'm very new to node but I believe that pipe would end up automatically pausing and resuming the stream itself depending on how saturated the write stream is...I think.

This is the code I'm using to attempt to pause the stream. I'm probably including more code here than is required but I think the context helps and the steps below are quite straight forward to follow.

Any help would be appreciated.

app.use('/play-torrent/:torrentIdentifier', function(req, res, next) {
    console.log('Getting torrent engine......');

    var engine = torrentStream(req.params.torrentIdentifier);
    var maxBuffer = 5000000000; //5000MB

    engine.on('ready', function() {
      console.log('Engine ready!');

      var mp4Files = _.filter(engine.files, function(file){
        return _.last(file.name.split('.')) === 'mp4';
      });

      var file = _.chain(mp4Files).sortBy('-length').value()[0];

      var range = req.headers.range;
      var positions = range.replace(/bytes=/, "").split("-");
      var start = parseInt(positions[0], 10);

      var total = file.length;
      var end = positions[1] ? parseInt(positions[1], 10) : (start + maxBuffer) > (total - 1) ? (total - 1) : (start + maxBuffer);
      var chunksize = (end - start) + 1;

      var stream = file.createReadStream({ start: start, end: end });

      stream.on('error', function(err) {
        console.log('Stream error', err);
        res.end(err);
      });

      stream.on('end', function() {
        console.log('Stream ended');
      });

      stream.on('close', function() {
        console.log('Stream closed');
      });

      stream.on('data', function(buffer) {
        console.log('Got data from torrent stream', buffer.length);
      });

      write206Headers(res, start, end, total, chunksize);

      stream.pipe(res);

      setTimeout(function(){ 
        console.log('60 SECONDS GONE - pausing stream');

        // Neither of these seem to work - `download` event on engine continues to be triggered
        stream.pause();
        // engine.swarm.pause();
      }, 60000);

      setTimeout(function(){ 
        console.log('90 SECONDS GONE - resuming stream');
        stream.resume();
        // engine.swarm.resume();
      }, 90000);
    });

    engine.on('download', function(pieceIndex, buffer){
      // Continues to trigger after stream is paused
      console.log('Piece downloaded with index: ', pieceIndex);
    });

  });
asapach commented 8 years ago

T-s will keep downloading as long as there are pieces selected. file.createReadStream() selects all the pieces in the file/range (here). You can try deselecting the pieces you don't need, but that might lead to unexpected results.

garethdn commented 8 years ago

@asapach Right, that makes perfect sense actually - thanks.

On a related issue then, if I was to reduce my max buffer to around 10MB and make multiple requests from the client for 10MB chunks should I be storing the engine instance instead of creating a new one for the same torrent each time? I'm assuming that each time I call torrentStream(req.params.torrentIdentifier) that I need to find and reconnect to all the peers again - or is this already handled in the t-s internals?

asapach commented 8 years ago

You should definitely keep the instance, since it's a fairly expensive operation to connect to the swarm and fetch all the metadata.

garethdn commented 8 years ago

@asapach Good to know, I appreciate the help. I was going to bring this up in the the gitter page but it doesn't look like it's active.