[Aversa-commits] aversa/sample bt-downloader.rb
bt-metainfo-viewer.rb bt-tracker.rb rubit.rb
teamikl at rubyforge.org
teamikl at rubyforge.org
Wed Sep 8 13:11:56 EDT 2004
Update of /var/cvs/aversa/aversa/sample
In directory rubyforge.org:/tmp/cvs-serv18536
Modified Files:
bt-downloader.rb bt-metainfo-viewer.rb bt-tracker.rb rubit.rb
Log Message:
bt-downloader.rb and bt-tracker.rb sample does not work, yet.
Now, rubit.rb can be the application front end, but those modules
also can run standalone.
Index: bt-downloader.rb
===================================================================
RCS file: /var/cvs/aversa/aversa/sample/bt-downloader.rb,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** bt-downloader.rb 5 Sep 2004 10:01:02 -0000 1.1
--- bt-downloader.rb 8 Sep 2004 17:11:49 -0000 1.2
***************
*** 9,12 ****
--- 9,17 ----
#
# - TODO Param savedir, download/upload rate, connections limit, strategy
+ # - TODO peer handler and downlaod/seeder strategy
+ # - TODO move MutexArray to Utility module.
+ # - TODO remove AspectR, and implement simple point-cup method in util.
+ # - TODO Offer easier API to user.
+ # - TODO Improve scheduler
#
# == AUTHORS
***************
*** 16,35 ****
#
! require "net/bittorrent"
include Net::BitTorrent
module Net
module BitTorrent
! module Client
def initialize(metainfo)
! @metainfo = metainfo
! @storage = Storage.new(metainfo)
! @bitfield = BitField.create(metainfo['info']['pieces'],
! @storage.get_pieces)
end
! def start_uploader
! @seeder = TCPServer()
end
--- 21,215 ----
#
! require 'thread'
! require 'socket'
! require 'aspectr'
! require 'net/bittorrent'
include Net::BitTorrent
+ include AspectR
+
+
+ class MutexArray < Array
+ attr_reader :mutex
+ def initialize
+ @mutex = Mutex.new
+ end
+ end
+
+ class MutexArrayAspect < Aspect
+ def lock(method, object, status, *args)
+ object.mutex.lock()
+ end
+
+ def unlock(method, object, status, *args)
+ object.mutex.unlock()
+ end
+ end
+
+ mutex_array_aspect = MutexArrayAspect.new() do |aspect|
+ aspect.wrap(MutexArray, :lock, :unlock, /\<\</)
+ aspect.wrap(MutexArray, :lock, :unlock, /\>\>/)
+ aspect.wrap(MutexArray, :lock, :unlock, /push/)
+ aspect.wrap(MutexArray, :lock, :unlock, /delete/)
+ aspect.wrap(MutexArray, :lock, :unlock, /each/)
+ end
+
module Net
module BitTorrent
! class Client
!
! @@version = '0.0.1'
+ # This client can take 1 metainfo file only.
+ # Sample of single download.
+ #
def initialize(metainfo)
!
! # MetaInfo
! @metainfo = MetaInfo.new(metainfo)
!
! # Storage info
! @storage = Storage.new(@metainfo)
! @bitfield = @storage.get_bitfield
!
! # Peers info
! @port = nil
! @server = nil
! @connections = MutexArray.new
! @peers = []
!
! # Tracker info
! @infohash = @metainfo.infohash
! @peerid = Util::create_myid(@@version, Time.now, Process.pid)
!
! # Scheduler info
! @tasks = MutexArray.new
!
! # handshake message
! # TODO move into module
! @protocol_name = "BitTorrent protocol"
! @handshake_message = @protocol_name.size.chr + @protocol_name
! @handshake_message += Array.new(8,0).pack('C8')
! @handshake_message += @infohash + @peerid
! end
!
!
! # TODO move to Net::BitTorrent::Seeder#open
! def setup_upload_peer(port_range)
! catch(:server_is_opened) do
! port_range.each do |port|
! begin
! @server = TCPServer.open(port)
! @port = port
! throw :server_is_opened
! rescue Errno::EADDRINUSE => error
! warn error.to_s
! next
! end
! end
! raise "Could not open upload peer port"
! end
!
! @connections.push(@server)
! puts "Start upload peer (port:#{@port})"
! end
!
!
! # TODO this also should separate to other class
! def connect_to_tracker
! # TODO Rerequester class will be changed
! req = Rerequester.new(@metainfo['announce'], @peerid, @infohash, @port)
! req.data['event'] = 'started'
! req.data['left'] = @metainfo.get_file_length
!
! # TODO move to inside of tracker requester class
! http = HTTPConnection.new
! http.userAgent = ''
! http.acceptEncoding = 'gzip'
!
! # TODO this also, wrap http session to a class
! # TODO http.get(req.to_uri).bdecode is smarter ? String#bdecode
! res = nil
! begin
! # TODO res = http.get(req.to_uri).bdecode
! res = decode(http.get( req.to_uri ))
! rescue Errno::ECONNREFUSED => e
! puts "Tracker not found (url:%s)" % @metainfo['announce']
! exit -1
! end
!
! # XXX check response.
! @peers = Util::parse_peers(res['peers']) unless res.nil?
end
! # Connect to peers and handshake
! def connect_to_peers
! @peers.uniq.each do |peer|
! next if peer['ip'] == '127.0.0.1' and peer['port'] == @port
! @tasks << proc {
! begin
! sock = TCPSocket.open(peer['ip'], peer['port'])
! sock.write(@handshake_message)
! @connections.push(sock)
! puts "Connected: %s:%d " % [peer['ip'], peer['port']]
! puts " write: handshake"
! rescue Exception => e
! puts "Connection failed: %s:%d" % [peer['ip'], peer['port']]
! end
! }
! puts "Added to task: connect(%s:%d)" % [peer['ip'], peer['port']]
! end
! end
!
! # TODO move to Net::BitTorrent::RawServer#start
! def start_server
! loop do
! puts "SERVER LOOP BEGIN"
!
! sockets = select(@connections)
! next if sockets.nil?
!
! for sock in sockets[0]
! if sock == @server
! new_sock = sock.accept
! p new_sock.peeraddr
! @connections.push(new_sock)
! puts "log: new peer connected"
! else
! if sock.eof?
! sock.close
! @connections.delete(sock)
! puts "log: peer disconnected"
! else
! len = sock.recv(4).unpack('N').shift
! tmp = sock.recv(len)
!
! # TODO : Continuation passing style.
! if tmp == @protocol_name # recieved handshake
! puts "log: recived handshake"
! sock.recv(8 + 20 + 20)
! else
! raise NotImplementedError
! end
! end
! end
! end
!
! puts "SERVER LOOP END"
! end
! end
!
! def start_task_scheduler
! loop do
! puts "tasks" + ('.' * @tasks.size)
! if @tasks.length > 0
! @tasks.each do |task|
! puts "task.call"
! task.call
! @tasks.delete(task) # TODO and FIXME bad lock
! end
! end
! sleep 1
! end
end
***************
*** 39,68 ****
! if $0 == __FILE__
! if ARGV.length > 0 and File.exists?(ARGV[0])
! # XXX Storage class does not take absolute path yet.
# Dir.chdir(File.dirname(ARGV[0]))
# Prepare BitTorrent download client object.
! # The argument is path of metainfo file.
! bt = Net::BitTorrent::Client.new(ARGV[0])
! # TODO start upload peer
! bt.start_uploader
! # TODO connect to trackers(announces) and get peers list
!
! # TODO connect to peers and shakehand
!
! # TODO Start Download strategy
! else
! puts "Usage: [.torrent file]"
! exit(-1)
! end
! else
! puts "ERROR: Do not include this file."
! exit(-2)
end
--- 219,276 ----
! module BtDownloader
!
! def self.help
! return "(bt-downloader) usage: [.torrent]"
! end
! def self.version
! return "(bt-downloader) version"
! end
!
! def self.main(*argv)
!
! begin
! raise ArgumentError if argv.empty?
! rescue Exception => e
! puts BtDownloader.help
! raise Exception
! end
!
! file = argv.shift
!
! ##
! # XXX save-directory of Storage.
! # If you want to save the download file to other directory,
! # you have to chdir, now.
! # I will change Storage class to care save file path in future.
! #
# Dir.chdir(File.dirname(ARGV[0]))
# Prepare BitTorrent download client object.
! # The argument is a path of metainfo file.
! bt = Net::BitTorrent::Client.new(file)
! # Start upload server (seeder), the argument is range of upload port.
! bt.setup_upload_peer((6900...7000))
! # Connect to tracker(announce url) and get peers list.
! bt.connect_to_tracker()
!
! # Connect to peers and shakehand.
! bt.connect_to_peers()
! # Start servers
! Thread.start(bt) do |bt_client|
! Thread.pass
! bt_client.start_server
! end
!
! # Scheduler start
! bt.start_task_scheduler
!
! end
end
+ BtDownloader.main(*ARGV) if $0 == __FILE__
+
Index: bt-tracker.rb
===================================================================
RCS file: /var/cvs/aversa/aversa/sample/bt-tracker.rb,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** bt-tracker.rb 7 Sep 2004 21:09:37 -0000 1.3
--- bt-tracker.rb 8 Sep 2004 17:11:49 -0000 1.4
***************
*** 143,149 ****
# main
#-------------------------------------------------
! if $0 == __FILE__ then
! tracker = BitTorrent::Tracker.new( :Port => 6969 )
! tracker.start
end
--- 143,162 ----
# main
#-------------------------------------------------
! module BtTracker
! def self.help
! return "(bt-tracker) Usage: [port]"
! end
!
! def self.version
! return "(bt-tracker) version..."
! end
!
! def self.main(*argv)
! tracker = BitTorrent::Tracker.new( :Port => 6969 )
! tracker.start
! end
end
+ BtTracker.main(*ARGV) if $0 == __FILE__
+
+
Index: bt-metainfo-viewer.rb
===================================================================
RCS file: /var/cvs/aversa/aversa/sample/bt-metainfo-viewer.rb,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** bt-metainfo-viewer.rb 4 Sep 2004 18:36:36 -0000 1.1
--- bt-metainfo-viewer.rb 8 Sep 2004 17:11:49 -0000 1.2
***************
*** 14,41 ****
#
! if $0 == __FILE__ and ARGV.length > 0 then
!
! require "net/bittorrent/metainfo"
! include Net::BitTorrent
! metainfo = MetaInfo.new( ARGV[0] )
! puts "-------------------" * 4
! puts "creation date : %s" % Time.at(metainfo.date) # ['creation date']
! puts "comment : %s" % metainfo['comment']
! puts "announce list : "
! metainfo.announces.each do |announce|
! puts " %s" % announce
end
- puts
- puts "[Info]"
- puts " name : %s " % metainfo["info"]["name"]
- puts " length : %d bytes" % metainfo.get_file_length
- puts " piece length : %d " % metainfo["info"]["piece length"]
- puts "-------------------" * 4
-
- else
- puts "Usage: [.torrent file path or uri]"
- exit(-1)
end
--- 14,56 ----
#
! require "net/bittorrent/metainfo"
! include Net::BitTorrent
! module BtMetaInfoViewer
! def self.help
! return "bt-metainfo-viewer.rb (help)\nUsage: [.torrent]"
! end
!
! def self.version
! return "bt-metainfo-viewer.rb (version)"
! end
!
! def self.main(file)
! metainfo = MetaInfo.new( file )
!
! puts "-------------------" * 4
! puts "creation date : %s" % Time.at(metainfo.date) # ['creation date']
! puts "comment : %s" % metainfo['comment']
! puts "announce list : "
! metainfo.announces.each do |announce|
! puts " %s" % announce
! end
! puts
! puts "[Info]"
! puts " name : %s " % metainfo["info"]["name"]
! puts " length : %d bytes" % metainfo.get_file_length
! puts " piece length : %d " % metainfo["info"]["piece length"]
! puts "-------------------" * 4
! end
! end
!
! if $0 == __FILE__
! unless ARGV.length < 1
! puts "Usage: [.torrent file path or uri]"
! exit(-1)
! else
! BtMetaInfoViewer.main(*ARGV)
end
end
Index: rubit.rb
===================================================================
RCS file: /var/cvs/aversa/aversa/sample/rubit.rb,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** rubit.rb 7 Sep 2004 21:07:27 -0000 1.2
--- rubit.rb 8 Sep 2004 17:11:49 -0000 1.3
***************
*** 82,90 ****
class RuBit
! def self.main(args)
! p args
end
end
! RuBit.main(ARGV) if $0 == __FILE__
--- 82,182 ----
class RuBit
!
! ##
! # If restrict file/module naming rules,
! # we can generate this table from exists files, dinamically.
! #
!
! @@module_table = {
! 'download' => { 'require' => 'bt-downloader.rb',
! 'include' => 'BtDownloader' },
! 'showinfo' => { 'require' => 'bt-metainfo-viewer.rb',
! 'include' => 'BtMetaInfoViewer' },
! 'makeinfo' => { 'require' => 'bt-metainfo-maker.rb',
! 'include' => 'BtMetaInfoMaker' },
! 'track' => { 'require' => 'bt-tracker.rb',
! 'include' => 'BtTracker' },
! }
!
!
! ##
! # Each modules can have meta information which help and version,
! # by implement special the methods. follow like thiese:
! #
!
! def self.help
! return "(Rubit) Help message"
! end
!
! def self.version
! return "(RuBit) Version message v0.0.1"
! end
!
!
! ##
! # Here is a main entry point.
! def self.main(*argv)
! command = argv.shift
! bt = RuBit.new
!
! ##
! # If command is a toplevel command, and if top level command had argument
! # rubit help ... show 'rubit' s help
! # rubit help showinfo ... show 'showinfo' module's help
! #
! if command.match(/\bhelp\b/) # help
! puts (argv.empty?) ? help : bt.load_module(argv.shift).help
! elsif command.match(/\bversion\b/) # version
! puts (argv.empty?) ? version : bt.load_module(argv.shift).version
! else
! bt.run(command, *argv)
! end
end
+
+
+ ##
+ # Generate methods each module_table's keys.
+ @@module_table.each_key do |method_name|
+ define_method(method_name.to_sym) do |*args|
+ self.run(command, *args)
+ end
+ end
+
+
+ ##
+ # load module and return the module object.
+ def load_module(module_name)
+ unless @@module_table.has_key? module_name
+ raise "Unknown command '#{module_name}'"
+ end
+ require_file = @@module_table[module_name]['require']
+ include_name = @@module_table[module_name]['include']
+
+ unless File.exists?(require_file)
+ raise "#{require_file} for #{module_name} module was not found"
+ end
+
+ unless require require_file
+ raise "Failed to load #{require_file}"
+ end
+
+ unless Object.constants.include?(include_name)
+ raise "#{include_name} Module/Class was not loaded"
+ end
+ return Object.const_get(include_name)
+ end
+
+ ##
+ # call the module's main
+ def run(module_name, *args)
+ obj = load_module(module_name)
+ unless obj.respond_to? "main"
+ raise NoMethodError, "undefined method 'main' fo #{include_name}"
+ end
+ return obj.main(*args)
+ end
+
end
! RuBit.main(*ARGV) if $0 == __FILE__
More information about the Aversa-commits
mailing list