yup 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "eventmachine"
4
+ gem "em-http-request"
5
+ gem "http_parser.rb"
6
+
7
+ group :development do
8
+ gem "shoulda", ">= 0"
9
+ gem "yard", "~> 0.6.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.6)
5
+ em-http-request (0.3.0)
6
+ addressable (>= 2.0.0)
7
+ escape_utils
8
+ eventmachine (>= 0.12.9)
9
+ escape_utils (0.2.3)
10
+ eventmachine (0.12.10)
11
+ git (1.2.5)
12
+ http_parser.rb (0.5.1)
13
+ jeweler (1.5.2)
14
+ bundler (~> 1.0.0)
15
+ git (>= 1.2.5)
16
+ rake
17
+ rake (0.9.2)
18
+ rcov (0.9.10)
19
+ shoulda (2.11.3)
20
+ yard (0.6.8)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler (~> 1.0.0)
27
+ em-http-request
28
+ eventmachine
29
+ http_parser.rb
30
+ jeweler (~> 1.5.2)
31
+ rcov
32
+ shoulda
33
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Denis Sukhonin
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,44 @@
1
+ = yup daemon
2
+
3
+ This is the small daemon for transparent asynchronous delegating HTTP requests when response is known or unimportant.
4
+
5
+ When a http request is arrived the yup daemon (yupd) answers to the client configured answer (by default 200 OK). Then the yupd forwards the http request to the specified host and retries if a timeout error was happend.
6
+
7
+ == On of use cases
8
+
9
+ For example we can have a rails app which send exceptions to an errbit by the gem hoptoad_notifier. We know the errbit can be not available by network issues or some else reasons, but we do not want lose exceptions. To resolve this problem we can start yupd on the same host with the rails app:
10
+ yupd --listen localhost:8081 --status-code 201 errbit.host.somewhere
11
+
12
+ Reconfiguration of hoptoad_notifier is very ease:
13
+ HoptoadNotifier.configure do |config|
14
+ config.host = "localhost" # yupd host
15
+ config.port = 8081 # yupd port
16
+ config.api_key = "api_key_for_your_app"
17
+ end
18
+
19
+ Now problem of availability of errbit is assigned to the yupd.
20
+
21
+ == Roadmap to 0.1
22
+
23
+ * Daemonize
24
+ * Logger
25
+ * Preforking
26
+ * Persistent HTTP requests queue
27
+ * A configurable map of different delegating rules
28
+ * Tests...
29
+
30
+ == Contributing to yup
31
+
32
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
33
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
34
+ * Fork the project
35
+ * Start a feature/bugfix branch
36
+ * Commit and push until you are happy with your contribution
37
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
38
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
39
+
40
+ == Copyright
41
+
42
+ Copyright (c) 2011 Denis Sukhonin. See LICENSE.txt for
43
+ further details.
44
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "yup"
16
+ gem.homepage = "http://github.com/neglectedvalue/yup"
17
+ gem.license = "MIT"
18
+ gem.summary = "Asynchronous HTTP delegate"
19
+ gem.description = "Just answers 200 (or specified) to a client and asynchronously forwards HTTP request to a configured host"
20
+ gem.email = "d.sukhonin@gmail.com"
21
+ gem.authors = ["Denis Sukhonin"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
data/bin/yupd ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+
4
+ require 'getoptlong'
5
+
6
+ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
7
+ require 'yup'
8
+
9
+ def usage
10
+ puts <<-EOF
11
+ Usage: #{$0} [OPTION] ... FORWARD_TO_HOST
12
+
13
+ Options:
14
+ -h, --help Show help
15
+ --listen <host:port>, -l Listen on an address (default localhost:8080)
16
+ --status-code <code> Send status code to a client on request (default 200)
17
+ --resend-delay <seconds> Resend failed requests in seconds (default 5.0)
18
+
19
+ Examples:
20
+ yupd --listen 0.0.0.0:8081 --status-code 201 errbit.host.somewhere
21
+
22
+ EOF
23
+ end
24
+
25
+ opts = GetoptLong.new(
26
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
27
+ ['--listen', '-l', GetoptLong::REQUIRED_ARGUMENT],
28
+ ['--status-code', GetoptLong::REQUIRED_ARGUMENT],
29
+ ['--resend-delay', '-d', GetoptLong::REQUIRED_ARGUMENT],
30
+ )
31
+ config = {}
32
+ opts.each do |opt, arg|
33
+ case opt
34
+ when '--help', '-h'
35
+ usage
36
+ exit 0
37
+ when '--listen', '-l'
38
+ config[:listen_host], config[:listen_port] = arg.split(':')
39
+ when '--resend-delay', '-d'
40
+ config[:resend_delay] = arg.to_f
41
+ when '--status-code'
42
+ config[:status_code] = arg.to_i
43
+ end
44
+ end
45
+
46
+ if ARGV.length != 1
47
+ puts "Missing host argument (try --help)"
48
+ usage
49
+ exit 1
50
+ end
51
+
52
+ config[:forward_to] = ARGV.shift
53
+
54
+ Yup.resend_delay = config[:resend_delay] if config.has_key?(:resend_delay)
55
+ Yup.run(config)
@@ -0,0 +1,39 @@
1
+ require 'em-http-request'
2
+
3
+ module Yup
4
+ class RequestForwarder
5
+ def initialize(parser, body, forward_to)
6
+ @parser = parser
7
+ @body = body
8
+ @forward_to = forward_to
9
+ end
10
+
11
+ def run
12
+ http_method = @parser.http_method.downcase.to_sym
13
+ http_url = "http://#{@forward_to}#{@parser.request_url}"
14
+ http = EventMachine::HttpRequest.
15
+ new(http_url).
16
+ send(http_method,
17
+ :head => @parser.headers.merge('Host' => @forward_to),
18
+ :body => @body)
19
+
20
+ http.callback do
21
+ if http.response_header.status / 100 == 2
22
+ puts '--- SUCCESS'
23
+ else
24
+ puts '--- FAIL'
25
+ # puts http.response_header.inspect
26
+ # puts http.response
27
+ p http
28
+ end
29
+ end
30
+
31
+ http.errback do
32
+ puts '--- ERROR'
33
+ p http
34
+
35
+ EventMachine.add_timer(Yup.resend_delay) { self.run }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ require 'webrick'
2
+ require 'http/parser'
3
+
4
+ module Yup
5
+ class RequestHandler < EM::Connection
6
+ attr_reader :queue
7
+
8
+ def initialize(forward_to, status_code)
9
+ @forward_to = forward_to
10
+ @status_code = status_code
11
+ @chunks = []
12
+ end
13
+
14
+ def post_init
15
+ @parser = Http::Parser.new(self)
16
+ end
17
+
18
+ def receive_data(data)
19
+ @parser << data
20
+ end
21
+
22
+ def on_message_begin
23
+ @body = ''
24
+ end
25
+
26
+ def on_body(chunk)
27
+ @body << chunk
28
+ end
29
+
30
+ def on_message_complete
31
+ puts '-- got request'
32
+ p @parser.http_version
33
+ p @parser.http_method # for requests
34
+ p @parser.request_url
35
+ p @parser.headers
36
+
37
+ resp = WEBrick::HTTPResponse.new(:HTTPVersion => '1.1')
38
+ resp.status = @status_code
39
+ resp['Server'] = 'yupd'
40
+ send_data resp.to_s
41
+
42
+ EventMachine.next_tick do
43
+ RequestForwarder.new(@parser, @body, @forward_to).run
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/yup.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+
4
+ require 'yup/request_forwarder'
5
+ require 'yup/request_handler'
6
+
7
+ module Yup
8
+ @@resend_delay = 5.0
9
+ def self.resend_delay
10
+ @@resend_delay
11
+ end
12
+ def self.resend_delay=(seconds)
13
+ @@resend_delay = seconds
14
+ end
15
+
16
+ def self.run(config)
17
+ host = config[:listen_host] || 'localhost'
18
+ port = config[:listen_port] || 8080
19
+ status_code = config[:status_code] || 200
20
+ forward_to = config[:forward_to]
21
+
22
+ EventMachine::run do
23
+ EventMachine::start_server(host, port, RequestHandler,
24
+ forward_to, status_code)
25
+ puts "listening on #{host}:#{port}"
26
+ end
27
+ end
28
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'yup'
16
+
17
+ class Test::Unit::TestCase
18
+ end
data/test/test_yup.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestYup < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yup
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 0
9
+ version: 0.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Denis Sukhonin
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-08 00:00:00 +04:00
18
+ default_executable: yupd
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: eventmachine
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: em-http-request
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: http_parser.rb
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: shoulda
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: *id004
72
+ - !ruby/object:Gem::Dependency
73
+ name: yard
74
+ requirement: &id005 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ - 6
82
+ - 0
83
+ version: 0.6.0
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: *id005
87
+ - !ruby/object:Gem::Dependency
88
+ name: bundler
89
+ requirement: &id006 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 1
96
+ - 0
97
+ - 0
98
+ version: 1.0.0
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *id006
102
+ - !ruby/object:Gem::Dependency
103
+ name: jeweler
104
+ requirement: &id007 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ segments:
110
+ - 1
111
+ - 5
112
+ - 2
113
+ version: 1.5.2
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: *id007
117
+ - !ruby/object:Gem::Dependency
118
+ name: rcov
119
+ requirement: &id008 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ type: :development
128
+ prerelease: false
129
+ version_requirements: *id008
130
+ description: Just answers 200 (or specified) to a client and asynchronously forwards HTTP request to a configured host
131
+ email: d.sukhonin@gmail.com
132
+ executables:
133
+ - yupd
134
+ extensions: []
135
+
136
+ extra_rdoc_files:
137
+ - LICENSE.txt
138
+ - README.rdoc
139
+ files:
140
+ - .document
141
+ - Gemfile
142
+ - Gemfile.lock
143
+ - LICENSE.txt
144
+ - README.rdoc
145
+ - Rakefile
146
+ - VERSION
147
+ - bin/yupd
148
+ - lib/yup.rb
149
+ - lib/yup/request_forwarder.rb
150
+ - lib/yup/request_handler.rb
151
+ - test/helper.rb
152
+ - test/test_yup.rb
153
+ has_rdoc: true
154
+ homepage: http://github.com/neglectedvalue/yup
155
+ licenses:
156
+ - MIT
157
+ post_install_message:
158
+ rdoc_options: []
159
+
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ hash: -969212524035482496
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ segments:
177
+ - 0
178
+ version: "0"
179
+ requirements: []
180
+
181
+ rubyforge_project:
182
+ rubygems_version: 1.3.7
183
+ signing_key:
184
+ specification_version: 3
185
+ summary: Asynchronous HTTP delegate
186
+ test_files:
187
+ - test/helper.rb
188
+ - test/test_yup.rb