torckapi 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +0 -2
- data/lib/torckapi/errors.rb +1 -1
- data/lib/torckapi/response/announce.rb +8 -7
- data/lib/torckapi/response/base.rb +21 -0
- data/lib/torckapi/response/error.rb +4 -1
- data/lib/torckapi/response/scrape.rb +14 -11
- data/lib/torckapi/tracker/base.rb +10 -3
- data/lib/torckapi/tracker/http.rb +2 -2
- data/lib/torckapi/tracker/udp.rb +5 -8
- data/lib/torckapi/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23d4a93deca3957dc10d4e056c505b5f57d92bd2
|
4
|
+
data.tar.gz: d4b1fe9fcb70d7ffa604209da48a3018702108dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2994677c358450c2a6e9a4d3a8ef2ef559e04b30963c37ae2b4ae96a793edef7c78d5abf653b61b3708e9db64c8ff8322bf0752600e3eb48bd1535eee0763851
|
7
|
+
data.tar.gz: 31f3e8806ab54efc32fa48db835f0b7ff1df1d7c64b67aa0908961121c44dddaee734dc022f4ea20d813d7dcef5e6b770fbb963a7506f6015c64c9755a00817b
|
data/README.md
CHANGED
data/lib/torckapi/errors.rb
CHANGED
@@ -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 <
|
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 '
|
2
|
+
require 'torckapi/response/base'
|
3
3
|
|
4
4
|
module Torckapi
|
5
5
|
module Response
|
6
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
new info_hash, *bdecoded_data.values_at(
|
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,10 +1,9 @@
|
|
1
|
-
require '
|
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 =
|
22
|
-
|
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
|
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
|
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(
|
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
|
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
|
-
|
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
|
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 ||= ""
|
data/lib/torckapi/tracker/udp.rb
CHANGED
@@ -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
|
data/lib/torckapi/version.rb
CHANGED
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.
|
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
|