Class: Torrenter::Peer::BufferState

Inherits:
Object
  • Object
show all
Defined in:
lib/torrenter/peer/buffer_state.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket, info_hash) ⇒ BufferState

Returns a new instance of BufferState.



13
14
15
16
17
# File 'lib/torrenter/peer/buffer_state.rb', line 13

def initialize(socket, info_hash)
  @socket    = socket
  @buffer    = ''
  @info_hash = info_hash
end

Instance Attribute Details

#pieceObject (readonly)

Returns the value of attribute piece.



12
13
14
# File 'lib/torrenter/peer/buffer_state.rb', line 12

def piece
  @piece
end

Instance Method Details

#bitfieldObject



74
75
76
# File 'lib/torrenter/peer/buffer_state.rb', line 74

def bitfield
  unpack('B').first.split('')
end

#current_piece=(type) ⇒ Object



54
55
56
# File 'lib/torrenter/peer/buffer_state.rb', line 54

def current_piece=(type)
  @piece.status = type if @piece
end

#hash_matches?Boolean

Returns:

  • (Boolean)


58
59
60
# File 'lib/torrenter/peer/buffer_state.rb', line 58

def hash_matches?
  @buffer[28..47] == @info_hash
end

#have {|unpack('C').last| ... } ⇒ Object

Yields:

  • (unpack('C').last)


70
71
72
# File 'lib/torrenter/peer/buffer_state.rb', line 70

def have
  yield unpack('C').last
end

#messager(index, blk) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 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?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/torrenter/peer/buffer_state.rb', line 111

def packet_length?
  @buffer.size >= msg_length + 4
end

#parse_handshakeObject



62
63
64
65
66
67
68
# 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) ⇒ Object



87
88
89
90
91
92
93
94
# 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) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 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) ⇒ Object



78
79
80
81
82
83
84
85
# 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?Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/torrenter/peer/buffer_state.rb', line 140

def piece_selected?
  @piece
end

#recv(bytes = BLOCK) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
# 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_pieceObject



115
116
117
# 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) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/torrenter/peer/buffer_state.rb', line 119

def send(msg)
  begin
    @socket.sendmsg_nonblock(msg)
  rescue *EXCEPTIONS
    @socket.close
  end
end