falcon 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +18 -0
- data/Gemfile +9 -0
- data/README.md +100 -0
- data/Rakefile +64 -36
- data/bin/falcon +28 -0
- data/falcon.gemspec +31 -0
- data/lib/falcon.rb +20 -57
- data/lib/falcon/command.rb +86 -0
- data/lib/falcon/server.rb +73 -0
- data/lib/falcon/version.rb +21 -1
- data/lib/rack/handler/falcon.rb +40 -0
- metadata +148 -77
- data/LICENSE +0 -19
- data/README.rdoc +0 -159
- data/app/models/falcon/encoding.rb +0 -5
- data/lib/falcon/base.rb +0 -98
- data/lib/falcon/encoder.rb +0 -235
- data/lib/falcon/engine.rb +0 -12
- data/lib/falcon/media.rb +0 -154
- data/lib/falcon/profile.rb +0 -96
- data/lib/falcon/profiles.rb +0 -9
- data/lib/generators/falcon/USAGE +0 -7
- data/lib/generators/falcon/install_generator.rb +0 -31
- data/lib/generators/falcon/templates/migrate/create_encodings.rb +0 -29
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b07f974b67bc387f25d6de874621983091f8f314
|
4
|
+
data.tar.gz: 6ba760b987d37bf8c33073b10dd1f68105d5ed4f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7651153688e68b7cb2062a5af88185ff8073c3d3d03e7ee0852772a1d1e1fdf82ebcad5d7f33077cb056ba8e60130609f7007240314df360841f13c867b5ae89
|
7
|
+
data.tar.gz: f6082bee731853ad813cb10f09db5187dea1ec369dc33636e18f92c9026c3d401dfe087eb66734d874e5d1584364f201cf0235e7fb2271ba028eda89cecccd99
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Falcon
|
2
|
+
|
3
|
+
A multi-process, multi-fiber Rack HTTP server built on top of [async], [async-io] and [async-http]. Each request is run within a light weight fiber and can block on up-stream requests without stalling the entire server process. Uses a multi-process model for handling blocking requests.
|
4
|
+
|
5
|
+
[![Build Status](https://secure.travis-ci.org/socketry/falcon.svg)](http://travis-ci.org/socketry/falcon)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/socketry/falcon.svg)](https://codeclimate.com/github/socketry/falcon)
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/socketry/falcon/badge.svg)](https://coveralls.io/r/socketry/falcon)
|
8
|
+
|
9
|
+
[async]: https://github.com/socketry/async
|
10
|
+
[async-io]: https://github.com/socketry/async-io
|
11
|
+
[async-http]: https://github.com/socketry/async-http
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'falcon'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install falcon
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
You can run `falcon` directly, and it will load the `config.ru` and start serving on port 8080.
|
32
|
+
|
33
|
+
### Integration with Guard
|
34
|
+
|
35
|
+
Falcon can restart very quickly and is ideal for use with guard. In your `Guardfile`:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
|
39
|
+
guard :falcon do
|
40
|
+
end
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
### Deploying with Passenger
|
45
|
+
|
46
|
+
You can run Falcon within Passenger to improve asyncronicity by using the `Falcon::Hijack` middleware. The first request from a client will be parsed by Passenger, but `rack.hijack` allows us to start parsing requests using Falcon within a separate `Async::Reactor` which reduces latency and avoids blocking IO where possible.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
|
50
|
+
if RACK_ENV == :production
|
51
|
+
use Falcon::Hijack
|
52
|
+
end
|
53
|
+
|
54
|
+
run MyApp
|
55
|
+
|
56
|
+
```
|
57
|
+
|
58
|
+
## Performance
|
59
|
+
|
60
|
+
Falcon is uses an asynchronous event-driven reactor to provide non-blocking IO. It can handle an arbitrary number of in-flight requests with minimal overhead per request.
|
61
|
+
|
62
|
+
It uses one Fiber per request, which yields in the presence of blocking IO.
|
63
|
+
|
64
|
+
### Memory Usage
|
65
|
+
|
66
|
+
Falcon uses a pre-fork model which loads the entire rack application before forking. This reduces per-process memory usage.
|
67
|
+
|
68
|
+
### Throughput
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
1. Fork it
|
73
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
74
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
75
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
76
|
+
5. Create new Pull Request
|
77
|
+
|
78
|
+
## License
|
79
|
+
|
80
|
+
Released under the MIT license.
|
81
|
+
|
82
|
+
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
83
|
+
|
84
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
85
|
+
of this software and associated documentation files (the "Software"), to deal
|
86
|
+
in the Software without restriction, including without limitation the rights
|
87
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
88
|
+
copies of the Software, and to permit persons to whom the Software is
|
89
|
+
furnished to do so, subject to the following conditions:
|
90
|
+
|
91
|
+
The above copyright notice and this permission notice shall be included in
|
92
|
+
all copies or substantial portions of the Software.
|
93
|
+
|
94
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
95
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
96
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
97
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
98
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
99
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
100
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,43 +1,71 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
|
4
|
-
|
5
|
-
require File.join(File.dirname(__FILE__), 'lib', 'falcon', 'version')
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:test)
|
6
5
|
|
7
|
-
desc 'Default: run unit tests.'
|
8
6
|
task :default => :test
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
8
|
+
task :server do
|
9
|
+
require 'async/reactor'
|
10
|
+
require 'async/http/server'
|
11
|
+
|
12
|
+
app = lambda do |env|
|
13
|
+
[200, {}, ["Hello World"]]
|
14
|
+
end
|
15
|
+
|
16
|
+
server = Async::HTTP::Server.new([
|
17
|
+
Async::IO::Address.tcp('127.0.0.1', 9294, reuse_port: true)
|
18
|
+
], app)
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
rdoc.title = 'Falcon'
|
22
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
-
rdoc.rdoc_files.include('README.rdoc')
|
24
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
20
|
+
Async::Reactor.run do
|
21
|
+
server.run
|
22
|
+
end
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
Jeweler::GemcutterTasks.new
|
41
|
-
rescue LoadError
|
42
|
-
puts "Jeweler not available. Install it with: gem install jeweler"
|
25
|
+
task :client do
|
26
|
+
require 'async/reactor'
|
27
|
+
require 'async/http/client'
|
28
|
+
|
29
|
+
client = Async::HTTP::Client.new([
|
30
|
+
Async::IO::Address.tcp('127.0.0.1', 9294, reuse_port: true)
|
31
|
+
])
|
32
|
+
|
33
|
+
Async::Reactor.run do
|
34
|
+
response = client.get("/")
|
35
|
+
|
36
|
+
puts response.inspect
|
37
|
+
end
|
43
38
|
end
|
39
|
+
|
40
|
+
task :wrk do
|
41
|
+
require 'async/reactor'
|
42
|
+
require 'async/http/server'
|
43
|
+
|
44
|
+
app = lambda do |env|
|
45
|
+
[200, {}, ["Hello World"]]
|
46
|
+
end
|
47
|
+
|
48
|
+
server = Async::HTTP::Server.new([
|
49
|
+
Async::IO::Address.tcp('127.0.0.1', 9294, reuse_port: true)
|
50
|
+
], app)
|
51
|
+
|
52
|
+
process_count = Etc.nprocessors
|
53
|
+
|
54
|
+
pids = process_count.times.collect do
|
55
|
+
fork do
|
56
|
+
Async::Reactor.run do
|
57
|
+
server.run
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
url = "http://127.0.0.1:9294/"
|
63
|
+
|
64
|
+
connections = process_count
|
65
|
+
system("wrk", "-c", connections.to_s, "-d", "2", "-t", connections.to_s, url)
|
66
|
+
|
67
|
+
pids.each do |pid|
|
68
|
+
Process.kill(:KILL, pid)
|
69
|
+
Process.wait pid
|
70
|
+
end
|
71
|
+
end
|
data/bin/falcon
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
require_relative '../lib/falcon'
|
24
|
+
|
25
|
+
begin
|
26
|
+
Falcon::Command.parse(ARGV).invoke
|
27
|
+
rescue Interrupt
|
28
|
+
end
|
data/falcon.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'lib/falcon/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "falcon"
|
6
|
+
spec.version = Falcon::VERSION
|
7
|
+
spec.authors = ["Samuel Williams"]
|
8
|
+
spec.email = ["samuel.williams@oriontransfer.co.nz"]
|
9
|
+
|
10
|
+
spec.summary = ""
|
11
|
+
spec.homepage = "https://github.com/socketry/falcon"
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
14
|
+
f.match(%r{^(test|spec|features)/})
|
15
|
+
end
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_dependency("async-http", "~> 0.2")
|
20
|
+
spec.add_dependency("async-container", "~> 0.1")
|
21
|
+
|
22
|
+
spec.add_dependency("rack", ">= 1.0")
|
23
|
+
|
24
|
+
spec.add_dependency('samovar', "~> 1.3")
|
25
|
+
|
26
|
+
spec.add_development_dependency "async-rspec", "~> 1.1"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.6"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
end
|
data/lib/falcon.rb
CHANGED
@@ -1,58 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
'video/3gpp-tt',
|
21
|
-
'video/BMPEG',
|
22
|
-
'video/BT656',
|
23
|
-
'video/CelB',
|
24
|
-
'video/DV',
|
25
|
-
'video/H261',
|
26
|
-
'video/H263',
|
27
|
-
'video/H263-1998',
|
28
|
-
'video/H263-2000',
|
29
|
-
'video/H264',
|
30
|
-
'video/JPEG',
|
31
|
-
'video/MJ2',
|
32
|
-
'video/MP1S',
|
33
|
-
'video/MP2P',
|
34
|
-
'video/MP2T',
|
35
|
-
'video/mp4',
|
36
|
-
'video/MP4V-ES',
|
37
|
-
'video/MPV',
|
38
|
-
'video/mpeg4',
|
39
|
-
'video/mpeg4-generic',
|
40
|
-
'video/nv',
|
41
|
-
'video/parityfec',
|
42
|
-
'video/pointer',
|
43
|
-
'video/raw',
|
44
|
-
'video/rtx',
|
45
|
-
'video/x-matroska',
|
46
|
-
'video/x-ms-wmv',
|
47
|
-
'video/divxplus',
|
48
|
-
'video/avi',
|
49
|
-
'video/divx',
|
50
|
-
'video/vnd.objectvideo' ]
|
51
|
-
|
52
|
-
def self.table_name_prefix
|
53
|
-
'falcon_'
|
54
|
-
end
|
55
|
-
end
|
1
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
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.
|
56
20
|
|
57
|
-
|
58
|
-
require 'falcon/engine'
|
21
|
+
require_relative "falcon/command"
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
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.
|
20
|
+
|
21
|
+
require_relative 'server'
|
22
|
+
|
23
|
+
require 'async/container'
|
24
|
+
|
25
|
+
require 'samovar'
|
26
|
+
require 'etc'
|
27
|
+
|
28
|
+
require 'rack/builder'
|
29
|
+
require 'rack/server'
|
30
|
+
|
31
|
+
module Falcon
|
32
|
+
module Command
|
33
|
+
def self.parse(*args)
|
34
|
+
Top.parse(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
class Serve < Samovar::Command
|
38
|
+
self.description = "Run an HTTP server."
|
39
|
+
|
40
|
+
options do
|
41
|
+
option '-c/--config <path>', "Rackup configuration file to load", default: 'config.ru'
|
42
|
+
option '-n/--concurrency <count>', "Number of processes to start", default: Etc.nprocessors, type: Integer
|
43
|
+
|
44
|
+
option '-b/--bind <address>', "Bind to the given hostname/address", default: "tcp://localhost:9292"
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
app, options = Rack::Builder.parse_file(@options[:config])
|
49
|
+
|
50
|
+
Async::Container.new(concurrency: @options[:concurrency]) do
|
51
|
+
server = Falcon::Server.new(app, [
|
52
|
+
Async::IO::Address.parse(@options[:bind], reuse_port: true)
|
53
|
+
])
|
54
|
+
|
55
|
+
server.run
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def invoke
|
60
|
+
run
|
61
|
+
|
62
|
+
sleep
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Top < Samovar::Command
|
67
|
+
self.description = "An asynchronous HTTP client/server toolset."
|
68
|
+
|
69
|
+
nested '<command>',
|
70
|
+
'serve' => Serve
|
71
|
+
# 'get' => Get
|
72
|
+
# 'post' => Post
|
73
|
+
# 'head' => Head,
|
74
|
+
# 'put' => Put,
|
75
|
+
# 'delete' => Delete
|
76
|
+
|
77
|
+
def invoke(program_name: File.basename($0))
|
78
|
+
if @command
|
79
|
+
@command.invoke
|
80
|
+
else
|
81
|
+
print_usage(program_name)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|