preston/bittorious

View on GitHub
app/controllers/tracker_controller.rb

Summary

Maintainability
A
25 mins
Test Coverage
class TrackerController < ApplicationController

    prepend_before_action :load_from_info_hash
    skip_before_action :authenticate_user!
    layout false

    def announce
        authorize! :announce, @torrent
# byebug
        data = peer_params
        # puts "ANNOUNCE DATA: #{data}"
        peer = @torrent.register_peer(data, current_user)

        # This part is standard BitTorrent.
        tracker_response = {
            'interval'    => Peer::UPDATE_PERIOD_MINUTES.minutes,
            'complete'   => @torrent.seed_count,
            'incomplete' => @torrent.peer_count,
            'peers'      => @torrent.peers.active.map{|p|  {'ip' => p.ip, 'peer id' => p.peer_id, 'port' => p.port}}
        }

        # BitTorious-specific extensions.
        if peer.volunteer_enabled
            tracker_response['volunteer'] = {
                'enabled'            => '1',
                'affinity_length'    => peer.volunteer_affinity_length,
                'affinity_offset'    => peer.volunteer_affinity_offset
            }
        end

        response.headers['Content-Type'] = 'text/plain; charset=ASCII'
        render plain: tracker_response.to_bencoding.encode('ASCII') # Force US-ASCII
    end

    def scrape
        # From http://wiki.theory.org/BitTorrentSpecification
        #   If info_hash was supplied and was valid, this dictionary will contain a single key/value. Each key consists of a 20-byte binary info_hash. The value of each entry is another dictionary containing the following:
        #
        #   complete: number of peers with the entire file, i.e. seeders (integer)
        #   downloaded: total number of times the tracker has registered a completion ("event=complete", i.e. a client finished downloading the torrent)
        #   incomplete: number of non-seeder peers, aka "leechers" (integer)
        #   name: (optional) the torrent's internal name, as specified by the "name" file in the info section of the .torrent file
        requested = []
        torrents = {}
        if(params[:info_hash] && t = load_from_info_hash)
            authorize! :read, t
            requested << t if t
        elsif current_user
            requested = Torrent.accessible_by current_ability
        else # unauthenticated
            requested = Torrent.accessible_by Ability.new(nil)
        end
        requested.each do |t|
            torrents[t.info_hash] = {
                complete: t.seed_count,
                #downloaded: t.downloaded,
                incomplete: t.peer_count,
                name: t.name
            }
        end
        # render text: {files: torrents}.bencode
        render html: {files: torrents}.bencode
    end


    private

    def load_from_info_hash
        @torrent = Torrent.find_by_info_hash(params[:info_hash]) if params[:info_hash]
    end



    def rsize
        rsize = 50
        ['num want', 'numwant', 'num_want'].each do |k|
            if params[k]
                rsize = params[k].to_i
                break
            end
        end
    end

    def peer_params
        # @peer_params ||=
        return {
            info_hash:   params[:info_hash],
            peer_id:     params[:peer_id],
            remote_ip:   get_remote_ip,
            uploaded:    params[:uploaded].to_i,
            downloaded:  params[:downloaded].to_i,
            left:        params[:left].to_i,
            key:         params[:key],
            event:       params[:event] || 'started',
            seed:        !!(@left == 0),
            rsize:       rsize,
            port:        params[:port],
            volunteer:   params[:volunteer]
        }
    end

end