falcon 0.34.5 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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