Class: RubyTorrent::Package

Inherits:
Object show all
Includes:
EventSource
Defined in:
lib/rubytorrent/package.rb

Overview

finally, the Package. one Package per Controller so we don’t do any thread safety stuff in here.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from EventSource

append_features, #on_event, #relay_event, #send_event, #unregister_events

Constructor Details

#initialize(metainfo, out = nil, validity_assumption = nil) ⇒ Package

Returns a new instance of Package.



487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/rubytorrent/package.rb', line 487

def initialize(metainfo, out=nil, validity_assumption=nil)
  info = metainfo.info

  created = false
  out ||= info.name
  case out
  when File
    raise ArgumentError, "'out' cannot be a File for a multi-file .torrent" if info.multiple?
    fstream = out
  when Dir
    raise ArgumentError, "'out' cannot be a Dir for a single-file .torrent" if info.single?
    fstream = out
  when String
    if info.single?
      rt_debug "output file is #{out}"
      begin
        fstream = File.open(out, "rb+")
      rescue Errno::ENOENT
 created = true
        fstream = File.open(out, "wb+")
      end
    else
      rt_debug "output directory is #{out}"
      unless File.exists? out
        Dir.mkdir(out)
        created = true
      end
      fstream = Dir.open(out)
    end
  else
    raise ArgumentError, "'out' should be a File, Dir or String object, is #{out.class}"
  end

  @ro = false
  @size = info.total_length
  if info.single?
    @files = [[fstream, Mutex.new, info.length]]
  else
    @files = info.files.map do |finfo|
      path = File.join(finfo.path[0, finfo.path.length - 1].inject(fstream.path) do |path, el|
        dir = File.join(path, el)
        unless File.exist? dir
          rt_debug "making directory #{dir}"
          Dir.mkdir dir
        end
        dir
      end, finfo.path[finfo.path.length - 1])
      rt_debug "opening #{path}..."
      [open_file(path), Mutex.new, finfo.length]
    end
  end

  i = 0
  @pieces = info.pieces.unpack("a20" * (info.pieces.length / 20)).map do |hash|
    start = (info.piece_length * i)
    len = [info.piece_length, @size - start].min
    p = Piece.new(i, hash, start, len, @files, (created ? false : validity_assumption))
    p.on_event(self, :complete) { send_event(:complete) if complete? }
    yield p if block_given?
    (i += 1) && p
  end

  reopen_ro if complete?
end

Instance Attribute Details

#piecesObject (readonly)

Returns the value of attribute pieces.



484
485
486
# File 'lib/rubytorrent/package.rb', line 484

def pieces
  @pieces
end

#sizeObject (readonly)

Returns the value of attribute size.



484
485
486
# File 'lib/rubytorrent/package.rb', line 484

def size
  @size
end

Instance Method Details

#bytes_completedObject



571
572
573
# File 'lib/rubytorrent/package.rb', line 571

def bytes_completed
  @pieces.inject(0) { |s, p| s + (p.complete? ? p.length : 0) }
end

#complete?Boolean

Returns:

  • (Boolean)


569
# File 'lib/rubytorrent/package.rb', line 569

def complete?; @pieces.detect { |p| !p.complete? || !p.valid? } == nil; end

#num_piecesObject



583
# File 'lib/rubytorrent/package.rb', line 583

def num_pieces; @pieces.length; end

#percent_completedObject



579
580
581
# File 'lib/rubytorrent/package.rb', line 579

def percent_completed
  100.0 * pieces_completed.to_f / @pieces.length.to_f
end

#pieces_completedObject



575
576
577
# File 'lib/rubytorrent/package.rb', line 575

def pieces_completed
  @pieces.inject(0) { |s, p| s + (p.complete? ? 1 : 0) }
end

#reopen_roObject



553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
# File 'lib/rubytorrent/package.rb', line 553

def reopen_ro
  raise "called on incomplete package" unless complete?
  return if @ro
  
  rt_debug "reopening all files with mode r"
  begin
  @files = @files.map do |fp, mutex, size|
    [fp.reopen(fp.path, "rb"), mutex, size]
  end
  rescue   SystemCallError, StandardError
          $stderr.print "system call error: " + $!
  end # exception rescue

  @ro = true
end

#ro?Boolean

Returns:

  • (Boolean)


552
# File 'lib/rubytorrent/package.rb', line 552

def ro?; @ro; end

#to_sObject



585
586
587
# File 'lib/rubytorrent/package.rb', line 585

def to_s
  "<#{self.class} size #@size>"
end