Class: RubyTorrent::Piece
- Inherits:
-
Object
- Object
- RubyTorrent::Piece
show all
- Includes:
- EventSource
- Defined in:
- lib/rubytorrent/package.rb
Overview
a Piece is the basic unit of the .torrent metainfo file (though not of the bittorrent protocol). Pieces store their data directly on disk, so many operations here will be slow. each Piece stores data in one or more file pointers.
unlike Blocks and Packages, which are either complete or incomplete, a Piece can be complete but not valid, if the SHA1 check fails. thus, a call to piece.complete? is not sufficient to determine whether the data is ok to use or not.
Pieces handle all the trickiness involved with Blocks: taking in Blocks from arbitrary locations, writing them out to the correct set of file pointers, keeping track of which sections of the data have been filled, claimed but not filled, etc.
Instance Attribute Summary collapse
Instance Method Summary
collapse
append_features, #on_event, #relay_event, #send_event, #unregister_events
Constructor Details
#initialize(index, sha1, start, length, files, validity_assumption = nil) ⇒ Piece
Returns a new instance of Piece.
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
# File 'lib/rubytorrent/package.rb', line 267
def initialize(index, sha1, start, length, files, validity_assumption=nil)
@index = index
@sha1 = sha1
@start = start
@length = length
@files = files @valid = nil
@start_index = 0
sum = 0
while(sum + @files[@start_index][2] <= @start)
sum += @files[@start_index][2]
@start_index += 1
end
@start_offset = @start - sum
@have = Covering.new(AwesomeRange.new(0 ... @length)).complete!
@valid = validity_assumption
@have.empty! unless valid?
@claimed = Covering.new(AwesomeRange.new(0 ... @length))
@state_m = Mutex.new
end
|
Instance Attribute Details
#index ⇒ Object
Returns the value of attribute index.
264
265
266
|
# File 'lib/rubytorrent/package.rb', line 264
def index
@index
end
|
#length ⇒ Object
Returns the value of attribute length.
264
265
266
|
# File 'lib/rubytorrent/package.rb', line 264
def length
@length
end
|
#start ⇒ Object
Returns the value of attribute start.
264
265
266
|
# File 'lib/rubytorrent/package.rb', line 264
def start
@start
end
|
Instance Method Details
#add_block(b) ⇒ Object
we don’t do any checking that this block has been claimed or not.
379
380
381
382
383
384
385
386
387
388
389
390
|
# File 'lib/rubytorrent/package.rb', line 379
def add_block(b)
@valid = nil
write = false
new_have = @state_m.synchronize { @have.fill AwesomeRange.new(b.begin ... (b.begin + b.length)) }
if new_have != @have
@have = new_have
write = true
end
write_bytes(b.begin, b.data) if write
send_event(:complete) if complete?
end
|
#claim_block(b) ⇒ Object
356
357
358
359
360
|
# File 'lib/rubytorrent/package.rb', line 356
def claim_block(b)
@state_m.synchronize do
@claimed = @claimed.fill AwesomeRange.new(b.begin ... (b.begin + b.length))
end
end
|
#complete? ⇒ Boolean
302
|
# File 'lib/rubytorrent/package.rb', line 302
def complete?; @have.complete?; end
|
#discard ⇒ Object
305
306
307
308
309
310
311
|
# File 'lib/rubytorrent/package.rb', line 305
def discard @state_m.synchronize do
@have.empty!
@claimed.empty!
end
@valid = false
end
|
#each_empty_block(max_length) ⇒ Object
348
349
350
351
352
353
354
|
# File 'lib/rubytorrent/package.rb', line 348
def each_empty_block(max_length)
raise "no empty blocks in a complete piece" if complete?
each_gap(@have, max_length) do |start, len|
yield Block.new(@index, start, len)
end
end
|
#each_unclaimed_block(max_length) ⇒ Object
340
341
342
343
344
345
346
|
# File 'lib/rubytorrent/package.rb', line 340
def each_unclaimed_block(max_length)
raise "no unclaimed blocks in a complete piece" if complete?
each_gap(@claimed, max_length) do |start, len|
yield Block.new(@index, start, len)
end
end
|
#empty_bytes ⇒ Object
331
332
333
334
335
|
# File 'lib/rubytorrent/package.rb', line 331
def empty_bytes
r = 0
each_gap(@have) { |start, len| r += len }
r
end
|
#get_complete_block(beginn, length) ⇒ Object
for a complete Piece, returns a complete Block of specified size and location.
370
371
372
373
374
375
376
|
# File 'lib/rubytorrent/package.rb', line 370
def get_complete_block(beginn, length)
raise "can't make block from incomplete piece" unless complete?
raise "invalid parameters #{beginn}, #{length}" unless (length > 0) && (beginn + length) <= @length
b = Block.new(@index, beginn, length)
b.add_chunk read_bytes(beginn, length) end
|
#percent_claimed ⇒ Object
337
|
# File 'lib/rubytorrent/package.rb', line 337
def percent_claimed; 100.0 * (@length.to_f - unclaimed_bytes) / @length; end
|
#percent_done ⇒ Object
338
|
# File 'lib/rubytorrent/package.rb', line 338
def percent_done; 100.0 * (@length.to_f - empty_bytes) / @length; end
|
#started? ⇒ Boolean
303
|
# File 'lib/rubytorrent/package.rb', line 303
def started?; !@claimed.empty? || !@have.empty?; end
|
#to_s ⇒ Object
298
299
300
|
# File 'lib/rubytorrent/package.rb', line 298
def to_s
"<piece #@index: #@start + #@length #{(complete? ? 'cmp' : 'inc')}>"
end
|
#unclaim_block(b) ⇒ Object
362
363
364
365
366
|
# File 'lib/rubytorrent/package.rb', line 362
def unclaim_block(b)
@state_m.synchronize do
@claimed = @claimed.poke AwesomeRange.new(b.begin ... (b.begin + b.length))
end
end
|
#unclaimed_bytes ⇒ Object
325
326
327
328
329
|
# File 'lib/rubytorrent/package.rb', line 325
def unclaimed_bytes
r = 0
each_gap(@claimed) { |start, len| r += len }
r
end
|
#valid? ⇒ Boolean
313
314
315
316
317
318
319
320
321
322
323
|
# File 'lib/rubytorrent/package.rb', line 313
def valid?
return @valid unless @valid.nil?
return (@valid = false) unless complete?
data = read_bytes(0, @length)
if (data.length != @length)
@valid = false
else
@valid = (Digest::SHA1.digest(data) == @sha1)
end
end
|