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 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
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --warnings
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ language: ruby
2
+ sudo: false
3
+ dist: trusty
4
+ cache: bundler
5
+ rvm:
6
+ - 2.0
7
+ - 2.1
8
+ - 2.2
9
+ - 2.3
10
+ - 2.4
11
+ - jruby-head
12
+ - ruby-head
13
+ - rbx-3
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: ruby-head
17
+ - rvm: jruby-head
18
+ - rvm: rbx-3
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in async-io.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'simplecov'
8
+ gem 'coveralls', require: false
9
+ end
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
- # encoding: utf-8
2
- require 'rake'
3
- require 'rake/testtask'
4
- require 'rake/rdoctask'
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
- desc 'Test the falcon plugin.'
11
- Rake::TestTask.new(:test) do |t|
12
- t.libs << 'lib'
13
- t.libs << 'test'
14
- t.pattern = 'test/**/*_test.rb'
15
- t.verbose = true
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
- desc 'Generate documentation for the falcon plugin.'
19
- Rake::RDocTask.new(:rdoc) do |rdoc|
20
- rdoc.rdoc_dir = 'rdoc'
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
- begin
28
- require 'jeweler'
29
- Jeweler::Tasks.new do |s|
30
- s.name = "falcon"
31
- s.version = Falcon::VERSION.dup
32
- s.summary = "Background video encoding"
33
- s.description = "Background video encoding via resque"
34
- s.email = "galeta.igor@gmail.com"
35
- s.homepage = "https://github.com/galetahub/falcon"
36
- s.authors = ["Igor Galeta", "Pavlo Galeta"]
37
- s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"] - %w(Gemfile Gemfile.lock)
38
- end
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
- module Falcon
2
- autoload :Profile, 'falcon/profile'
3
- autoload :Base, 'falcon/base'
4
- autoload :Encoder, 'falcon/encoder'
5
- autoload :Media, 'falcon/media'
6
-
7
- CONTENT_TYPES = [
8
- 'application/x-mp4',
9
- 'video/mpeg',
10
- 'video/quicktime',
11
- 'video/x-la-asf',
12
- 'video/x-ms-asf',
13
- 'video/x-msvideo',
14
- 'video/x-sgi-movie',
15
- 'video/x-flv',
16
- 'flv-application/octet-stream',
17
- 'application/octet-stream',
18
- 'video/3gpp',
19
- 'video/3gpp2',
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
- require 'falcon/profiles'
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