Being a BitTorrent Client

Problem

You want to write a Ruby script that downloads or shares large files with BitTorrent.

Solution

The third-party RubyTorrent library implements the BitTorrent protocol; you can use it to write BitTorrent clients. The RubyTorrent package has no setup.rb file, so youll need to manually copy the files into your Ruby classpath or package them with your application.

The BitTorrent class acts as a BitTorrent client, so to download a torrent, all you have to do is give it the path or URL to a .torrent file. This code will download the classic B-movie Night of the Living Dead to the current working directory:

require ubytorrent file = http://publicdomaintorrents.com/bt/btdownload.php?type=torrent + &file=Night_of_the_Living_Dead.avi.torrent client = RubyTorrent::BitTorrent.new(file)

Run this in irb, keep your session open, and in a few hours (or days), youll have your movie![4]

[4] That is, assuming the torrent is still active when you read this. Incidentally, Night of the Living Dead is in the public domain because of a mishap regarding the copyright notice.

Discussion

BitTorrent is the most efficient way yet devised for sharing large files between lots of people. As you download the file you e also sharing what youve downloaded with others: the more people are trying to download the file, the faster it is for everyone.

RubyTorrent is a simple client library to the BitTorrent protocol. In its simplest form, you simply construct a BitTorrent object with the URL or path to a torrent information file, and wait for the download to complete. However, theres a lot more you can do to provide a better user interface.

The BitTorrent object has several methods that let you keep track of the progress of the download:

client.num_active_peers # => 9 # That is, 9 other people are downloading this file along with me. client.ulrate # => 517.638825414351 client.dlrate # => 17532.608916979 # That is, about 3 kb/sec uploading and 17 kb/sec downloading. client.percent_completed # => 0.25

You can also register code blocks to be run at certain points in the clients lifecycle. Heres a more advanced BitTorrent client that registers code blocks to let the user know about new and dropped peer connections. It also uses a thread to occasionally report on the progress of the download. The user can specify which port to use when uploading data to peers, and a maximum upload rate in kilobytes.

#!/usr/bin/ruby # btclient.rb require ubytorrent def download(torrent, destination=nil, local_port=6881, max_ul=40) client = RubyTorrent::BitTorrent.new(torrent, destination, :port => local_port, :ulratelim => max_ul * 1024) thread = Thread.new do until client.complete? if client.tracker puts \%s: %dk of %dk (%.2f%% complete) % [Time.now, client.bytes_completed / 1024, client.total_bytes / 1024, client.percent_completed] sleep(60) else sleep(5) end end end client.on_event(self, :tracker_connected) do |src, url| puts "[Connected to tracker at #{url}]" end client.on_event(self, :added_peer) do |src, peer| puts "[Connected to #{peer}.]" end client.on_event(self, :removed_peer) do |src, peer| puts "[Lost connection to #{peer.name}.]" end client.on_event(self, :complete) do puts Download complete. thread.kill client.shutdown end thread.join end download(*ARGV)

See Also

Категории