leecher 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -62,7 +62,6 @@ module Leecher
62
62
  [
63
63
  [:username, "your username on the website?", :required],
64
64
  [:password, ".. and the password for that user?", :password],
65
- [:log_fn, "filename to log to:", File.join(@config_dirname, "log")],
66
65
  [:host, "where does the amqp queue live?", "nzb.trim.za.net"],
67
66
  [:aria2_bin, "which aria2 must I use?", %x{which aria2c}.strip()],
68
67
  [:aria2_dir, "what whould you like your default download directory to be?", Dir.pwd],
@@ -172,6 +171,9 @@ module Leecher
172
171
  raise log.fatal("First fork failed") if (pid = Kernel.fork()) == -1
173
172
  Kernel.exit!(RC_OK) unless pid.nil?
174
173
  Process.setsid()
174
+ File.open(File.join(@config_dirname, "pid"), "w") do |f|
175
+ f.puts(Process.pid)
176
+ end
175
177
  Dir.chdir(config[:chdir]) if config.has_key? :chdir
176
178
  File.umask(config[:umask]) if config.has_key? :umask
177
179
  [
@@ -3,7 +3,7 @@
3
3
  :metalink_queue_name: metalink
4
4
  :log:
5
5
  :level: :info
6
- :filename: <%= log_fn %>
6
+ :filename: <%= File.join(config_dirname, "leecher.log") %>
7
7
  :bunny_opts:
8
8
  :host: <%= host %>
9
9
  :port: 5672
@@ -12,8 +12,8 @@
12
12
  :pass: <%= password %>
13
13
  :ssl: false
14
14
  :verify_ssl: false
15
- :logfile: false
16
- :logfile: false
15
+ :logfile: <%= File.join(config_dirname, "bunny.log") %>
16
+ :logging: false
17
17
  :frame_max: 131072
18
18
  :channel_max: 0
19
19
  :heartbeat: 300
@@ -22,4 +22,5 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency(%q<rspec>, [">=2"])
23
23
  s.add_runtime_dependency(%q<bunny>)
24
24
  s.add_runtime_dependency(%q<erubis>)
25
+ s.add_runtime_dependency(%q<yajl-ruby>)
25
26
  end
@@ -4,7 +4,8 @@ module Leecher
4
4
 
5
5
  require "bunny"
6
6
  require "leecher/shellout"
7
- require 'xmlrpc/client'
7
+ require "xmlrpc/client"
8
+ require "yajl"
8
9
 
9
10
  include Leecher::Shellout
10
11
 
@@ -50,7 +51,6 @@ module Leecher
50
51
 
51
52
  def run()
52
53
  @bunny = make_bunny(self.bunny_opts)
53
- @bunny.start()
54
54
 
55
55
  @graceful_shutdown = false
56
56
  @dont_kill_me = false
@@ -94,7 +94,6 @@ module Leecher
94
94
  # Start again.
95
95
  log.debug("Reconnecting to rabbitmq")
96
96
  @bunny = make_bunny(self.bunny_opts)
97
- @bunny.start()
98
97
  rescue Exception => e
99
98
  log.error([e.class.name, e.message].join(": "))
100
99
  e.backtrace.each do |line|
@@ -105,7 +104,10 @@ module Leecher
105
104
  end
106
105
 
107
106
  def make_bunny(bunny_opts)
108
- Bunny.new(bunny_opts)
107
+ b = Bunny.new(bunny_opts)
108
+ b.start()
109
+ b.qos()
110
+ b
109
111
  end
110
112
 
111
113
  def get_queue(bunny, *queue_joinable_name)
@@ -119,25 +121,51 @@ module Leecher
119
121
 
120
122
  next_queue_message(q) do |msg|
121
123
  @dont_kill_me = true
122
-
123
- log.info("Will call aria2.addUri #{msg.inspect()}")
124
-
125
- #FIXME is it possible something can go wrong but not throw an exception?
124
+
125
+ # FIXME: is it possible something can go wrong but not throw an exception?
126
126
  begin
127
- status = call_rpc("aria2.addUri", [msg])
128
- log.info("Added uri to aria with gid: #{status}")
129
- return true
127
+ uris, options = Yajl::Parser.parse(msg)
128
+ call_aria(uris, options)
129
+ true
130
130
  rescue Exception => e
131
131
  log.error("Failed to add uri to aria2c: #{e.message}")
132
- return false
132
+ false
133
+ ensure
134
+ @dont_kill_me = false
135
+ end
136
+ end
137
+ end
138
+
139
+ def call_aria(uris, options)
140
+ rewrite_aria_dir_opt(options)
141
+ log.info("Will call aria2.addUri(#{uris.inspect()}, #{options.inspect()})")
142
+ status = call_rpc("aria2.addUri", uris, options)
143
+ log.info("Added uri to aria with gid: #{status}")
144
+ end
145
+
146
+ def rewrite_aria_dir_opt(options)
147
+ # Attempt to rewrite +dir+ to a relative path
148
+ if (dir = options.delete("dir"))
149
+ begin
150
+ global_opts = call_rpc("aria2.getGlobalOption")
151
+ global_dir = global_opts.delete("dir")
152
+ options["dir"] = File.join(global_dir, dir)
153
+ rescue Exception => e
154
+ log.error("Couldn't get aria2 global options")
133
155
  end
134
156
  end
135
- ensure
136
- @dont_kill_me = false
137
157
  end
138
158
 
139
159
  def next_queue_message(q, &block)
140
- q.subscribe() do |msg|
160
+ # +:timeout+: Sometimes it happens that our connection is stale (e.g. DSL
161
+ # drops and comes back) but the connection never drops. Rabbitmq
162
+ # kicks us off after 15 min. Thus, use a timeout of 15 minutes
163
+ # so that, if lightning strikes, worst case is we're 15 minutes
164
+ # behind.
165
+ # +:ack+: Acks are sent by +queue.ack+, which is sent via the
166
+ # subscribe block automatically if the option is turned on.
167
+ q.subscribe(:timeout => 900,
168
+ :ack => true) do |msg|
141
169
  payload = msg[:payload]
142
170
  case payload
143
171
  when :queue_empty
@@ -169,6 +197,7 @@ module Leecher
169
197
  raise e
170
198
  else
171
199
  retried = true
200
+ log.debug("It appears aria isn't running. Attempting to start it up by calling: #{make_aria_exec}")
172
201
  shellout(make_aria_exec, nil, nil, nil)
173
202
  sleep 10
174
203
  retry
@@ -186,7 +215,7 @@ module Leecher
186
215
  end
187
216
 
188
217
  def make_aria_exec
189
- args = aria2_opts[:args]
218
+ args = aria2_opts[:args].dup
190
219
 
191
220
  if aria2_opts.has_key?(:config)
192
221
  args.push([
@@ -1,3 +1,3 @@
1
1
  module Leecher
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -27,7 +27,7 @@ describe Leecher::Client do
27
27
  @c.metalink_queue_name.should == "metalink"
28
28
  end
29
29
 
30
- describe "#next_queue_message" do
30
+ context "next_queue_message" do
31
31
 
32
32
  it "should only return when something is on the queue" do
33
33
  bunny = double("bunny")
@@ -40,7 +40,7 @@ describe Leecher::Client do
40
40
  end
41
41
  end
42
42
 
43
- describe "#drain_metalink_queue" do
43
+ context "drain_metalink_queue" do
44
44
 
45
45
  before do
46
46
  @q = double("q")
@@ -51,10 +51,13 @@ describe Leecher::Client do
51
51
 
52
52
 
53
53
  it "should rpc to aria2" do
54
+ uris = ["http://some/url"]
55
+ options = {}
54
56
  @c.stub(:next_queue_message).
55
- and_yield("http://some/url")
57
+ and_yield(Yajl::Encoder.encode([uris, options]))
56
58
  rpc_server = double("rpc_server")
57
- rpc_server.stub(:call).
59
+ rpc_server.should_receive(:call).
60
+ with("aria2.addUri", uris, options).
58
61
  and_return(true)
59
62
  @c.stub(:rpc_server).
60
63
  and_return(rpc_server)
@@ -63,7 +66,7 @@ describe Leecher::Client do
63
66
 
64
67
  it "should return according to the success of the rpc" do
65
68
  @c.stub(:next_queue_message).
66
- and_yield("http://some/url")
69
+ and_yield(Yajl::Encoder.encode([[], {}]))
67
70
  rpc_server = double("rpc_server")
68
71
  @c.stub(:rpc_server).
69
72
  and_return(rpc_server)
@@ -74,5 +77,22 @@ describe Leecher::Client do
74
77
  and_raise(RuntimeError)
75
78
  @c.drain_metalink_queue(@q).should be_false
76
79
  end
80
+
81
+ it "should rewrite the dir option" do
82
+ uris = ["http://some/url"]
83
+ options = { "dir" => "foo" }
84
+ @c.stub(:next_queue_message).
85
+ and_yield(Yajl::Encoder.encode([uris, options]))
86
+ rpc_server = double("rpc_server")
87
+ rpc_server.should_receive(:call).
88
+ with("aria2.getGlobalOption").
89
+ and_return({"dir" => "/tmp"})
90
+ rpc_server.should_receive(:call).
91
+ with("aria2.addUri", uris, {"dir" => "/tmp/foo"}).
92
+ and_return(true)
93
+ @c.stub(:rpc_server).
94
+ and_return(rpc_server)
95
+ @c.drain_metalink_queue(@q).should be_true
96
+ end
77
97
  end
78
98
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leecher
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
+ - 2
8
9
  - 1
9
- - 0
10
- version: 0.1.0
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Marc Bowes
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-09 00:00:00 +02:00
18
+ date: 2011-05-26 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -60,6 +60,20 @@ dependencies:
60
60
  version: "0"
61
61
  type: :runtime
62
62
  version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: yajl-ruby
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :runtime
76
+ version_requirements: *id004
63
77
  description: A server populates a queue, this client downloads those files
64
78
  email:
65
79
  - marcbowes+leecher@gmail.com