[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