class QuartzTorrent::PeerClient
Represents a client that talks to bittorrent peers. This is the main class used to download and upload bittorrents.
Attributes
Set the port used by the torrent peer client. This only has an effect if start has not yet been called.
Public Class Methods
Create a new PeerClient
that will save and load torrent data under the specified baseDirectory.
# File lib/quartz_torrent/peerclient.rb, line 1724 def initialize(baseDirectory, maxIncomplete = 5, maxActive = 10) @port = 9998 @handler = nil @stopped = true @reactor = nil @logger = LogManager.getLogger("peerclient") @worker = nil @handler = PeerClientHandler.new baseDirectory, maxIncomplete, maxActive @reactor = QuartzTorrent::Reactor.new(@handler, LogManager.getLogger("peerclient.reactor")) @toStart = [] end
Public Instance Methods
Add a new torrent to manage given a MagnetURI
object. This is generally the method to call if you have a magnet link. Returns the infoHash of the newly added torrent.
# File lib/quartz_torrent/peerclient.rb, line 1796 def addTorrentByMagnetURI(magnet) raise "addTorrentByMagnetURI should be called with a MagnetURI object, not a #{magnet.class}" if ! magnet.is_a?(MagnetURI) trackerUrl = magnet.trackers raise "addTorrentByMagnetURI can't handle magnet links that don't have a tracker URL." if !trackerUrl addTorrentWithoutMetainfo(trackerUrl, magnet.btInfoHash, magnet) end
Add a new torrent to manage described by a Metainfo
object. This is generally the method to call if you have a .torrent file. Returns the infoHash of the newly added torrent.
# File lib/quartz_torrent/peerclient.rb, line 1779 def addTorrentByMetainfo(metainfo) raise "addTorrentByMetainfo should be called with a Metainfo object, not #{metainfo.class}" if ! metainfo.is_a?(Metainfo) trackerclient = TrackerClient.createFromMetainfo(metainfo, false) addTorrent(trackerclient, metainfo.infoHash, metainfo.info) end
Add a new torrent to manage given an announceUrl and an infoHash. The announceUrl may be a list. Returns the infoHash of the newly added torrent.
# File lib/quartz_torrent/peerclient.rb, line 1787 def addTorrentWithoutMetainfo(announceUrl, infoHash, magnet = nil) raise "addTorrentWithoutMetainfo should be called with a Magnet object, not a #{magnet.class}" if magnet && ! magnet.is_a?(MagnetURI) trackerclient = TrackerClient.create(announceUrl, infoHash, 0, false) addTorrent(trackerclient, infoHash, nil, magnet) end
Adjust the bytesDownloaded property of the specified torrent by the passed amount. Adjustment should be an integer. It is added to the current bytesUploaded amount.
# File lib/quartz_torrent/peerclient.rb, line 1853 def adjustBytesDownloaded(infoHash, adjustment) return if ! adjustment raise "Bytes downloaded adjustment must be an Integer, not a #{adjustment.class}" if !adjustment.is_a?(Integer) @handler.adjustBytesDownloaded(infoHash, adjustment) end
Adjust the bytesUploaded property of the specified torrent by the passed amount. Adjustment should be an integer. It is added to the current bytesUploaded amount.
# File lib/quartz_torrent/peerclient.rb, line 1845 def adjustBytesUploaded(infoHash, adjustment) return if ! adjustment raise "Bytes uploaded adjustment must be an Integer, not a #{adjustment.class}" if !adjustment.is_a?(Integer) @handler.adjustBytesUploaded(infoHash, adjustment) end
Remove a currently running torrent
# File lib/quartz_torrent/peerclient.rb, line 1860 def removeTorrent(infoHash, deleteFiles = false) @handler.removeTorrent(infoHash, deleteFiles) end
Set the download rate limit in bytes/second.
# File lib/quartz_torrent/peerclient.rb, line 1819 def setDownloadRateLimit(infoHash, bytesPerSecond) raise "download rate limit must be an Integer, not a #{bytesPerSecond.class}" if bytesPerSecond && ! bytesPerSecond.is_a?(Integer) @handler.setDownloadRateLimit(infoHash, bytesPerSecond) end
Pause or unpause the specified torrent.
# File lib/quartz_torrent/peerclient.rb, line 1814 def setPaused(infoHash, value) @handler.setPaused(infoHash, value) end
Set the maximum amount of time (in seconds) that a torrent can be in the upload-only state before it is paused. Pass nil to disable.
# File lib/quartz_torrent/peerclient.rb, line 1838 def setUploadDuration(infoHash, seconds) raise "upload ratio must be Numeric, not a #{seconds.class}" if seconds && ! seconds.is_a?(Numeric) @handler.setUploadDuration(infoHash, seconds) end
Set the upload rate limit in bytes/second.
# File lib/quartz_torrent/peerclient.rb, line 1825 def setUploadRateLimit(infoHash, bytesPerSecond) raise "upload rate limit must be an Integer, not a #{bytesPerSecond.class}" if bytesPerSecond && ! bytesPerSecond.is_a?(Integer) @handler.setUploadRateLimit(infoHash, bytesPerSecond) end
Set the upload ratio. Pass nil to disable
# File lib/quartz_torrent/peerclient.rb, line 1831 def setUploadRatio(infoHash, ratio) raise "upload ratio must be Numeric, not a #{ratio.class}" if ratio && ! ratio.is_a?(Numeric) @handler.setUploadRatio(infoHash, ratio) end
Start the PeerClient: open the listening port, and start a new thread to begin downloading/uploading pieces. If listening fails, an exception of class Errno::EADDRINUSE is thrown.
# File lib/quartz_torrent/peerclient.rb, line 1741 def start return if ! @stopped @logger.info "Starting" @reactor.listen("0.0.0.0",@port,:listener_socket) @stopped = false @worker = Thread.new do QuartzTorrent.initThread("peerclient") begin @toStart.each{ |trackerclient| trackerclient.start } @reactor.start @logger.info "Reactor stopped." @handler.torrentData.each do |k,v| v.trackerClient.stop end rescue @logger.error "Unexpected exception in worker thread: #{$!}" @logger.error $!.backtrace.join("\n") end end end
Stop the PeerClient
. This method may take some time to complete.
# File lib/quartz_torrent/peerclient.rb, line 1765 def stop return if @stopped @logger.info "Stop called. Stopping reactor" @reactor.stop if @worker @logger.info "Worker wait timed out after 10 seconds. Shutting down anyway" if ! @worker.join(10) end @stopped = true end
Get a hash of new TorrentDataDelegate
objects keyed by torrent infohash. This is the method to call to get information about the state of torrents being downloaded.
# File lib/quartz_torrent/peerclient.rb, line 1807 def torrentData(infoHash = nil) # This will have to work by putting an event in the handler's queue, and blocking for a response. # The handler will build a response and return it. @handler.getDelegateTorrentData(infoHash) end
Private Instance Methods
Helper method for adding a torrent.
# File lib/quartz_torrent/peerclient.rb, line 1866 def addTorrent(trackerclient, infoHash, info, magnet = nil) trackerclient.port = @port torrentData = @handler.addTrackerClient(infoHash, info, trackerclient) torrentData.magnet = magnet trackerclient.dynamicRequestParamsBuilder = Proc.new do torrentData = @handler.torrentData[infoHash] dataLength = (info ? info.dataLength : nil) result = TrackerDynamicRequestParams.new(dataLength) if torrentData && torrentData.blockState result.left = torrentData.blockState.totalLength - torrentData.blockState.completedLength result.downloaded = torrentData.bytesDownloadedDataOnly result.uploaded = torrentData.bytesUploadedDataOnly end result end # If we haven't started yet then add this trackerclient to a queue of # trackerclients to start once we are started. If we start too soon we # will connect to the tracker, and it will try to connect back to us before we are listening. if ! trackerclient.started? if @stopped @toStart.push trackerclient else trackerclient.start end end torrentData.infoHash end