falcon 0.34.5 → 0.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/Gemfile +2 -0
  4. data/bin/falcon +1 -1
  5. data/bin/falcon-host +1 -1
  6. data/examples/beer/config.ru +25 -23
  7. data/examples/beer/falcon.rb +2 -0
  8. data/examples/hello/config.ru +1 -1
  9. data/examples/hello/falcon.rb +14 -2
  10. data/examples/hello/preload.rb +6 -0
  11. data/examples/trailers/config.ru +33 -0
  12. data/examples/trailers/falcon.rb +7 -0
  13. data/falcon.gemspec +3 -1
  14. data/lib/falcon.rb +0 -4
  15. data/lib/falcon/adapters/response.rb +2 -2
  16. data/lib/falcon/command.rb +3 -53
  17. data/lib/falcon/command/host.rb +22 -39
  18. data/lib/falcon/command/paths.rb +45 -0
  19. data/lib/falcon/{host.rb → command/proxy.rb} +39 -45
  20. data/lib/falcon/command/redirect.rb +72 -0
  21. data/lib/falcon/command/serve.rb +28 -58
  22. data/lib/falcon/command/supervisor.rb +5 -5
  23. data/lib/falcon/command/top.rb +79 -0
  24. data/lib/falcon/command/virtual.rb +18 -53
  25. data/lib/falcon/configuration.rb +1 -1
  26. data/lib/falcon/{configurations/host.rb → configuration/application.rb} +13 -11
  27. data/lib/falcon/{configurations → configuration}/lets_encrypt_tls.rb +0 -0
  28. data/lib/falcon/{configurations → configuration}/proxy.rb +2 -2
  29. data/lib/falcon/{configurations → configuration}/rack.rb +2 -2
  30. data/lib/falcon/{configurations → configuration}/self_signed_tls.rb +0 -0
  31. data/lib/falcon/{configurations → configuration}/supervisor.rb +2 -2
  32. data/lib/falcon/{configurations → configuration}/tls.rb +0 -0
  33. data/lib/falcon/controller/host.rb +58 -0
  34. data/lib/falcon/controller/proxy.rb +102 -0
  35. data/lib/falcon/{service.rb → controller/redirect.rb} +37 -24
  36. data/lib/falcon/controller/serve.rb +112 -0
  37. data/lib/falcon/controller/virtual.rb +89 -0
  38. data/lib/falcon/middleware/proxy.rb +143 -0
  39. data/lib/falcon/{redirection.rb → middleware/redirect.rb} +31 -29
  40. data/lib/falcon/proxy_endpoint.rb +1 -1
  41. data/lib/falcon/service/application.rb +113 -0
  42. data/lib/falcon/service/generic.rb +53 -0
  43. data/lib/falcon/service/supervisor.rb +95 -0
  44. data/lib/falcon/services.rb +32 -5
  45. data/lib/falcon/version.rb +1 -1
  46. data/lib/rack/handler/falcon.rb +2 -1
  47. data/logo-square.afdesign +0 -0
  48. metadata +43 -17
  49. data/lib/falcon/hosts.rb +0 -135
  50. data/lib/falcon/proxy.rb +0 -141
  51. data/lib/falcon/supervisor.rb +0 -106
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f640e30a68a5dd3b923da93eafd29efde45370c6bad1c3cf92d0a43e11dd016
4
- data.tar.gz: 23cc00d9299c5d0ae67f9fa12746fc263c003f300b9d598048b46faf6064476c
3
+ metadata.gz: 5c3bb4c2f18d6b7005093348a0a91bb477ce212a286fef49179f8b3ad9f429b7
4
+ data.tar.gz: 7571194deea1618ee129e8e70361758b3af7eb843ef68669a6c1adc839ae756e
5
5
  SHA512:
6
- metadata.gz: 97e38f0048e75ca73ceb06c18a5bc80d66f8d9624216cd76a7fe7fac65444758f17dbffb28e10581d8c7b90a9e0c12ad6a17538efa4d994904699c135868c191
7
- data.tar.gz: 0da2a193a2f63ea1f48b7d328ae51b5745777fb688799347caf4697dfea233b6c5a09fa42207464d326c4bf052336eb932ac051d1016c49fa64efbccf4e794a4
6
+ metadata.gz: 5b152cd97f1460687e7c6672347c96e66771fd66fabbd65d5220005c50b5f067aec3d05594e07389752d4e1ef7e2526b384a15b6d9b17b3449222e99909b186b
7
+ data.tar.gz: 6d91a871d7b11010d3b4be9e9119346e401491ce087a8e0ee353b3eb9942e301136f1da02b92b3f575a4cc8d6b8d33b6dccc1fac03d49561ad330a44030990db
@@ -24,12 +24,13 @@ matrix:
24
24
  - rvm: 2.6
25
25
  gemfile: gems/rack3.gemfile
26
26
  - rvm: 2.6
27
- env: COVERAGE=Summary,Coveralls
27
+ env: COVERAGE=PartialSummary,Coveralls
28
+ - rvm: 2.7
28
29
  - rvm: truffleruby
29
30
  - rvm: jruby-head
30
31
  env: JRUBY_OPTS="--debug -X+O"
31
32
  - rvm: ruby-head
32
- - rvm: 2.6
33
+ - rvm: 2.7
33
34
  os: osx
34
35
  allow_failures:
35
36
  - rvm: truffleruby
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ # gem "async-container", path: "../async-container"
6
+
5
7
  group :development do
6
8
  gem 'ruby-prof', platform: :mri
7
9
  end
data/bin/falcon CHANGED
@@ -20,7 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require_relative '../lib/falcon'
23
+ require_relative '../lib/falcon/command'
24
24
 
25
25
  begin
26
26
  Falcon::Command.call
@@ -20,7 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require_relative '../lib/falcon'
23
+ require_relative '../lib/falcon/command/host'
24
24
 
25
25
  begin
26
26
  Falcon::Command::Host.call
@@ -23,31 +23,33 @@ run lambda {|env|
23
23
  body.write("<!DOCTYPE html><html><head><title>#{count} Bottles of Beer</title></head><body>")
24
24
 
25
25
  task.async do |task|
26
- body.write(COMMENT)
27
-
28
- count.downto(1) do |i|
29
- task.annotate "bottles of beer #{i}"
26
+ begin
27
+ body.write(COMMENT)
30
28
 
31
- Async.logger.info(body) {"#{bottles(i)} of beer on the wall..."}
32
- body.write("<p>#{bottles(i)} of beer on the wall, ")
33
- task.sleep(0.1)
34
- body.write("#{bottles(i)} of beer, ")
35
- task.sleep(0.1)
36
- body.write("take one down and pass it around, ")
37
- task.sleep(0.1)
38
- body.write("#{bottles(i-1)} of beer on the wall.</p>")
39
- task.sleep(0.1)
40
- body.write("<script>var child; while (child = document.body.firstChild) child.remove();</script>")
29
+ count.downto(1) do |i|
30
+ task.annotate "bottles of beer #{i}"
31
+
32
+ Async.logger.info(body) {"#{bottles(i)} of beer on the wall..."}
33
+ body.write("<p>#{bottles(i)} of beer on the wall, ")
34
+ task.sleep(0.1)
35
+ body.write("#{bottles(i)} of beer, ")
36
+ task.sleep(0.1)
37
+ body.write("take one down and pass it around, ")
38
+ task.sleep(0.1)
39
+ body.write("#{bottles(i-1)} of beer on the wall.</p>")
40
+ task.sleep(0.1)
41
+ body.write("<script>var child; while (child = document.body.firstChild) child.remove();</script>")
42
+ end
43
+
44
+ code = File.read(__FILE__)
45
+ body.write("<h1>Source Code</h1>")
46
+ body.write("<pre><code>#{CGI.escapeHTML code}</code></pre>")
47
+ body.write("</body></html>")
48
+ rescue
49
+ puts "Remote end closed connection: #{$!}"
50
+ ensure
51
+ body.close
41
52
  end
42
-
43
- code = File.read(__FILE__)
44
- body.write("<h1>Source Code</h1>")
45
- body.write("<pre><code>#{CGI.escapeHTML code}</code></pre>")
46
- body.write("</body></html>")
47
- rescue
48
- puts "Remote end closed connection: #{$!}"
49
- ensure
50
- body.close
51
53
  end
52
54
 
53
55
  [200, {'content-type' => 'text/html; charset=utf-8'}, body]
@@ -3,3 +3,5 @@
3
3
  load :rack, :self_signed_tls, :supervisor
4
4
 
5
5
  rack 'beer.localhost', :self_signed_tls
6
+
7
+ supervisor
@@ -8,7 +8,7 @@ class RequestLogger
8
8
  end
9
9
 
10
10
  def call(env)
11
- logger = Async.logger.with(level: :debug, name: "middleware")
11
+ logger = Async.logger.with(level: :debug)
12
12
 
13
13
  Async(logger: logger) do
14
14
  @app.call(env)
@@ -2,10 +2,22 @@
2
2
 
3
3
  load :rack, :self_signed_tls, :supervisor
4
4
 
5
- rack 'hello.localhost', :self_signed_tls
6
-
7
5
  supervisor
8
6
 
7
+ rack 'hello.localhost', :self_signed_tls do
8
+ # scheme 'http'
9
+ # protocol {Async::HTTP::Protocol::HTTP1}
10
+ #
11
+ # endpoint do
12
+ # Async::HTTP::Endpoint.for(scheme, "localhost", port: 9292, protocol: protocol)
13
+ # end
14
+
15
+ append preload "preload.rb"
16
+
17
+ # Process will connect to supervisor to report statistics periodically, otherwise it would be killed.
18
+ # report :supervisor
19
+ end
20
+
9
21
  # service 'jobs' do
10
22
  # shell ['rake', 'background:jobs:process']
11
23
  # end
@@ -0,0 +1,6 @@
1
+
2
+ if GC.respond_to?(:compact)
3
+ Async.logger.warn(self, "Compacting the mainframe...")
4
+ GC.compact
5
+ Async.logger.warn(self, "Compacting done...")
6
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env falcon --verbose serve -c
2
+
3
+ require 'async'
4
+
5
+ class RequestLogger
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ logger = Async.logger.with(level: :debug, name: "middleware")
12
+
13
+ Async(logger: logger) do
14
+ @app.call(env)
15
+ end.wait
16
+ end
17
+ end
18
+
19
+ use RequestLogger
20
+
21
+ run lambda {|env|
22
+ start_time = Async::Clock.now
23
+
24
+ server_timing = ->{
25
+ "app;dur=#{Async::Clock.now - start_time}"
26
+ }
27
+
28
+ [
29
+ 200,
30
+ [["trailers", "server-timing"], ["server-timing", server_timing]],
31
+ ["Hello World"]
32
+ ]
33
+ }
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env falcon-host
2
+
3
+ load :rack, :self_signed_tls, :supervisor
4
+
5
+ rack 'trailers.localhost', :self_signed_tls
6
+
7
+ supervisor
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "async", "~> 1.13"
23
23
  spec.add_dependency "async-io", "~> 1.22"
24
24
  spec.add_dependency "async-http", "~> 0.50.0"
25
- spec.add_dependency "async-container", "~> 0.14.0"
25
+ spec.add_dependency "async-container", "~> 0.16.0"
26
26
 
27
27
  spec.add_dependency "rack", ">= 1.0"
28
28
 
@@ -30,6 +30,8 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency 'localhost', "~> 1.1"
31
31
  spec.add_dependency 'build-environment', '~> 1.11'
32
32
 
33
+ spec.add_dependency 'process-metrics', '~> 0.1.0'
34
+
33
35
  spec.add_development_dependency "async-rspec", "~> 1.7"
34
36
  spec.add_development_dependency "async-websocket", "~> 0.12.0"
35
37
  spec.add_development_dependency "async-process", "~> 1.1"
@@ -18,8 +18,4 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative "falcon/command"
22
21
  require_relative "falcon/server"
23
-
24
- require_relative 'falcon/hosts'
25
- require_relative 'falcon/proxy'
@@ -20,7 +20,7 @@
20
20
 
21
21
  require_relative 'output'
22
22
  require_relative '../version'
23
- require_relative '../proxy'
23
+ require_relative '../middleware/proxy'
24
24
 
25
25
  require 'async/http/body/hijack'
26
26
  require 'time'
@@ -28,7 +28,7 @@ require 'time'
28
28
  module Falcon
29
29
  module Adapters
30
30
  class Response < ::Protocol::HTTP::Response
31
- IGNORE_HEADERS = Proxy::HOP_HEADERS
31
+ IGNORE_HEADERS = Middleware::Proxy::HOP_HEADERS
32
32
 
33
33
  # Append a list of newline encoded headers.
34
34
  def self.wrap_headers(fields)
@@ -18,62 +18,12 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'command/serve'
22
- require_relative 'command/virtual'
23
- require_relative 'command/host'
24
- require_relative 'command/supervisor'
25
-
26
- require_relative 'version'
27
-
28
- require 'samovar'
21
+ require_relative 'command/top'
29
22
 
30
23
  module Falcon
31
24
  module Command
32
- def self.call(*args)
33
- Top.call(*args)
34
- end
35
-
36
- class Top < Samovar::Command
37
- self.description = "An asynchronous HTTP server."
38
-
39
- options do
40
- option '--verbose | --quiet', "Verbosity of output for debugging.", key: :logging
41
- option '-h/--help', "Print out help information."
42
- option '-v/--version', "Print out the application version."
43
- end
44
-
45
- nested :command, {
46
- 'serve' => Serve,
47
- 'virtual' => Virtual,
48
- 'host' => Host,
49
- 'supervisor' => Supervisor
50
- }, default: 'serve'
51
-
52
- def verbose?
53
- @options[:logging] == :verbose
54
- end
55
-
56
- def quiet?
57
- @options[:logging] == :quiet
58
- end
59
-
60
- def call
61
- if verbose?
62
- Async.logger.debug!
63
- elsif quiet?
64
- Async.logger.warn!
65
- else
66
- Async.logger.info!
67
- end
68
-
69
- if @options[:version]
70
- puts "#{self.name} v#{Falcon::VERSION}"
71
- elsif @options[:help]
72
- self.print_usage
73
- else
74
- @command.call
75
- end
76
- end
25
+ def self.call(*arguments)
26
+ Top.call(*arguments)
77
27
  end
78
28
  end
79
29
  end
@@ -18,63 +18,46 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative '../server'
22
- require_relative '../endpoint'
21
+ require_relative '../controller/host'
23
22
  require_relative '../configuration'
24
- require_relative '../hosts'
25
- require_relative '../services'
26
-
27
- require 'async/container'
28
- require 'async/container/controller'
29
-
30
- require 'async/io/host_endpoint'
31
- require 'async/io/shared_endpoint'
32
- require 'async/io/ssl_endpoint'
33
23
 
34
24
  require 'samovar'
35
25
 
36
- require 'rack/builder'
37
- require 'rack/server'
38
-
39
26
  module Falcon
40
27
  module Command
41
28
  class Host < Samovar::Command
42
- self.description = "Run a specific virtual host."
29
+ self.description = "Host the specified applications."
43
30
 
44
- one :path, "A path specified if running from a script."
31
+ many :paths, "Service configuration paths.", default: ["falcon.rb"]
45
32
 
46
- def assume_privileges(path)
47
- stat = File.stat(path)
48
-
49
- Process::GID.change_privilege(stat.gid)
50
- Process::UID.change_privilege(stat.uid)
33
+ def container_class
34
+ Async::Container.best_container_class
51
35
  end
52
36
 
53
- def run(container, verbose = false)
37
+ def configuration(verbose = false)
54
38
  configuration = Configuration.new(verbose)
55
- configuration.load_file(@path)
56
-
57
- Async.logger.info(self) {"Starting services described by #{@path}..."}
58
-
59
- assume_privileges(@path)
60
39
 
61
- hosts = Hosts.new(configuration)
62
- hosts.each do |host|
63
- host.run(container)
40
+ @paths.each do |path|
41
+ path = File.expand_path(path)
42
+ configuration.load_file(path)
64
43
  end
65
44
 
66
- services = Services.new(configuration)
67
- services.each do |service|
68
- service.run(container)
69
- end
70
-
71
- return container
45
+ return configuration
72
46
  end
73
47
 
74
- def call(container = Async::Container.new)
75
- container = run(container, parent&.verbose?)
48
+ def controller
49
+ Controller::Host.new(self)
50
+ end
51
+
52
+ def call
53
+ Async.logger.info(self) do |buffer|
54
+ buffer.puts "Falcon Host v#{VERSION} taking flight!"
55
+ buffer.puts "- Configuration: #{@paths.join(', ')}"
56
+ buffer.puts "- To terminate: Ctrl-C or kill #{Process.pid}"
57
+ buffer.puts "- To reload all sites: kill -HUP #{Process.pid}"
58
+ end
76
59
 
77
- container.wait(true)
60
+ self.controller.run
78
61
  end
79
62
  end
80
63
  end
@@ -0,0 +1,45 @@
1
+ # Copyright, 2019, 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 '../configuration'
22
+
23
+ module Falcon
24
+ module Command
25
+ module Paths
26
+ def resolved_paths(&block)
27
+ @paths.collect do |path|
28
+ Dir.glob(path)
29
+ end.flatten.sort.uniq.each(&block)
30
+ end
31
+
32
+ def configuration
33
+ configuration = Configuration.new
34
+
35
+ self.resolved_paths.each do |path|
36
+ path = File.expand_path(path)
37
+
38
+ configuration.load_file(path)
39
+ end
40
+
41
+ return configuration
42
+ end
43
+ end
44
+ end
45
+ end