torckapi 0.0.23 → 0.0.24

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0e78cdf84987163d2164e0eab58654e6c0825c6
4
- data.tar.gz: 7516aecf37f02107ce58f5c193dfd1a9285f7289
3
+ metadata.gz: 128514fdb065b8c1127accfd9d1f34faa850abbb
4
+ data.tar.gz: 9ec91b782fb80a643e27a29b59d23913cbf9c5ab
5
5
  SHA512:
6
- metadata.gz: 3c560a87c520bf0f0220fb8608e72cc0072455aeb7be1ed884d8bbb1bb285eb3e9e3f01a3d500e49ee31c99cdaeab6ed241acb6e8e035fbf9dcfe6cea265a0a6
7
- data.tar.gz: 76931f6d709de866750b102a8097d7fbf2b30dbc098c419d4208cf83a10fd54dc411545cf080b8fcd371446a3653e783abd93ce333671eb180b025337a554e38
6
+ metadata.gz: 11251aa9696786eb80c58cd38e108de956363cceb110120e9b2df4f65cc7628645520088571f4c86aa446cfbc7b7f4f89588482c71841e9217279480a2de4c80
7
+ data.tar.gz: 236b55602c853b01eb0882c0f6852559e9378dedb79c78658c4bc08f57e7004f0647442b947ceb5b7afe24e71c2663837ea09910a72043d6929aeab8e2b85eda
@@ -10,6 +10,7 @@ module Torckapi
10
10
  CommunicationFailedError = Class.new(CommunicationError)
11
11
  CommunicationTimeoutError = Class.new(CommunicationError)
12
12
  MalformedResponseError = Class.new(Error)
13
+ LittleEndianResponseError = Class.new(MalformedResponseError)
13
14
  TransactionIdMismatchError = Class.new(CommunicationError)
14
15
  end
15
16
  end
@@ -30,7 +30,7 @@ module Torckapi
30
30
 
31
31
  def initialize url, options={}
32
32
  @url = url
33
- @options = {timeout: 15, tries: 3}.merge(options)
33
+ @options = {timeout: 15, tries: 7}.merge(options)
34
34
  end
35
35
  end
36
36
  end
@@ -7,13 +7,13 @@ module Torckapi
7
7
  class HTTP < Base
8
8
  # (see Base#announce)
9
9
  def announce info_hash
10
- super info_hash
10
+ super
11
11
  Torckapi::Response::Announce.from_http(info_hash, perform_request(url_for(@url.dup, Announce, info_hash)))
12
12
  end
13
13
 
14
14
  # (see Base#scrape)
15
15
  def scrape info_hashes=[]
16
- super info_hashes
16
+ super
17
17
  Torckapi::Response::Scrape.from_http(perform_request(url_for(@url.dup, Scrape, info_hashes)))
18
18
  end
19
19
 
@@ -22,7 +22,7 @@ module Torckapi
22
22
  REQUEST_ACTIONS = [Announce = 1, Scrape = 2].freeze
23
23
 
24
24
  def initialize url, options={}
25
- super url, options
25
+ super
26
26
  @url.query ||= ""
27
27
  end
28
28
 
@@ -8,12 +8,12 @@ module Torckapi
8
8
  # Implementation of http://www.bittorrent.org/beps/bep_0015.html
9
9
  class UDP < Base
10
10
  def announce info_hash, peer_id=SecureRandom.random_bytes(20)
11
- super info_hash
11
+ super
12
12
  perform_request Announce, announce_request_data(info_hash, peer_id), info_hash
13
13
  end
14
14
 
15
15
  def scrape info_hashes=[]
16
- super info_hashes
16
+ super
17
17
  perform_request Scrape, scrape_request_data(info_hashes), info_hashes
18
18
  end
19
19
 
@@ -23,12 +23,27 @@ module Torckapi
23
23
  REQUEST_ACTIONS = [Connect = 0, Announce = 1, Scrape = 2].freeze
24
24
  RESPONSE_CLASSES = [nil, Torckapi::Response::Announce, Torckapi::Response::Scrape, Torckapi::Response::Error].freeze
25
25
  RESPONSE_MIN_LENGTHS = [16, 20, 8, 8].freeze
26
+ RESPONSE_CODES = 0..RESPONSE_CLASSES.length
27
+
28
+ def initialize url, options={}
29
+ super
30
+ @state = nil
31
+ @connection_id = nil
32
+ @communicated_at = 0
33
+ end
34
+
35
+ def connected?
36
+ @connection_id && @communicated_at.to_i >= Time.now.to_i - CONNECTION_TIMEOUT
37
+ end
38
+
39
+ def connecting?
40
+ @state == :connecting
41
+ end
26
42
 
27
43
  def perform_request action, data, *args
28
- connect
29
44
  response = communicate action, data
30
45
 
31
- RESPONSE_CLASSES[response[:type]].from_udp(*args, response[:data])
46
+ RESPONSE_CLASSES[response[:code]].from_udp(*args, response[:data])
32
47
  end
33
48
 
34
49
  def announce_request_data info_hash, peer_id
@@ -40,29 +55,31 @@ module Torckapi
40
55
  end
41
56
 
42
57
  def connect
43
- return if @connection_id && @communicated_at.to_i >= Time.now.to_i - CONNECTION_TIMEOUT
58
+ return if connected? || connecting?
44
59
 
45
- @connection_id = [0x041727101980].pack('Q>')
60
+ @state, @connection_id = :connecting, [0x041727101980].pack('Q>')
46
61
  response = communicate Connect
47
- @connection_id = response[:data]
62
+ @state, @connection_id = nil, response[:data]
48
63
  end
49
64
 
50
65
  def communicate action, data=nil
51
66
  @socket ||= UDPSocket.new
52
67
 
53
- transaction_id = SecureRandom.random_bytes(4)
54
68
  tries = 0
55
69
  response = nil
56
70
 
57
71
  begin
72
+ timeout = @options[:timeout] * (2 ** tries)
73
+ connect
74
+ transaction_id = SecureRandom.random_bytes(4)
58
75
  packet = [@connection_id, [action].pack('L>'), transaction_id, data].join
59
76
 
60
- Timeout::timeout(@options[:timeout], CommunicationTimeoutError) do
77
+ Timeout::timeout(timeout, CommunicationTimeoutError) do
61
78
  @socket.send(packet, 0, @url.host, @url.port)
62
79
  response = parse_response @socket.recvfrom(65536), transaction_id
63
80
  @communicated_at = Time.now
64
81
  end
65
- rescue CommunicationTimeoutError
82
+ rescue CommunicationTimeoutError, LittleEndianResponseError => e
66
83
  retry if (tries += 1) <= @options[:tries]
67
84
  end
68
85
 
@@ -72,14 +89,18 @@ module Torckapi
72
89
  end
73
90
 
74
91
  def parse_response data, transaction_id
75
- response, sender_addrinfo = data
76
-
77
- response_type = response[0..3].unpack('L>')[0]
92
+ response = data[0]
78
93
 
79
94
  raise TransactionIdMismatchError, response.inspect if transaction_id != response[4..7]
80
- raise MalformedResponseError, response.inspect if RESPONSE_MIN_LENGTHS[response_type] > response.length
81
95
 
82
- {type: response_type, data: response[8..-1]}
96
+ response_code, response_code_le = response[0..3].unpack('L>')[0], response[0..3].unpack('L<')[0]
97
+
98
+ unless RESPONSE_CODES.include?(response_code)
99
+ raise (RESPONSE_CODES.include?(response_code_le) ? LittleEndianResponseError : MalformedResponseError), response.inspect
100
+ end
101
+ raise MalformedResponseError, response.inspect if RESPONSE_MIN_LENGTHS[response_code] > response.length
102
+
103
+ {code: response_code, data: response[8..-1]}
83
104
  end
84
105
  end
85
106
  end
@@ -1,3 +1,3 @@
1
1
  module Torckapi
2
- VERSION = "0.0.23"
2
+ VERSION = "0.0.24"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: torckapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Krupenik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-24 00:00:00.000000000 Z
11
+ date: 2014-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake