torckapi 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e495bbcc0cb11ec0068098e7c26d5df80e6b0993
4
- data.tar.gz: 44342f08c1d9e6640a9e7a8c06c6e5397646b031
3
+ metadata.gz: 23d4a93deca3957dc10d4e056c505b5f57d92bd2
4
+ data.tar.gz: d4b1fe9fcb70d7ffa604209da48a3018702108dd
5
5
  SHA512:
6
- metadata.gz: 57f087caa172b88f83df1d6511dd124b2767749357ebdda87b59326edc86eda2f4b305977bcedb8ebd54a8a866b1eb4d05d41daaf37ce359355b649ee3c8fa5a
7
- data.tar.gz: dfc8f78453037d1d758985de50f618813eaffeb19b982a6b873133c034b79601e4c91639ac8899ef5ed6940a68bf41eaaef58aeded3f2c4e7e2fa7a8f7a416e1
6
+ metadata.gz: 2994677c358450c2a6e9a4d3a8ef2ef559e04b30963c37ae2b4ae96a793edef7c78d5abf653b61b3708e9db64c8ff8322bf0752600e3eb48bd1535eee0763851
7
+ data.tar.gz: 31f3e8806ab54efc32fa48db835f0b7ff1df1d7c64b67aa0908961121c44dddaee734dc022f4ea20d813d7dcef5e6b770fbb963a7506f6015c64c9755a00817b
data/README.md CHANGED
@@ -36,6 +36,4 @@ tracker.scrape(["0123456789ABCDEF0123456789ABCDEF01234567", "123456789ABCDEF0123
36
36
 
37
37
  Add tests.
38
38
 
39
- Add HTTP implementation.
40
-
41
39
  Document everything.
@@ -9,7 +9,7 @@ module Torckapi
9
9
  class CommunicationError < Error; end
10
10
  class CommunicationFailedError < CommunicationError; end
11
11
  class CommunicationTimeoutError < CommunicationError; end
12
- class MalformedResponseError < CommunicationError; end
12
+ class MalformedResponseError < Error; end
13
13
  class TransactionIdMismatchError < CommunicationError; end
14
14
  end
15
15
  end
@@ -1,9 +1,10 @@
1
1
  require 'ipaddr'
2
- require 'bencode'
2
+ require 'torckapi/response/base'
3
3
 
4
4
  module Torckapi
5
5
  module Response
6
- class Announce
6
+ # Announce response
7
+ class Announce < Base
7
8
  # @!attribute [r] info_hash
8
9
  # @return [String] 40-char hexadecimal string
9
10
  # @!attribute [r] leechers
@@ -12,6 +13,7 @@ module Torckapi
12
13
  # @return [Array<IPAddr, Fixnum>] list of peers
13
14
  # @!attribute [r] seeders
14
15
  # @return [Fixnum] number of seeders
16
+
15
17
  attr_reader :info_hash, :leechers, :peers, :seeders
16
18
 
17
19
  # Construct response object from udp response data
@@ -25,12 +27,11 @@ module Torckapi
25
27
  # Construct response object from http response data
26
28
  # @param info_hash [String] 40-char hexadecimal string
27
29
  # @param data [String] HTTP response data (bencoded)
28
- # @param compact [true, false] is peer data in compact format?
29
30
  # @return [Torckapi::Response::Announce] response
30
- def self.from_http info_hash, data, compact=true
31
- bdecoded_data = BEncode.load(data)
32
- raise Torckapi::Tracker::MalformedResponseError unless bdecoded_data.is_a? Hash and bdecoded_data.has_key? 'peers'
33
- new info_hash, *bdecoded_data.values_at("incomplete", "complete"), peers_from_compact(bdecoded_data['peers'])
31
+ # @raise [Torckapi::Tracker::MalformedResponseError]
32
+ def self.from_http info_hash, data
33
+ bdecoded_data = bdecode_and_check data, 'peers'
34
+ new info_hash, *bdecoded_data.values_at('incomplete', 'complete'), peers_from_compact(bdecoded_data['peers'])
34
35
  end
35
36
 
36
37
  private
@@ -0,0 +1,21 @@
1
+ require 'bencode'
2
+
3
+ module Torckapi
4
+ module Response
5
+ class Base
6
+ protected
7
+
8
+ def self.bdecode_and_check data, key
9
+ begin
10
+ bdecoded_data = BEncode.load(data)
11
+ rescue BEncode::DecodeError
12
+ raise Torckapi::Tracker::MalformedResponseError
13
+ end
14
+
15
+ raise Torckapi::Tracker::MalformedResponseError unless bdecoded_data.is_a? Hash and bdecoded_data.has_key? key
16
+
17
+ bdecoded_data
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,9 @@
1
+ require 'torckapi/response/base'
2
+
1
3
  module Torckapi
2
4
  module Response
3
- class Error
5
+ # Error response
6
+ class Error < Base
4
7
  # @!attribute [r] info_hash
5
8
  # @return [String] 40-char hexadecimal string
6
9
  # @!attribute [r] info_hashes
@@ -1,10 +1,9 @@
1
- require 'bencode'
1
+ require 'torckapi/response/base'
2
2
 
3
3
  module Torckapi
4
4
  module Response
5
-
6
5
  # Scrape response
7
- class Scrape
6
+ class Scrape < Base
8
7
  # @return [Hash<String, Hash>] scrape data
9
8
  attr_reader :data
10
9
 
@@ -12,29 +11,33 @@ module Torckapi
12
11
  # @param info_hashes [Array<String>] list of 40-char hexadecimal strings
13
12
  # @param data [String] UDP response data (omit action and transaction_id)
14
13
  # @return [Torckapi::Response::Scrape] response
14
+ # @raise [Torckapi::Tracker::MalformedResponseError]
15
15
  def self.from_udp info_hashes, data
16
- raise Torckapi::MalformedResponseError if data.length != info_hashes.count * 12
16
+ raise Torckapi::Tracker::MalformedResponseError if data.length != info_hashes.count * 12
17
17
  new Hash[info_hashes.zip(data.unpack('a12' * info_hashes.count).map { |i| counts_unpacked(i) })]
18
18
  end
19
19
 
20
+ # Construct response object from http response data
21
+ # @param data [String] HTTP response data (bencoded)
22
+ # @return [Torckapi::Response::Scrape] response
23
+ # @raise [Torckapi::Tracker::MalformedResponseError]
20
24
  def self.from_http data
21
- bdecoded_data = BEncode.load(data)
22
- raise Torckapi::MalformedResponseError unless bdecoded_data.is_a? Hash and bdecoded_data.has_key? 'files'
23
- new Hash[bdecoded_data["files"].map { |info_hash, counts| [info_hash.unpack('H*').join, counts_translated(counts) ]}]
25
+ bdecoded_data = bdecode_and_check data, 'files'
26
+ new Hash[bdecoded_data['files'].map { |info_hash, counts| [info_hash.unpack('H*').join, counts_translated(counts) ]}]
24
27
  end
25
28
 
26
29
  private
27
30
 
28
31
  def self.counts_unpacked data
29
- counts_with_block(data, lambda { |data| data.unpack('L>3').map(&:to_i) })
32
+ counts_with_block(data) { |data| data.unpack('L>3').map(&:to_i) }
30
33
  end
31
34
 
32
35
  def self.counts_translated data
33
- counts_with_block(data, lambda { |data| data.values_at("complete", "downloaded", "incomplete") })
36
+ counts_with_block(data) { |data| data.values_at('complete', 'downloaded', 'incomplete') }
34
37
  end
35
38
 
36
- def self.counts_with_block data, block
37
- Hash[[:seeders, :completed, :leechers].zip(block.call(data))]
39
+ def self.counts_with_block data, &block
40
+ Hash[[:seeders, :completed, :leechers].zip(yield data)]
38
41
  end
39
42
 
40
43
  def initialize data
@@ -3,16 +3,23 @@ module Torckapi
3
3
 
4
4
  # Public interface for torrent trackers
5
5
  class Base
6
- # Announce Request
6
+ # Announce request
7
7
  # @param info_hash [String] 40-char hexadecimal string
8
+ # @param peer_id [String] 20-byte binary string
8
9
  # @return [Torckapi::Response::Announce] a response object
9
- def announce info_hash
10
+ # @raise [Torckapi::InvalidInfohashError] when supplied with invalid info_hash
11
+ # @raise [Torckapi::Tracker::CommunicationFailedError] when tracker haven't responded at all
12
+ # @raise [Torckapi::Tracker::MalformedResponseError] when tracker returned junk
13
+ def announce info_hash, peer_id=SecureRandom.random_bytes(20)
10
14
  raise Torckapi::InvalidInfohashError if info_hash !~ /\A[0-9a-f]{40}\z/i
11
15
  end
12
16
 
13
- # Scrape Request
17
+ # Scrape request
14
18
  # @param info_hashes [Array<String>] An array of 40-char hexadecimal strings
15
19
  # @return [Torckapi::Response::Scrape] a response object
20
+ # @raise [Torckapi::InvalidInfohashError] when supplied with invalid info_hash
21
+ # @raise [Torckapi::Tracker::CommunicationFailedError] when tracker haven't responded at all
22
+ # @raise [Torckapi::Tracker::MalformedResponseError] when tracker returned junk
16
23
  def scrape info_hashes=[]
17
24
  raise Torckapi::InvalidInfohashError if info_hashes.any? { |i| i !~ /\A[0-9a-f]{40}\z/i }
18
25
  end
@@ -5,8 +5,6 @@ module Torckapi
5
5
  module Tracker
6
6
 
7
7
  class HTTP < Base
8
- REQUEST_ACTIONS = [Announce = 1, Scrape = 2].freeze
9
-
10
8
  # (see Base#announce)
11
9
  def announce info_hash
12
10
  super info_hash
@@ -21,6 +19,8 @@ module Torckapi
21
19
 
22
20
  private
23
21
 
22
+ REQUEST_ACTIONS = [Announce = 1, Scrape = 2].freeze
23
+
24
24
  def initialize url, options={}
25
25
  super url, options
26
26
  @url.query ||= ""
@@ -5,21 +5,13 @@ require 'torckapi/tracker/base'
5
5
 
6
6
  module Torckapi
7
7
  module Tracker
8
-
9
8
  # Implementation of http://www.bittorrent.org/beps/bep_0015.html
10
9
  class UDP < Base
11
- CONNECTION_TIMEOUT = 60
12
- REQUEST_ACTIONS = [Connect = 0, Announce = 1, Scrape = 2].freeze
13
- RESPONSE_CLASSES = [nil, Torckapi::Response::Announce, Torckapi::Response::Scrape, Torckapi::Response::Error].freeze
14
- RESPONSE_MIN_LENGTHS = [16, 20, 8, 8].freeze
15
-
16
- # (see Base#announce)
17
10
  def announce info_hash, peer_id=SecureRandom.random_bytes(20)
18
11
  super info_hash
19
12
  perform_request Announce, announce_request_data(info_hash, peer_id), info_hash
20
13
  end
21
14
 
22
- # (see Base#scrape)
23
15
  def scrape info_hashes=[]
24
16
  super info_hashes
25
17
  perform_request Scrape, scrape_request_data(info_hashes), info_hashes
@@ -27,6 +19,11 @@ module Torckapi
27
19
 
28
20
  private
29
21
 
22
+ CONNECTION_TIMEOUT = 60
23
+ REQUEST_ACTIONS = [Connect = 0, Announce = 1, Scrape = 2].freeze
24
+ RESPONSE_CLASSES = [nil, Torckapi::Response::Announce, Torckapi::Response::Scrape, Torckapi::Response::Error].freeze
25
+ RESPONSE_MIN_LENGTHS = [16, 20, 8, 8].freeze
26
+
30
27
  def perform_request action, data, *args
31
28
  connect
32
29
  response = communicate action, data
@@ -1,3 +1,3 @@
1
1
  module Torckapi
2
- VERSION = "0.0.16"
2
+ VERSION = "0.0.17"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: torckapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Krupenik
@@ -66,6 +66,7 @@ files:
66
66
  - lib/torckapi.rb
67
67
  - lib/torckapi/errors.rb
68
68
  - lib/torckapi/response/announce.rb
69
+ - lib/torckapi/response/base.rb
69
70
  - lib/torckapi/response/error.rb
70
71
  - lib/torckapi/response/scrape.rb
71
72
  - lib/torckapi/tracker/base.rb