requeus 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Ilia Ablamonov, Anatoliy Plastinin, Cloud Castle Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = requeus
2
+
3
+ Requeus is a library for proxying http requests via queue (currently supports Amazon SQS and RabbitMQ).
4
+ It consists of two parts:
5
+ * client for adding request to queue
6
+ * and background worker for processing queue
7
+
8
+ == Copyright
9
+
10
+ Copyright (c) 2011 Ilia Ablamonov, Anatoliy Plastinin, Cloud Castle Inc. See LICENSE.txt for
11
+ further details.
12
+
data/lib/requeus.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'thread'
2
+
3
+ %w(blob_store impl queue request server adapters).each do |file|
4
+ require "requeus/#{file}"
5
+ end
6
+
7
+ require 'requeus/railtie' if defined?(Rails)
8
+
9
+ module Requeus
10
+ class << self
11
+ def request queue, method, path, params = {}, headers = {}
12
+ Requeus::Impl.instance.request queue, method, path, params, headers
13
+ end
14
+
15
+ def start_workers
16
+ Requeus::Impl.instance.start_workers
17
+ end
18
+
19
+ def config_path= path;
20
+ Requeus::Impl.instance.config_path = path;
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,46 @@
1
+ require 'fileutils'
2
+
3
+ module Requeus
4
+ module Adapter
5
+ class Filesystem
6
+ def initialize opts
7
+ @path = opts['path']
8
+ ensure_path
9
+ end
10
+
11
+ def put file
12
+ uid = generate_id
13
+ FileUtils.copy file.path, path_for(uid)
14
+ FileUtils.chmod 0666, path_for(uid)
15
+ uid
16
+ end
17
+
18
+ def get uid
19
+ return nil unless File.exists?(path_for(uid))
20
+ File.new path_for(uid)
21
+ end
22
+
23
+ def delete uid
24
+ FileUtils.remove path_for(uid)
25
+ true
26
+ end
27
+
28
+ private
29
+
30
+ def path_for uid
31
+ File.join @path, uid
32
+ end
33
+
34
+ def ensure_path
35
+ FileUtils.mkdir_p(@path) unless File.exists?(@path)
36
+ raise "Path '#{@path}' is not writable" unless File.writable?(@path)
37
+ end
38
+
39
+ def generate_id
40
+ UUIDTools::UUID.timestamp_create().to_s
41
+ end
42
+
43
+ Requeus::BlobStore.adapters['filesystem'] = self
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,79 @@
1
+ require 'carrot'
2
+
3
+ #todo: schedule 'recover' action to mimic SQS behaviour
4
+
5
+ module Requeus
6
+ module Adapter
7
+ class Rabbit
8
+ def initialize opts
9
+ @opts = opts
10
+ end
11
+
12
+ def put queue, request
13
+ cmd cq(queue), :publish, request, :persistent => true
14
+ true
15
+ end
16
+
17
+ def get queue, limit = 1
18
+ result = []
19
+ requests = 0
20
+
21
+ while requests <= limit && r = pop_request(cq(queue))
22
+ result << r
23
+ requests += 1
24
+ end
25
+
26
+ result
27
+ end
28
+
29
+ def confirm queue, handle
30
+ cq(queue).delivery_tag = handle
31
+ cmd cq(queue), :ack
32
+ true
33
+ end
34
+
35
+ private
36
+
37
+ def cq name
38
+ client.queue(name, :durable => true)
39
+ end
40
+
41
+ def pop_request queue
42
+ request = cmd queue, :pop
43
+ [queue.delivery_tag, request] if request
44
+ end
45
+
46
+ def cmd queue, command, *args
47
+ retried = false
48
+ begin
49
+ queue.send(command, *args)
50
+ rescue Carrot::AMQP::Server::ServerDown => e
51
+ puts 'Reconnecting...'
52
+ unless retried
53
+ drop_client
54
+ retried = true
55
+ retry
56
+ else
57
+ raise e
58
+ end
59
+ end
60
+ end
61
+
62
+ def drop_client
63
+ Thread.current[:requeus_rabbit_client] = nil
64
+ end
65
+
66
+ def client
67
+ Thread.current[:requeus_rabbit_client] ||= Carrot.new(
68
+ :host => @opts['host'],
69
+ :port => @opts['port'].to_i,
70
+ :user => @opts['user'],
71
+ :pass => @opts['pass'],
72
+ :vhost => @opts['vhost']
73
+ )
74
+ end
75
+
76
+ Requeus::Server.adapters['rabbit'] = self
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,59 @@
1
+ require 'aws'
2
+
3
+ module Requeus
4
+ module Adapter
5
+ class S3 < Filesystem
6
+ def initialize options
7
+ @options = options
8
+ super 'path' => options['cache_path']
9
+ end
10
+
11
+ def put file
12
+ uid = generate_id
13
+ begin
14
+ bucket.put(uid, open(file.path))
15
+ rescue Aws::AwsError
16
+ raise "S3:Failed to upload local file '#{file}' as '#{uid}' to AWS/S3 bucket '#{bucket.name}'"
17
+ end
18
+ uid
19
+ end
20
+
21
+ def delete uid
22
+ bucket.delete_key uid
23
+ super uid
24
+ end
25
+
26
+ def get uid
27
+ key = bucket.key(uid)
28
+ raise "S3:File 's3://#{bucket.name}/#{uid}' doesn't exists" unless key.exists?
29
+ File.open(path_for(uid), 'w') {|f| f.write(key.data) }
30
+ super uid
31
+ end
32
+
33
+ private
34
+
35
+ def connection
36
+ @connection ||= Aws::S3.new(@options['access_key_id'], @options['secret_access_key'])
37
+ end
38
+
39
+ def bucket
40
+ @bucket ||= begin
41
+ bucket = connection.bucket(@options['bucket'])
42
+ bucket = connection.bucket(@options['bucket'], true) unless bucket.exists? #todo: permissions
43
+ bucket
44
+ end
45
+ end
46
+
47
+ Requeus::BlobStore.adapters['s3'] = self
48
+ end
49
+ end
50
+ end
51
+
52
+ class Aws::S3::Bucket
53
+ def exists?
54
+ location
55
+ true
56
+ rescue Aws::AwsError
57
+ false
58
+ end
59
+ end
@@ -0,0 +1,35 @@
1
+ module Requeus
2
+ module Adapter
3
+ class SQS
4
+ def initialize options = {}
5
+ @options = options
6
+ end
7
+
8
+ def put queue, request
9
+ get_queue(queue).send_message(request)
10
+ end
11
+
12
+ def get queue, limit = 1
13
+ get_queue(queue).receive_messages(limit).map do |message|
14
+ [message.receipt_handle, message.body]
15
+ end
16
+ end
17
+
18
+ def confirm queue, handle
19
+ connection.interface.delete_message(connection.interface.queue_url_by_name(queue), handle)
20
+ end
21
+
22
+ private
23
+
24
+ def get_queue queue
25
+ (@queues ||= {})[queue] ||= connection.queue(queue)
26
+ end
27
+
28
+ def connection
29
+ @connection ||= Aws::Sqs.new(@options['access_key_id'], @options['secret_access_key'])
30
+ end
31
+
32
+ Requeus::Server.adapters['sqs'] = self
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ %w(filesystem rabbit s3 sqs).each do |file|
2
+ require "requeus/adapter/#{file}"
3
+ end
@@ -0,0 +1,21 @@
1
+ module Requeus
2
+ class BlobStore
3
+ def initialize name, conf
4
+ @name = name
5
+ @connection = self.class.adapters[conf['adapter']].new(conf)
6
+ end
7
+
8
+ delegate :put, :get, :delete,
9
+ :to => :connection
10
+
11
+ attr_reader :name
12
+
13
+ private
14
+
15
+ attr_reader :connection
16
+
17
+ def self.adapters
18
+ @@adapters ||= {}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'singleton'
2
+
3
+ module Requeus
4
+ class Impl
5
+ include Singleton
6
+
7
+ def request queue, method, path, params, headers
8
+ r = Requeus::Request.new(method, path, params, headers).to_json
9
+ server_sequence.any? {|q| q.put(queues[queue].name, r)}
10
+ end
11
+
12
+ def start_workers
13
+ queues.values.map {|q| q.start_workers}.flatten.each(&:join)
14
+ end
15
+
16
+ def config_path= path
17
+ @config_path = path
18
+ end
19
+
20
+ def config
21
+ @config ||= YAML.load_file(@config_path)[ENV['REQUEUS_ENV'] || ENV['RAILS_ENV'] || 'development']
22
+ end
23
+
24
+ def queues
25
+ @queues ||= {}.tap do |queues|
26
+ config['queues'].each do |name, conf|
27
+ queues[name] = Requeus::Queue.new conf
28
+ end
29
+ end
30
+ end
31
+
32
+ def server_sequence
33
+ @server_sequence ||= config['servers']['sequence'].split.map do |name|
34
+ conf = @config['servers'][name]
35
+ Requeus::Server.new name, conf
36
+ end
37
+ end
38
+
39
+ def blob_sequence
40
+ @blob_sequence ||= config['blob']['sequence'].split.map do |name|
41
+ conf = @config['blob'][name]
42
+ Requeus::BlobStore.new name, conf
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,54 @@
1
+ module Requeus
2
+ class Queue
3
+ def initialize conf
4
+ @name = conf['name']
5
+ @endpoint = conf['endpoint']
6
+ @workers_count = conf['workers'].to_i
7
+ @interval = conf['interval'].to_f
8
+ end
9
+
10
+ attr_reader :name,
11
+ :endpoint
12
+
13
+ def start_workers
14
+ workers_queue = SizedQueue.new(@workers_count)
15
+
16
+ @workers_count.times.map do
17
+ Thread.new do
18
+ loop do
19
+ begin
20
+ server, queue, handle, request = workers_queue.pop
21
+
22
+ if request.do_request queue.endpoint
23
+ server.confirm queue.name, handle
24
+ request.delete_files
25
+ end
26
+ rescue Exception => e
27
+ puts e
28
+ puts e.backtrace.join("\n")
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Requeus::Impl.instance.server_sequence.map do |s|
35
+ Thread.new(s) do |server|
36
+ loop do
37
+ begin
38
+ requests = server.get @name, workers_queue.num_waiting
39
+
40
+ if requests.empty?
41
+ sleep server.interval * @interval
42
+ else
43
+ requests.each {|handle, request| workers_queue << [server, self, handle, Requeus::Request.from_json(request)]}
44
+ end
45
+ rescue Exception => e
46
+ puts e
47
+ puts e.backtrace.join("\n")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ module Requeus
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load 'tasks/requeus.rake'
5
+ end
6
+
7
+ initializer "requeus.initialize" do
8
+ config_file = Rails.root.join("config", "requeus.yml")
9
+
10
+ if config_file.file?
11
+ Requeus.config_path = config_file
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,121 @@
1
+ require 'tempfile'
2
+ require 'net/http'
3
+ require 'net/http/post/multipart'
4
+
5
+ # Stub for running outside Rails
6
+ module ActionDispatch; module Http; class UploadedFile; end; end; end
7
+
8
+ module Requeus
9
+ class Request
10
+ def initialize method, path, params, headers, file_uids = nil
11
+ @method = method
12
+ @path = path
13
+ @params = params.reject{|_, v| as_file(v)}
14
+ @headers = headers
15
+
16
+ if file_uids
17
+ @files = file_uids
18
+ else
19
+ @files = params.reject{|_, v| !as_file(v)}
20
+ @files.each {|k, v| @files[k] = upload_file(as_file(v)) if as_file(v)}
21
+ end
22
+ end
23
+
24
+ def self.from_json json
25
+ r = JSON.parse(json)
26
+ new r['method'], r['path'], r['params'], r['headers'], r['files']
27
+ end
28
+
29
+ def do_request endpoint
30
+ uri = URI.parse endpoint + @path
31
+
32
+ req_klass = case @method.upcase
33
+ when 'GET'
34
+ Net::HTTP::Get
35
+ when 'POST'
36
+ Net::HTTP::Post
37
+ when 'PUT'
38
+ Net::HTTP::Put
39
+ when 'DELETE'
40
+ Net::HTTP::Delete
41
+ end
42
+
43
+ res = Net::HTTP.start uri.host, uri.port do |http|
44
+ if @files.present?
45
+ params = @params.dup
46
+ @files.each do |k, uid|
47
+ params[k] = UploadIO.new(download_file(uid), "application/octet-stream")
48
+ end
49
+ req = req_klass::Multipart.new uri.path, params
50
+ else
51
+ req = req_klass.new uri.path
52
+ req.form_data = to_http_data(@params) if req_klass::REQUEST_HAS_BODY
53
+ end
54
+
55
+ @headers.each{|k,v| req.add_field(k, v)}
56
+
57
+ http.request req
58
+ end
59
+
60
+ if res.is_a? Net::HTTPOK
61
+ true
62
+ else
63
+ puts "Error #{res.code} returned for request:"
64
+ puts self.to_json
65
+ false
66
+ end
67
+ end
68
+
69
+ def delete_files
70
+ @files.each do |_, uid|
71
+ blob_sequence.any?{|bs| bs.delete uid}
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def upload_file file
78
+ blob_sequence.each do |bs|
79
+ uid = bs.put file
80
+ return uid if uid
81
+ end
82
+ end
83
+
84
+ def download_file uid
85
+ blob_sequence.each do |bs|
86
+ file = bs.get uid
87
+ return file if file
88
+ end
89
+ end
90
+
91
+ def blob_sequence
92
+ Requeus::Impl.instance.blob_sequence
93
+ end
94
+
95
+ def as_file param
96
+ case param
97
+ when File, Tempfile
98
+ param
99
+ when ActionDispatch::Http::UploadedFile
100
+ param.tempfile
101
+ else
102
+ nil
103
+ end
104
+ end
105
+
106
+ #todo: make recursion
107
+ def to_http_data params
108
+ result = {}
109
+ params.each do |k, v|
110
+ if v.is_a?(Hash)
111
+ v.each do |k1, v1|
112
+ result["#{k.to_s}[#{k1.to_s}]"] = v1
113
+ end
114
+ else
115
+ result[k.to_s] = v
116
+ end
117
+ end
118
+ result
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,40 @@
1
+ module Requeus
2
+ class Server
3
+
4
+ private
5
+
6
+ def self.forward_to method_name, obj
7
+ class_eval <<-EOS
8
+ def #{method_name}(*args, &block)
9
+ #{obj}.send(#{method_name.inspect}, *args, &block)
10
+ end
11
+ EOS
12
+ end
13
+
14
+ public
15
+
16
+ forward_to :put, :connection
17
+ forward_to :get, :connection
18
+ forward_to :confirm, :connection
19
+
20
+ def initialize name, conf
21
+ @name = name
22
+ @connection = self.class.adapters[conf['adapter']].new(conf)
23
+ @interval = conf['interval'].to_f
24
+ end
25
+
26
+ # delegate :put, :get, :confirm,
27
+ # :to => :connection
28
+
29
+ attr_reader :name,
30
+ :interval
31
+
32
+ private
33
+
34
+ attr_reader :connection
35
+
36
+ def self.adapters
37
+ @@adapters ||= {}
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require 'daemons'
2
+
3
+ def requeus_main cmd
4
+ pwd = `pwd`.strip
5
+
6
+ opts = {
7
+ :dir_mode => :normal,
8
+ :dir => File.join(pwd, 'tmp/pids'),
9
+ :log_output => true,
10
+ :ARGV => [cmd]
11
+ }
12
+
13
+ Daemons.run_proc('requeus', opts) do
14
+ Requeus.config_path = File.join(pwd, 'config/requeus.yml')
15
+ Requeus.start_workers
16
+ end
17
+ end
18
+
19
+ namespace :requeus do
20
+ %w(start stop run).each do |cmd|
21
+ desc cmd
22
+ task cmd do
23
+ requeus_main cmd
24
+ end
25
+ end
26
+ end
data/requeus.gemspec ADDED
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{requeus}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ilia Ablamonov", "Anatoliy Plastinin", "Cloud Castle Inc."]
12
+ s.date = %q{2011-05-04}
13
+ s.description = %q{requeus gem is a library for proxying requests}
14
+ s.email = %q{antlypls@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "LICENSE.txt",
21
+ "README.rdoc",
22
+ "lib/requeus.rb",
23
+ "lib/requeus/adapter/filesystem.rb",
24
+ "lib/requeus/adapter/rabbit.rb",
25
+ "lib/requeus/adapter/s3.rb",
26
+ "lib/requeus/adapter/sqs.rb",
27
+ "lib/requeus/adapters.rb",
28
+ "lib/requeus/blob_store.rb",
29
+ "lib/requeus/impl.rb",
30
+ "lib/requeus/queue.rb",
31
+ "lib/requeus/railtie.rb",
32
+ "lib/requeus/request.rb",
33
+ "lib/requeus/server.rb",
34
+ "lib/tasks/requeus.rake",
35
+ "requeus.gemspec"
36
+ ]
37
+ s.homepage = %q{http://github.com/antlypls/requeus}
38
+ s.licenses = ["MIT"]
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = %q{1.4.2}
41
+ s.summary = %q{requeus}
42
+
43
+ if s.respond_to? :specification_version then
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<carrot>, ["~> 0.8.1"])
48
+ s.add_runtime_dependency(%q<aws>, ["~> 2.3.34"])
49
+ s.add_runtime_dependency(%q<daemons>, ["~> 1.0.10"])
50
+ s.add_runtime_dependency(%q<multipart-post>, ["~> 1.1.0"])
51
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
52
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
53
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
54
+ s.add_development_dependency(%q<rcov>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<carrot>, ["~> 0.8.1"])
57
+ s.add_dependency(%q<aws>, ["~> 2.3.34"])
58
+ s.add_dependency(%q<daemons>, ["~> 1.0.10"])
59
+ s.add_dependency(%q<multipart-post>, ["~> 1.1.0"])
60
+ s.add_dependency(%q<shoulda>, [">= 0"])
61
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
62
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
63
+ s.add_dependency(%q<rcov>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<carrot>, ["~> 0.8.1"])
67
+ s.add_dependency(%q<aws>, ["~> 2.3.34"])
68
+ s.add_dependency(%q<daemons>, ["~> 1.0.10"])
69
+ s.add_dependency(%q<multipart-post>, ["~> 1.1.0"])
70
+ s.add_dependency(%q<shoulda>, [">= 0"])
71
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
72
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
73
+ s.add_dependency(%q<rcov>, [">= 0"])
74
+ end
75
+ end
76
+
metadata ADDED
@@ -0,0 +1,208 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: requeus
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Ilia Ablamonov
14
+ - Anatoliy Plastinin
15
+ - Cloud Castle Inc.
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-05-04 00:00:00 +04:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ type: :runtime
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 61
31
+ segments:
32
+ - 0
33
+ - 8
34
+ - 1
35
+ version: 0.8.1
36
+ requirement: *id001
37
+ prerelease: false
38
+ name: carrot
39
+ - !ruby/object:Gem::Dependency
40
+ type: :runtime
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 71
47
+ segments:
48
+ - 2
49
+ - 3
50
+ - 34
51
+ version: 2.3.34
52
+ requirement: *id002
53
+ prerelease: false
54
+ name: aws
55
+ - !ruby/object:Gem::Dependency
56
+ type: :runtime
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 1
65
+ - 0
66
+ - 10
67
+ version: 1.0.10
68
+ requirement: *id003
69
+ prerelease: false
70
+ name: daemons
71
+ - !ruby/object:Gem::Dependency
72
+ type: :runtime
73
+ version_requirements: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ hash: 19
79
+ segments:
80
+ - 1
81
+ - 1
82
+ - 0
83
+ version: 1.1.0
84
+ requirement: *id004
85
+ prerelease: false
86
+ name: multipart-post
87
+ - !ruby/object:Gem::Dependency
88
+ type: :development
89
+ version_requirements: &id005 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirement: *id005
99
+ prerelease: false
100
+ name: shoulda
101
+ - !ruby/object:Gem::Dependency
102
+ type: :development
103
+ version_requirements: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ hash: 23
109
+ segments:
110
+ - 1
111
+ - 0
112
+ - 0
113
+ version: 1.0.0
114
+ requirement: *id006
115
+ prerelease: false
116
+ name: bundler
117
+ - !ruby/object:Gem::Dependency
118
+ type: :development
119
+ version_requirements: &id007 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ hash: 7
125
+ segments:
126
+ - 1
127
+ - 5
128
+ - 2
129
+ version: 1.5.2
130
+ requirement: *id007
131
+ prerelease: false
132
+ name: jeweler
133
+ - !ruby/object:Gem::Dependency
134
+ type: :development
135
+ version_requirements: &id008 !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirement: *id008
145
+ prerelease: false
146
+ name: rcov
147
+ description: requeus gem is a library for proxying requests
148
+ email: antlypls@gmail.com
149
+ executables: []
150
+
151
+ extensions: []
152
+
153
+ extra_rdoc_files:
154
+ - LICENSE.txt
155
+ - README.rdoc
156
+ files:
157
+ - LICENSE.txt
158
+ - README.rdoc
159
+ - lib/requeus.rb
160
+ - lib/requeus/adapter/filesystem.rb
161
+ - lib/requeus/adapter/rabbit.rb
162
+ - lib/requeus/adapter/s3.rb
163
+ - lib/requeus/adapter/sqs.rb
164
+ - lib/requeus/adapters.rb
165
+ - lib/requeus/blob_store.rb
166
+ - lib/requeus/impl.rb
167
+ - lib/requeus/queue.rb
168
+ - lib/requeus/railtie.rb
169
+ - lib/requeus/request.rb
170
+ - lib/requeus/server.rb
171
+ - lib/tasks/requeus.rake
172
+ - requeus.gemspec
173
+ has_rdoc: true
174
+ homepage: http://github.com/antlypls/requeus
175
+ licenses:
176
+ - MIT
177
+ post_install_message:
178
+ rdoc_options: []
179
+
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ hash: 3
188
+ segments:
189
+ - 0
190
+ version: "0"
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ none: false
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ hash: 3
197
+ segments:
198
+ - 0
199
+ version: "0"
200
+ requirements: []
201
+
202
+ rubyforge_project:
203
+ rubygems_version: 1.4.2
204
+ signing_key:
205
+ specification_version: 3
206
+ summary: requeus
207
+ test_files: []
208
+