Class: QuartzTorrent::ExtendedMetaInfo

Inherits:
Extended show all
Defined in:
lib/quartz_torrent/peermsg.rb

Overview

An Extended Metainfo message. Used to request metadata pieces, or provide responses to those requests.

Constant Summary

Constants inherited from PeerWireMessage

PeerWireMessage::MessageBitfield, PeerWireMessage::MessageCancel, PeerWireMessage::MessageChoke, PeerWireMessage::MessageExtended, PeerWireMessage::MessageHave, PeerWireMessage::MessageInterested, PeerWireMessage::MessageKeepAlive, PeerWireMessage::MessagePiece, PeerWireMessage::MessageRequest, PeerWireMessage::MessageUnchoke, PeerWireMessage::MessageUninterested

Instance Attribute Summary collapse

Attributes inherited from Extended

#extendedMessageId

Attributes inherited from PeerWireMessage

#messageId

Instance Method Summary collapse

Methods inherited from Extended

#payloadLength, #to_s

Methods inherited from PeerWireMessage

#length, #payloadLength, #to_s

Constructor Details

#initializeExtendedMetaInfo

Returns a new instance of ExtendedMetaInfo.



407
408
409
410
411
412
413
414
415
# File 'lib/quartz_torrent/peermsg.rb', line 407

def initialize
  super()
  @extendedMessageId = 0
  @msgType = nil
  @piece = nil
  @totalSize = nil
  @data = nil
  @dict = {}
end

Instance Attribute Details

#dataObject

This field is only set if the msgType is :piece. It contains the data for the piece.



424
425
426
# File 'lib/quartz_torrent/peermsg.rb', line 424

def data
  @data
end

#dictObject

Returns the value of attribute dict.



417
418
419
# File 'lib/quartz_torrent/peermsg.rb', line 417

def dict
  @dict
end

#msgTypeObject

Message type as a symbol. One of :request, :data, or :reject



419
420
421
# File 'lib/quartz_torrent/peermsg.rb', line 419

def msgType
  @msgType
end

#pieceObject

Returns the value of attribute piece.



420
421
422
# File 'lib/quartz_torrent/peermsg.rb', line 420

def piece
  @piece
end

#totalSizeObject

This field is only set if the msgType is :piece



422
423
424
# File 'lib/quartz_torrent/peermsg.rb', line 422

def totalSize
  @totalSize
end

Instance Method Details

#serializeTo(io) ⇒ Object



470
471
472
473
474
475
476
# File 'lib/quartz_torrent/peermsg.rb', line 470

def serializeTo(io)
  super(io)
  updateDictFromProps
  io.write @dict.bencode
  raise "Extended metainfo piece messages must have piece data. This one's data was nil" if ! @data && dict['msg_type'] == 1
  io.write @data if dict['msg_type'] == 1
end

#unserialize(payload) ⇒ Object



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/quartz_torrent/peermsg.rb', line 426

def unserialize(payload)
  # Unserialize extended message id
  super(payload)

  # Rest of the message is a bencoded dictionary.
  # Piece messages of this class are encoded in an interesting way: the bencoded dictionary
  # is concatenated with the arbitrary binary data of the piece at the end. To decode this
  # we need to know the position of when we've finished reading the dictionary. We do this by
  # using a Parser object from the bencode library which maintains a stream object which happens
  # to know the current offset of the parsing.

  payload = payload[1,payload.length]
  parser = BEncode::Parser.new payload

  begin
    @dict = parser.parse!
  rescue
    e = RuntimeError.new("Error bdecoding payload '#{payload}' (payload length = #{payload.length})")
    e.set_backtrace($!.backtrace)
    raise e
  end

  @msgType = @dict['msg_type']
  raise "Extended Metainfo message contained no 'msg_type' key." if ! @msgType
  if @msgType == 0
    @msgType = :request
  elsif @msgType == 1
    @msgType = :piece
  elsif @msgType == 2
    @msgType = :reject
  else
    raise "Unknown message type '#{@msgType}' in Extended Metainfo message"
  end

  @piece = @dict['piece']
  raise "Extended Metainfo message contained no 'piece' key." if ! @piece
  
  @totalSize = @dict['total_size'] if @msgType == :piece

  # If this is a piece message, read the data after the dictionary.
  @data = parser.stream.read if @msgType == :piece
  
end