class Torrenter::Peer::BufferState

Attributes

piece[R]

Public Class Methods

new(socket, info_hash) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 13
def initialize(socket, info_hash)
  @socket    = socket
  @buffer    = ''
  @info_hash = info_hash
end

Public Instance Methods

bitfield() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 74
def bitfield
  unpack('B').first.split('')
end
current_piece=(type) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 54
def current_piece=(type)
  @piece.status = type if @piece
end
hash_matches?() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 58
def hash_matches?
  @buffer[28..47] == @info_hash
end
have() { |unpack('C').last| ... } click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 70
def have
  yield unpack('C').last
end
messager(index, blk) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 19
def messager(index, blk)
  if @buffer.empty?
    recv
  else
    case @buffer[4]
    when nil
      @buffer.slice!(0..3) if @buffer[0..3] == KEEP_ALIVE
    when HANDSHAKE
      parse_handshake
    when BITFIELD
      bitfield.each_with_index do |bit, i|
        blk.call(i, @socket) if bit == '1'
      end

      send_interested if @buffer.empty?
    when HAVE
      if @buffer.bytesize < 9
        recv
      else
        have { |i| blk.call(i, @socket) }
      end
      send_interested if @buffer.empty?
    when INTERESTED
      parse_interested(index)
    when PIECE
      parse_piece(index)
    when CANCEL
      @socket.close
    else
      recv
      send(KEEP_ALIVE)
    end
  end
end
packet_length?() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 111
def packet_length?
  @buffer.size >= msg_length + 4
end
parse_handshake() { || ... } click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 62
def parse_handshake
  if !hash_matches?
    yield
  else
    @buffer.slice!(0..67)
  end
end
parse_interested(index) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 87
def parse_interested(index)
  if interested?
    pick_piece(index)
    request_piece if @piece
  else
    @socket.close
  end
end
parse_piece(index) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 96
def parse_piece(index)
  if packet_length?
    @piece << @buffer.slice!(13..-1)
    @buffer.clear
    if @piece.complete?
      @piece.write_to_file
      @piece = nil
      pick_piece(index) unless index.all?
    end
    request_piece
  else
    recv
  end
end
pick_piece(index) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 78
def pick_piece(index)
  @piece = index.find_least(@socket)
  if @piece
    puts "#{@piece.index} selected by #{@socket}."
  else
    puts "No piece selected!"
  end
end
piece_selected?() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 140
def piece_selected?
  @piece
end
recv(bytes=BLOCK) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 127
def recv(bytes=BLOCK)
  begin
    @buffer << @socket.recv_nonblock(bytes)
  rescue *EXCEPTIONS
    ''
  rescue Errno::ETIMEDOUT
    if piece_selected?
      @piece.status = :available
    end
    @socket.close
  end
end
request_piece() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 115
def request_piece
  send pack(13, "\x06", @piece.index, @piece.chunk, @piece.block) if @piece
end
send(msg) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 119
def send(msg)
  begin
    @socket.sendmsg_nonblock(msg)
  rescue *EXCEPTIONS
    @socket.close
  end
end

Private Instance Methods

interested?() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 162
def interested?
  @buffer.slice!(0..4) == "\x00\x00\x00\x01\x01"
end
msg_length() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 158
def msg_length
  @buffer[0..3].unpack("N*").last
end
pack(*msg) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 150
def pack(*msg)
  msg.map { |m| m.is_a?(Integer) ? [m].pack("I>") : m }.join
end
send_interested() click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 146
def send_interested
  send("\x00\x00\x00\x01\x02")
end
unpack(type) click to toggle source
# File lib/torrenter/peer/buffer_state.rb, line 154
def unpack(type)
  @buffer.slice!(0...msg_length + 4)[5..-1].unpack("#{type}*")
end