class QuartzTorrent::HttpTrackerDriver
A tracker driver that uses the HTTP protocol. This is the classic BitTorrent tracker protocol.
Public Class Methods
new(announceUrl, infoHash)
click to toggle source
Calls superclass method
QuartzTorrent::TrackerDriver::new
# File lib/quartz_torrent/httptrackerdriver.rb, line 9 def initialize(announceUrl, infoHash) super() @startSent = false @logger = LogManager.getLogger("http_tracker_client") @announceUrl = announceUrl @infoHash = infoHash end
Public Instance Methods
request(event = nil)
click to toggle source
Request a list of peers from the tracker and return it as a TrackerResponse. Event, if specified, may be set to :started, :stopped, or :completed. This is used to notify the tracker that this is the first request, that we are shutting down, or that we have the full torrent respectively. Not specifying the event just means this is a regular poll.
def getPeers(event = nil)
# File lib/quartz_torrent/httptrackerdriver.rb, line 23 def request(event = nil) uri = URI(@announceUrl) dynamicParams = @dynamicRequestParamsBuilder.call params = {} params['info_hash'] = CGI.escape(@infoHash) params['peer_id'] = dynamicParams.peerId params['port'] = dynamicParams.port params['uploaded'] = dynamicParams.uploaded.to_s params['downloaded'] = dynamicParams.downloaded.to_s params['left'] = dynamicParams.left.to_s params['compact'] = "1" params['no_peer_id'] = "1" if ! @startSent event = :started @startSent = true end params['event'] = event.to_s if event @logger.debug "Request parameters: " params.each do |k,v| @logger.debug " #{k}: #{v}" end query = "" params.each do |k,v| query << "&" if query.length > 0 query << "#{k}=#{v}" end uri.query = query begin res = Net::HTTP.get_response(uri) rescue Timeout::Error return TrackerResponse.new(false, "Tracker request timed out", []) end @logger.debug "Tracker response code: #{res.code}" @logger.debug "Tracker response body: #{res.body}" result = buildTrackerResponse(res) @logger.debug "TrackerResponse: #{result.inspect}" result end
Protected Instance Methods
decodePeers(peersProp)
click to toggle source
# File lib/quartz_torrent/httptrackerdriver.rb, line 70 def decodePeers(peersProp) peers = [] if peersProp.is_a?(String) # Compact format: 4byte IP followed by 2byte port, in network byte order index = 0 while index + 6 <= peersProp.length ip = peersProp[index,4].unpack("CCCC").join('.') port = peersProp[index+4,2].unpack("n").first peers.push TrackerPeer.new(ip, port) index += 6 end else # Non-compact format peersProp.each do |peer| ip = peer['ip'] port = peer['port'] if ip && port peers.push TrackerPeer.new(ip, port) end end #raise "Non-compact peer format not implemented" end peers end
Private Instance Methods
buildTrackerResponse(netHttpResponse)
click to toggle source
# File lib/quartz_torrent/httptrackerdriver.rb, line 96 def buildTrackerResponse(netHttpResponse) error = nil peers = [] interval = nil success = netHttpResponse.code.to_i >= 200 && netHttpResponse.code.to_i < 300 if success begin decoded = netHttpResponse.body.bdecode rescue error = "Tracker netHttpResponse body was not a valid bencoded string" success = false return self end if decoded.has_key? 'peers' peers = decodePeers(decoded['peers']) else error = "Tracker netHttpResponse didn't contain a peers property" success = false end if decoded.has_key? 'interval' interval = decoded['interval'].to_i end else error = netHttpResponse.body end result = TrackerResponse.new(success, error, peers) result.interval = interval if interval result end