pakyow-core 0.11.3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +0 -0
  3. data/LICENSE +4 -0
  4. data/{pakyow-core/README.md → README.md} +3 -4
  5. data/commands/pakyow +13 -0
  6. data/lib/pakyow/app/connection/behavior/session.rb +33 -0
  7. data/lib/pakyow/app/connection/behavior/values.rb +42 -0
  8. data/lib/pakyow/app/connection/behavior/verifier.rb +34 -0
  9. data/lib/pakyow/app/connection/session/abstract.rb +24 -0
  10. data/lib/pakyow/app/connection/session/cookie.rb +56 -0
  11. data/lib/pakyow/app/connection.rb +57 -0
  12. data/lib/pakyow/app.rb +219 -0
  13. data/lib/pakyow/behavior/aspects.rb +45 -0
  14. data/lib/pakyow/behavior/config.rb +72 -0
  15. data/lib/pakyow/behavior/endpoints.rb +41 -0
  16. data/lib/pakyow/behavior/frameworks.rb +45 -0
  17. data/lib/pakyow/behavior/helpers.rb +107 -0
  18. data/lib/pakyow/behavior/initializers.rb +19 -0
  19. data/lib/pakyow/behavior/isolating.rb +69 -0
  20. data/lib/pakyow/behavior/operations.rb +46 -0
  21. data/lib/pakyow/behavior/pipeline.rb +58 -0
  22. data/lib/pakyow/behavior/plugins.rb +148 -0
  23. data/lib/pakyow/behavior/rescuing.rb +51 -0
  24. data/lib/pakyow/behavior/restarting.rb +68 -0
  25. data/lib/pakyow/behavior/sessions.rb +34 -0
  26. data/lib/pakyow/behavior/verification.rb +47 -0
  27. data/lib/pakyow/cli.rb +199 -0
  28. data/lib/pakyow/connection/multipart_input.rb +24 -0
  29. data/lib/pakyow/connection/multipart_parser.rb +112 -0
  30. data/lib/pakyow/connection/params.rb +29 -0
  31. data/lib/pakyow/connection/query_parser.rb +174 -0
  32. data/lib/pakyow/connection/statuses.rb +119 -0
  33. data/lib/pakyow/connection.rb +568 -0
  34. data/lib/pakyow/endpoints.rb +94 -0
  35. data/lib/pakyow/environment/actions/dispatch.rb +37 -0
  36. data/lib/pakyow/environment/actions/input_parser.rb +21 -0
  37. data/lib/pakyow/environment/actions/logger.rb +33 -0
  38. data/lib/pakyow/environment/actions/normalizer.rb +73 -0
  39. data/lib/pakyow/environment/behavior/config.rb +166 -0
  40. data/lib/pakyow/environment/behavior/initializers.rb +21 -0
  41. data/lib/pakyow/environment/behavior/input_parsing.rb +54 -0
  42. data/lib/pakyow/environment/behavior/plugins.rb +23 -0
  43. data/lib/pakyow/environment/behavior/restarting.rb +54 -0
  44. data/lib/pakyow/environment/behavior/running.rb +129 -0
  45. data/lib/pakyow/environment/behavior/silencing.rb +23 -0
  46. data/lib/pakyow/environment/behavior/timezone.rb +21 -0
  47. data/lib/pakyow/environment/behavior/watching.rb +75 -0
  48. data/lib/pakyow/environment.rb +381 -0
  49. data/lib/pakyow/error.rb +273 -0
  50. data/lib/pakyow/errors.rb +97 -0
  51. data/lib/pakyow/framework.rb +39 -0
  52. data/lib/pakyow/generator.rb +138 -0
  53. data/lib/pakyow/generators/project/default/%dot%env.erb +1 -0
  54. data/lib/pakyow/generators/project/default/%dot%gitignore +11 -0
  55. data/lib/pakyow/generators/project/default/%dot%ruby-version.erb +1 -0
  56. data/lib/pakyow/generators/project/default/Gemfile.erb +28 -0
  57. data/lib/pakyow/generators/project/default/README.md +14 -0
  58. data/lib/pakyow/generators/project/default/config/application.rb.erb +17 -0
  59. data/lib/pakyow/generators/project/default/config/environment.rb +11 -0
  60. data/lib/pakyow/generators/project/default/config/initializers/application/keep +0 -0
  61. data/lib/pakyow/generators/project/default/config/initializers/environment/keep +0 -0
  62. data/lib/pakyow/generators/project/default/database/keep +0 -0
  63. data/lib/pakyow/generators/project/default/frontend/assets/images/keep +0 -0
  64. data/lib/pakyow/generators/project/default/frontend/assets/packs/keep +0 -0
  65. data/lib/pakyow/generators/project/default/frontend/assets/styles/keep +0 -0
  66. data/lib/pakyow/generators/project/default/frontend/includes/keep +0 -0
  67. data/lib/pakyow/generators/project/default/frontend/layouts/default.html.erb +19 -0
  68. data/lib/pakyow/generators/project/default/frontend/pages/keep +0 -0
  69. data/lib/pakyow/generators/project/default/public/favicon.ico +0 -0
  70. data/lib/pakyow/generators/project/default/public/robots.txt +1 -0
  71. data/lib/pakyow/generators/project.rb +29 -0
  72. data/lib/pakyow/helpers/app.rb +28 -0
  73. data/lib/pakyow/helpers/connection.rb +45 -0
  74. data/lib/pakyow/info.rb +26 -0
  75. data/lib/pakyow/integrations/bootsnap.rb +18 -0
  76. data/lib/pakyow/integrations/bundler/require.rb +7 -0
  77. data/lib/pakyow/integrations/bundler/setup.rb +7 -0
  78. data/lib/pakyow/integrations/dotenv.rb +9 -0
  79. data/lib/pakyow/loader.rb +31 -0
  80. data/lib/pakyow/logger/colorizer.rb +38 -0
  81. data/lib/pakyow/logger/destination.rb +17 -0
  82. data/lib/pakyow/logger/formatter.rb +22 -0
  83. data/lib/pakyow/logger/formatters/human.rb +101 -0
  84. data/lib/pakyow/logger/formatters/json.rb +99 -0
  85. data/lib/pakyow/logger/formatters/logfmt.rb +50 -0
  86. data/lib/pakyow/logger/multiplexed.rb +19 -0
  87. data/lib/pakyow/logger/thread_local.rb +29 -0
  88. data/lib/pakyow/logger/timekeeper.rb +64 -0
  89. data/lib/pakyow/logger.rb +125 -0
  90. data/lib/pakyow/operation.rb +71 -0
  91. data/lib/pakyow/plugin/helper_caller.rb +20 -0
  92. data/lib/pakyow/plugin/lookup.rb +33 -0
  93. data/lib/pakyow/plugin/state.rb +68 -0
  94. data/lib/pakyow/plugin.rb +367 -0
  95. data/lib/pakyow/process_manager.rb +53 -0
  96. data/lib/pakyow/processes/proxy.rb +67 -0
  97. data/lib/pakyow/processes/server.rb +32 -0
  98. data/lib/pakyow/rack/compatibility.rb +68 -0
  99. data/lib/pakyow/task.rb +315 -0
  100. data/lib/pakyow/tasks/boot.rake +21 -0
  101. data/lib/pakyow/tasks/create.rake +32 -0
  102. data/lib/pakyow/tasks/help.rake +17 -0
  103. data/lib/pakyow/tasks/info/endpoints.rake +72 -0
  104. data/lib/pakyow/tasks/info.rake +31 -0
  105. data/lib/pakyow/tasks/irb.rake +11 -0
  106. data/lib/pakyow/tasks/prelaunch.rake +37 -0
  107. data/lib/pakyow/types.rb +32 -0
  108. data/lib/pakyow/validations/acceptance.rb +37 -0
  109. data/lib/pakyow/validations/email.rb +28 -0
  110. data/lib/pakyow/validations/inline.rb +32 -0
  111. data/lib/pakyow/validations/length.rb +44 -0
  112. data/lib/pakyow/validations/presence.rb +41 -0
  113. data/lib/pakyow/validations.rb +8 -0
  114. data/lib/pakyow/validator.rb +81 -0
  115. data/lib/pakyow/verifier.rb +177 -0
  116. data/lib/pakyow.rb +5 -0
  117. metadata +267 -65
  118. data/pakyow-core/CHANGELOG.md +0 -128
  119. data/pakyow-core/LICENSE +0 -20
  120. data/pakyow-core/lib/pakyow/core/app.rb +0 -82
  121. data/pakyow-core/lib/pakyow/core/app_context.rb +0 -10
  122. data/pakyow-core/lib/pakyow/core/base.rb +0 -61
  123. data/pakyow-core/lib/pakyow/core/call_context.rb +0 -171
  124. data/pakyow-core/lib/pakyow/core/config/app.rb +0 -49
  125. data/pakyow-core/lib/pakyow/core/config/cookies.rb +0 -4
  126. data/pakyow-core/lib/pakyow/core/config/logger.rb +0 -34
  127. data/pakyow-core/lib/pakyow/core/config/reloader.rb +0 -10
  128. data/pakyow-core/lib/pakyow/core/config/server.rb +0 -10
  129. data/pakyow-core/lib/pakyow/core/config/session.rb +0 -41
  130. data/pakyow-core/lib/pakyow/core/config.rb +0 -95
  131. data/pakyow-core/lib/pakyow/core/errors.rb +0 -16
  132. data/pakyow-core/lib/pakyow/core/helpers/configuring.rb +0 -142
  133. data/pakyow-core/lib/pakyow/core/helpers/hooks.rb +0 -106
  134. data/pakyow-core/lib/pakyow/core/helpers/running.rb +0 -124
  135. data/pakyow-core/lib/pakyow/core/helpers.rb +0 -61
  136. data/pakyow-core/lib/pakyow/core/loader.rb +0 -32
  137. data/pakyow-core/lib/pakyow/core/middleware/logger.rb +0 -146
  138. data/pakyow-core/lib/pakyow/core/middleware/override.rb +0 -3
  139. data/pakyow-core/lib/pakyow/core/middleware/reloader.rb +0 -23
  140. data/pakyow-core/lib/pakyow/core/middleware/req_path_normalizer.rb +0 -49
  141. data/pakyow-core/lib/pakyow/core/middleware/session.rb +0 -5
  142. data/pakyow-core/lib/pakyow/core/middleware/static.rb +0 -76
  143. data/pakyow-core/lib/pakyow/core/multilog.rb +0 -19
  144. data/pakyow-core/lib/pakyow/core/request.rb +0 -119
  145. data/pakyow-core/lib/pakyow/core/response.rb +0 -135
  146. data/pakyow-core/lib/pakyow/core/route_eval.rb +0 -254
  147. data/pakyow-core/lib/pakyow/core/route_expansion_eval.rb +0 -115
  148. data/pakyow-core/lib/pakyow/core/route_lookup.rb +0 -41
  149. data/pakyow-core/lib/pakyow/core/route_merger.rb +0 -76
  150. data/pakyow-core/lib/pakyow/core/route_module.rb +0 -21
  151. data/pakyow-core/lib/pakyow/core/route_set.rb +0 -74
  152. data/pakyow-core/lib/pakyow/core/route_template_defaults.rb +0 -43
  153. data/pakyow-core/lib/pakyow/core/route_template_eval.rb +0 -72
  154. data/pakyow-core/lib/pakyow/core/router.rb +0 -181
  155. data/pakyow-core/lib/pakyow/core.rb +0 -8
  156. data/pakyow-core/lib/pakyow-core.rb +0 -1
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pakyow
4
+ module Actions
5
+ # Sets up a connection logger and logs the prologue/epilogue.
6
+ #
7
+ class Logger
8
+ def call(connection, &block)
9
+ if silence?(connection)
10
+ connection.logger.silence do
11
+ call_with_logging(connection, &block)
12
+ end
13
+ else
14
+ call_with_logging(connection, &block)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def call_with_logging(connection)
21
+ connection.logger.prologue(connection)
22
+ yield
23
+ connection.logger.epilogue(connection)
24
+ end
25
+
26
+ def silence?(connection)
27
+ Pakyow.silencers.any? { |silencer|
28
+ silencer.call(connection)
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/core_refinements/string/normalization"
4
+
5
+ module Pakyow
6
+ module Actions
7
+ # Normalizes request uris, issuing a 301 redirect to the normalized uri.
8
+ #
9
+ class Normalizer
10
+ using Support::Refinements::String::Normalization
11
+
12
+ def call(connection)
13
+ if strict_www? && require_www? && !www?(connection) && !subdomain?(connection)
14
+ redirect!(connection, File.join(add_www(connection), connection.path))
15
+ elsif strict_www? && !require_www? && www?(connection)
16
+ redirect!(connection, File.join(remove_www(connection), connection.path))
17
+ elsif strict_path? && slash?(connection)
18
+ redirect!(connection, String.normalize_path(connection.path))
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def redirect!(connection, location)
25
+ connection.status = 301
26
+ connection.set_header("Location", location)
27
+ connection.halt
28
+ end
29
+
30
+ def add_www(connection)
31
+ "www.#{connection.authority}"
32
+ end
33
+
34
+ def remove_www(connection)
35
+ connection.authority.split(".", 2)[1]
36
+ end
37
+
38
+ def slash?(connection)
39
+ double_slash?(connection) || tail_slash?(connection)
40
+ end
41
+
42
+ def double_slash?(connection)
43
+ connection.path.include?("//")
44
+ end
45
+
46
+ TAIL_SLASH_REGEX = /(.)+(\/)+$/
47
+
48
+ def tail_slash?(connection)
49
+ !(TAIL_SLASH_REGEX =~ connection.path).nil?
50
+ end
51
+
52
+ def subdomain?(connection)
53
+ connection.host.count(".") > 1
54
+ end
55
+
56
+ def www?(connection)
57
+ connection.subdomain == "www"
58
+ end
59
+
60
+ def strict_path?
61
+ Pakyow.config.normalizer.strict_path == true
62
+ end
63
+
64
+ def strict_www?
65
+ Pakyow.config.normalizer.strict_www == true
66
+ end
67
+
68
+ def require_www?
69
+ Pakyow.config.normalizer.require_www == true
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ require "pakyow/logger/formatters/human"
6
+ require "pakyow/logger/formatters/logfmt"
7
+
8
+ module Pakyow
9
+ module Environment
10
+ module Behavior
11
+ module Config
12
+ extend Support::Extension
13
+
14
+ apply_extension do
15
+ setting :default_env, :development
16
+ setting :freeze_on_boot, true
17
+ setting :exit_on_boot_failure, true
18
+ setting :timezone, :utc
19
+ setting :connection_class do
20
+ require "pakyow/connection"
21
+ Connection
22
+ end
23
+
24
+ setting :root do
25
+ File.expand_path(".")
26
+ end
27
+
28
+ setting :lib do
29
+ File.join(config.root, "lib")
30
+ end
31
+
32
+ setting :environment_path do
33
+ File.join(config.root, "config/environment")
34
+ end
35
+
36
+ setting :loader_path do
37
+ File.join(config.root, "config/loader")
38
+ end
39
+
40
+ defaults :test do
41
+ setting :exit_on_boot_failure, false
42
+ end
43
+
44
+ configurable :server do
45
+ setting :host, "localhost"
46
+ setting :port, 3000
47
+ setting :count, 1
48
+ setting :proxy, true
49
+
50
+ defaults :production do
51
+ setting :proxy, false
52
+
53
+ setting :host do
54
+ ENV["HOST"] || "0.0.0.0"
55
+ end
56
+
57
+ setting :port do
58
+ ENV["PORT"] || 3000
59
+ end
60
+
61
+ setting :count do
62
+ ENV["WORKERS"] || 5
63
+ end
64
+ end
65
+ end
66
+
67
+ configurable :cli do
68
+ setting :repl do
69
+ require "irb"; IRB
70
+ end
71
+ end
72
+
73
+ configurable :logger do
74
+ setting :enabled, true
75
+ setting :sync, true
76
+
77
+ setting :level do
78
+ if config.logger.enabled
79
+ :debug
80
+ else
81
+ :off
82
+ end
83
+ end
84
+
85
+ setting :formatter do
86
+ Logger::Formatters::Human
87
+ end
88
+
89
+ setting :destinations do
90
+ if config.logger.enabled
91
+ { stdout: $stdout }
92
+ else
93
+ {}
94
+ end
95
+ end
96
+
97
+ defaults :test do
98
+ setting :enabled, false
99
+ end
100
+
101
+ defaults :production do
102
+ setting :level do
103
+ if config.logger.enabled
104
+ :info
105
+ else
106
+ :off
107
+ end
108
+ end
109
+
110
+ setting :formatter do
111
+ Logger::Formatters::Logfmt
112
+ end
113
+ end
114
+
115
+ defaults :ludicrous do
116
+ setting :enabled, false
117
+ end
118
+ end
119
+
120
+ configurable :normalizer do
121
+ setting :strict_path, true
122
+ setting :strict_www, false
123
+ setting :require_www, true
124
+ end
125
+
126
+ configurable :tasks do
127
+ setting :paths, ["./tasks", File.expand_path("../../../tasks", __FILE__)]
128
+ setting :prelaunch, []
129
+ end
130
+
131
+ configurable :redis do
132
+ configurable :connection do
133
+ setting :url do
134
+ ENV["REDIS_URL"] || "redis://127.0.0.1:6379"
135
+ end
136
+
137
+ setting :timeout, 5
138
+ setting :driver, nil
139
+ setting :id, nil
140
+ setting :tcp_keepalive, 5
141
+ setting :reconnect_attempts, 1
142
+ setting :inherit_socket, false
143
+ end
144
+
145
+ configurable :pool do
146
+ setting :size, 3
147
+ setting :timeout, 1
148
+ end
149
+
150
+ setting :key_prefix, "pw"
151
+ end
152
+
153
+ configurable :cookies do
154
+ setting :domain
155
+ setting :path, "/"
156
+ setting :max_age
157
+ setting :expires
158
+ setting :secure
159
+ setting :http_only
160
+ setting :same_site
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Environment
7
+ module Behavior
8
+ module Initializers
9
+ extend Support::Extension
10
+
11
+ apply_extension do
12
+ on "configure" do
13
+ Dir.glob(File.join(Pakyow.config.root, "config/initializers/environment/**/*.rb")).each do |initializer|
14
+ require initializer
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ require "pakyow/support/extension"
6
+ require "pakyow/support/indifferentize"
7
+
8
+ require "pakyow/connection/query_parser"
9
+ require "pakyow/connection/multipart_parser"
10
+
11
+ module Pakyow
12
+ module Environment
13
+ module Behavior
14
+ module InputParsing
15
+ extend Support::Extension
16
+ using Support::Indifferentize
17
+
18
+ apply_extension do
19
+ class_state :input_parsers, default: {}
20
+
21
+ on "configure" do
22
+ Pakyow.parse_input "application/x-www-form-urlencoded" do |input, connection|
23
+ connection.params.parse(input.read)
24
+ end
25
+
26
+ Pakyow.parse_input "multipart/form-data" do |input, connection|
27
+ Connection::MultipartParser.new(
28
+ connection.params, boundary: connection.type_params[:boundary]
29
+ ).parse(input)
30
+ end
31
+
32
+ Pakyow.parse_input "application/json" do |input, connection|
33
+ values = JSON.parse(input.read)
34
+
35
+ if values.is_a?(Hash)
36
+ values.deep_indifferentize.each do |key, value|
37
+ connection.params.add(key, value)
38
+ end
39
+ end
40
+
41
+ values
42
+ end
43
+ end
44
+ end
45
+
46
+ class_methods do
47
+ def parse_input(type, &block)
48
+ @input_parsers[type] = block
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Environment
7
+ module Behavior
8
+ module Plugins
9
+ extend Support::Extension
10
+
11
+ apply_extension do
12
+ class_state :plugins, default: {}
13
+ end
14
+
15
+ class_methods do
16
+ def register_plugin(plugin_name, plugin_module)
17
+ @plugins[plugin_name] = plugin_module
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Environment
7
+ module Behavior
8
+ module Restarting
9
+ extend Support::Extension
10
+
11
+ apply_extension do
12
+ on "run" do
13
+ @respawn = false
14
+
15
+ # Other processes (e.g. apps) can touch this file to restart the server.
16
+ #
17
+ watch "./tmp/restart.txt" do
18
+ restart
19
+ end
20
+
21
+ # Automatically bundle.
22
+ #
23
+ watch "./Gemfile" do
24
+ Bundler.with_clean_env do
25
+ Support::CLI::Runner.new(message: "Bundling").run("bundle install")
26
+ end
27
+ end
28
+
29
+ # Respawn when the bundle changes.
30
+ #
31
+ watch "./Gemfile.lock" do
32
+ respawn
33
+ end
34
+
35
+ # Respawn when something about the environment changes.
36
+ #
37
+ watch "#{Pakyow.config.environment_path}.rb" do
38
+ respawn
39
+ end
40
+ end
41
+ end
42
+
43
+ class_methods do
44
+ def respawn
45
+ # Set the respawn flag and stop the process manager.
46
+ # Pakyow will check the flag and respawn from the main thread.
47
+ #
48
+ @respawn = true; @process_manager.stop
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "async/reactor"
4
+ require "async/io/shared_endpoint"
5
+ require "async/http/endpoint"
6
+
7
+ require "pakyow/support/extension"
8
+
9
+ require "pakyow/process_manager"
10
+ require "pakyow/processes/proxy"
11
+ require "pakyow/processes/server"
12
+
13
+ module Pakyow
14
+ module Environment
15
+ module Behavior
16
+ module Running
17
+ extend Support::Extension
18
+
19
+ apply_extension do
20
+ unfreezable :process_manager
21
+
22
+ class_state :processes, default: []
23
+
24
+ on "run" do
25
+ if config.server.proxy
26
+ # Find a port to run the environment on, start the proxy on the configured port.
27
+ #
28
+ port = Processes::Proxy.find_local_port
29
+ process :proxy, restartable: false do
30
+ Processes::Proxy.new(
31
+ host: config.server.host,
32
+ port: config.server.port,
33
+ proxy_port: port
34
+ ).run
35
+ end
36
+ else
37
+ # Run the environment on the configured port.
38
+ #
39
+ port = config.server.port
40
+ end
41
+
42
+ endpoint = Async::HTTP::Endpoint.parse(
43
+ "http://#{config.server.host}:#{port}"
44
+ )
45
+
46
+ bound_endpoint = Async::Reactor.run {
47
+ Async::IO::SharedEndpoint.bound(endpoint)
48
+ }.wait
49
+
50
+ process :server, count: config.server.count do
51
+ Pakyow.config.server.port = port
52
+
53
+ Processes::Server.new(
54
+ protocol: endpoint.protocol,
55
+ scheme: endpoint.scheme,
56
+ endpoint: bound_endpoint
57
+ ).run
58
+ end
59
+
60
+ unless config.server.proxy || ENV.key?("PW_RESPAWN")
61
+ Pakyow.logger << Processes::Server.running_text(
62
+ scheme: endpoint.scheme, host: config.server.host, port: port
63
+ )
64
+ end
65
+ end
66
+ end
67
+
68
+ class_methods do
69
+ def process(name, count: 1, restartable: true, &block)
70
+ @processes << {
71
+ name: name,
72
+ block: block,
73
+ count: count,
74
+ restartable: restartable
75
+ }
76
+ end
77
+
78
+ def run
79
+ performing :run do
80
+ @process_manager = @processes.each_with_object(ProcessManager.new) { |process, manager|
81
+ manager.add(process)
82
+ }
83
+
84
+ root_pid = Process.pid
85
+
86
+ at_exit do
87
+ if Process.pid == root_pid
88
+ shutdown
89
+ else
90
+ @apps.select { |app|
91
+ app.respond_to?(:shutdown)
92
+ }.each(&:shutdown)
93
+ end
94
+ end
95
+ end
96
+
97
+ @process_manager.wait
98
+
99
+ if @respawn
100
+ # Replace the master process with a copy of itself.
101
+ #
102
+ exec "PW_RESPAWN=true #{$0} #{ARGV.join(" ")}"
103
+ end
104
+ rescue SignalException
105
+ exit
106
+ end
107
+
108
+ def shutdown
109
+ if $stdout.isatty
110
+ # Don't let ^C mess up our output.
111
+ #
112
+ puts
113
+ end
114
+
115
+ Pakyow.logger << "Goodbye"
116
+
117
+ performing :shutdown do
118
+ @process_manager.stop
119
+ end
120
+ end
121
+
122
+ def restart
123
+ @process_manager.restart
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Environment
7
+ module Behavior
8
+ module Silencing
9
+ extend Support::Extension
10
+
11
+ apply_extension do
12
+ class_state :silencers, default: []
13
+ end
14
+
15
+ class_methods do
16
+ def silence(&block)
17
+ @silencers << block
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Environment
7
+ module Behavior
8
+ # Sets up the timezone for the environment.
9
+ #
10
+ module Timezone
11
+ extend Support::Extension
12
+
13
+ apply_extension do
14
+ after "configure" do
15
+ ENV["TZ"] = config.timezone.to_s
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "filewatcher"
4
+
5
+ require "pakyow/support/extension"
6
+
7
+ module Pakyow
8
+ module Environment
9
+ module Behavior
10
+ module Watching
11
+ extend Support::Extension
12
+
13
+ apply_extension do
14
+ class_state :on_change_matchers, default: {}
15
+ class_state :watched_paths, default: []
16
+
17
+ unfreezable :filewatcher, :filewatcher_thread
18
+
19
+ after "run" do
20
+ @filewatcher = Filewatcher.new(
21
+ @watched_paths.map { |path|
22
+ File.expand_path(path)
23
+ }
24
+ )
25
+
26
+ @filewatcher_thread = Thread.new do
27
+ @filewatcher.watch(&method(:watch_callback))
28
+ end
29
+ end
30
+
31
+ on "shutdown" do
32
+ @filewatcher.stop
33
+ @filewatcher_thread.join
34
+ end
35
+ end
36
+
37
+ class_methods do
38
+ # Register a callback to be called when a file changes.
39
+ #
40
+ def on_change(matcher, &block)
41
+ (@on_change_matchers[matcher] ||= []) << block
42
+ end
43
+
44
+ # Register one or more path for changes.
45
+ #
46
+ def watch(*paths, &block)
47
+ @watched_paths.concat(paths).uniq!
48
+
49
+ if block
50
+ paths.each do |path|
51
+ on_change(File.expand_path(path), &block)
52
+ end
53
+ end
54
+ end
55
+
56
+ # @api private
57
+ def change_callbacks(path)
58
+ @on_change_matchers.each_with_object([]) { |(matcher, blocks), matched_blocks|
59
+ if matcher.match?(path)
60
+ matched_blocks.concat(blocks)
61
+ end
62
+ }
63
+ end
64
+
65
+ # @api private
66
+ def watch_callback(path, _event)
67
+ change_callbacks(path).each do |callback|
68
+ instance_exec(&callback)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end