rity 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "awesome_print"
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Lars Gierth
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ Evented Fiber-aware Ruby webserver
2
+ ==================================
3
+
4
+ Rity is a lightweight Ruby webserver that runs inside an EventMachine loop and puts each request into a fiber.
5
+
6
+ TODO
7
+ ----
8
+
9
+ - Tests (!)
10
+ - Command Line Interface
11
+ - Logging
12
+ - Proxying via EM.enable_proxy
13
+ - Rack Handler
14
+ - Support for keep-alive connections
15
+ - Investigate MVM support in JRuby/Rubinius/MRI
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ Bundler.setup :default
3
+
4
+ task :default => :test
5
+
6
+ require "rake/testtask"
7
+ Rake::TestTask.new :test do |t|
8
+ t.test_files = FileList["test/*_test.rb"]
9
+ end
10
+
11
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rity/cli"
4
+ Rity::CLI.start
@@ -0,0 +1,4 @@
1
+ require "rity/connection"
2
+ require "rity/request"
3
+ require "rity/server"
4
+ require "rity/version"
@@ -0,0 +1,19 @@
1
+ require "rity"
2
+ require "thor"
3
+
4
+ module Rity
5
+ class CLI < Thor
6
+ map "--version" => :version, "-v" => :version
7
+
8
+ desc :version, "Print version information"
9
+ def version
10
+ say Rity::VERSION
11
+ end
12
+
13
+ desc :start, "Start an instance of Rity"
14
+ def start
15
+ server = Rity::Server.new
16
+ server.start
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ require "eventmachine"
2
+ require "hatetepe"
3
+
4
+ require "rity/request"
5
+
6
+ module Rity
7
+ class Connection < EM::Connection
8
+ def initialize(app)
9
+ @app = app
10
+ @requests = []
11
+ end
12
+
13
+ def post_init
14
+ request = nil
15
+ @parser = Hatetepe::Parser.new do |p|
16
+ p.on_request do |verb, url|
17
+ request = Request.new(@app, verb, url)
18
+ @requests.push(request)
19
+ request.callback &@responder.method(:resume)
20
+ end
21
+
22
+ p.on_header do |name, value|
23
+ request.add_header(name, value)
24
+ end
25
+
26
+ p.on_headers_complete do
27
+ request.precall
28
+ end
29
+
30
+ p.on_body_chunk do |chunk|
31
+ request.add_body_chunk(chunk)
32
+ end
33
+
34
+ p.on_complete do
35
+ request.call
36
+ end
37
+ end
38
+
39
+ @builder = Hatetepe::Builder.new do |b|
40
+ b.on_write &method(:send_data)
41
+
42
+ b.on_complete do
43
+ close_connection_after_writing if @requests.empty?
44
+ end
45
+ end
46
+
47
+ @responder = Fiber.new do
48
+ loop do
49
+ while @requests[0] && @requests[0].response
50
+ request = @requests.shift
51
+ @builder.response(request.response)
52
+ end
53
+ Fiber.yield
54
+ end
55
+ end
56
+ end
57
+
58
+ def receive_data(data)
59
+ @parser << data
60
+ rescue Exception
61
+ close_connection
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,63 @@
1
+ require "em/deferrable"
2
+ require "fiber"
3
+ require "stringio"
4
+
5
+ require "rack"
6
+ require "async-rack"
7
+
8
+ module Rity
9
+ class Request
10
+ include EM::Deferrable
11
+
12
+ attr_reader :app, :env, :response
13
+
14
+ def initialize(app, verb, url)
15
+ @app = app
16
+ @env = {
17
+ "REQUEST_METHOD" => verb,
18
+ "REQUEST_URI" => url,
19
+ "rack.input" => StringIO.new,
20
+ "async.callback" => method(:postcall)
21
+ }
22
+ end
23
+
24
+ def add_body_chunk(chunk)
25
+ env["rack.input"] << chunk
26
+ end
27
+
28
+ def add_header(name, value)
29
+ key = "HTTP_" + name.upcase.gsub("-", "_")
30
+ @env[key] = value
31
+ end
32
+
33
+ def precall
34
+ Fiber.new do
35
+ rescue_errors { app.precall(env) }
36
+ end.resume if app.respond_to?(:precall)
37
+ end
38
+
39
+ def call
40
+ env["rack.input"].close
41
+ env["rack.input"].rewind
42
+
43
+ Fiber.new do
44
+ rescue_errors { postcall(app.call(env)) }
45
+ end.resume
46
+ end
47
+
48
+ def postcall(response)
49
+ return if @response || response[0] < 0
50
+ @response = response
51
+ succeed
52
+ end
53
+
54
+ def rescue_errors
55
+ begin
56
+ yield
57
+ rescue Exception
58
+ postcall([500, {"Content-Type" => "text/html"},
59
+ ["<h1>#{Hatetepe::STATUS_CODES[500]}</h1>"]])
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ require "eventmachine"
2
+ require "em-synchrony"
3
+
4
+ require "rity/connection"
5
+
6
+ module Rity
7
+ class Server
8
+ def self.start(address, port, app)
9
+ EM.synchrony do
10
+ trap("INT") { EM.stop }
11
+ trap("TERM") { EM.stop }
12
+
13
+ EM.epoll
14
+
15
+ puts "Binding to #{address}:#{port}"
16
+ EM.start_server address, port, Connection, app
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Rity
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ require "bundler"
2
+ Bundler.setup :default
3
+
4
+ require "rity"
5
+ require "awesome_print"
6
+
7
+ class MyApp
8
+ def call(env)
9
+ raise "Error, Error!"
10
+
11
+ response = [200, {"Content-Type" => "text/html"}, ["Hello!"]]
12
+ return response
13
+
14
+ EM.add_timer(2) { env["async.callback"].call(response) }
15
+
16
+ [-1, {}, []]
17
+ end
18
+ end
19
+
20
+ Rity::Server.start "127.0.0.1", 3000, MyApp.new
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rity/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rity"
7
+ s.version = Rity::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Lars Gierth"]
10
+ s.email = ["lars.gierth@gmail.com"]
11
+ s.homepage = "https://github.com/lgierth/rity"
12
+ s.summary = %q{Evented Fiber-aware Ruby webserver}
13
+ s.description = %q{Rity is a lightweight Ruby webserver that runs inside an EventMachine loop and puts each request into a fiber.}
14
+
15
+ s.add_dependency "eventmachine"
16
+ s.add_dependency "em-synchrony"
17
+ s.add_dependency "hatetepe"
18
+ s.add_dependency "rack"
19
+ s.add_dependency "async-rack"
20
+ s.add_dependency "thor"
21
+
22
+ s.files = `git ls-files`.split("\n") - [".gitignore"]
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rity
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Lars Gierth
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-07 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: em-synchrony
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: hatetepe
39
+ requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: rack
50
+ requirement: &id004 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: async-rack
61
+ requirement: &id005 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: thor
72
+ requirement: &id006 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: *id006
81
+ description: Rity is a lightweight Ruby webserver that runs inside an EventMachine loop and puts each request into a fiber.
82
+ email:
83
+ - lars.gierth@gmail.com
84
+ executables:
85
+ - rity
86
+ extensions: []
87
+
88
+ extra_rdoc_files: []
89
+
90
+ files:
91
+ - Gemfile
92
+ - LICENSE
93
+ - README.md
94
+ - Rakefile
95
+ - bin/rity
96
+ - lib/rity.rb
97
+ - lib/rity/cli.rb
98
+ - lib/rity/connection.rb
99
+ - lib/rity/request.rb
100
+ - lib/rity/server.rb
101
+ - lib/rity/version.rb
102
+ - myapp.rb
103
+ - rity.gemspec
104
+ homepage: https://github.com/lgierth/rity
105
+ licenses: []
106
+
107
+ post_install_message:
108
+ rdoc_options: []
109
+
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: -1038596497
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: -1038596497
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ requirements: []
131
+
132
+ rubyforge_project:
133
+ rubygems_version: 1.8.2
134
+ signing_key:
135
+ specification_version: 3
136
+ summary: Evented Fiber-aware Ruby webserver
137
+ test_files: []
138
+