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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +0 -0
- data/LICENSE +4 -0
- data/{pakyow-core/README.md → README.md} +3 -4
- data/commands/pakyow +13 -0
- data/lib/pakyow/app/connection/behavior/session.rb +33 -0
- data/lib/pakyow/app/connection/behavior/values.rb +42 -0
- data/lib/pakyow/app/connection/behavior/verifier.rb +34 -0
- data/lib/pakyow/app/connection/session/abstract.rb +24 -0
- data/lib/pakyow/app/connection/session/cookie.rb +56 -0
- data/lib/pakyow/app/connection.rb +57 -0
- data/lib/pakyow/app.rb +219 -0
- data/lib/pakyow/behavior/aspects.rb +45 -0
- data/lib/pakyow/behavior/config.rb +72 -0
- data/lib/pakyow/behavior/endpoints.rb +41 -0
- data/lib/pakyow/behavior/frameworks.rb +45 -0
- data/lib/pakyow/behavior/helpers.rb +107 -0
- data/lib/pakyow/behavior/initializers.rb +19 -0
- data/lib/pakyow/behavior/isolating.rb +69 -0
- data/lib/pakyow/behavior/operations.rb +46 -0
- data/lib/pakyow/behavior/pipeline.rb +58 -0
- data/lib/pakyow/behavior/plugins.rb +148 -0
- data/lib/pakyow/behavior/rescuing.rb +51 -0
- data/lib/pakyow/behavior/restarting.rb +68 -0
- data/lib/pakyow/behavior/sessions.rb +34 -0
- data/lib/pakyow/behavior/verification.rb +47 -0
- data/lib/pakyow/cli.rb +199 -0
- data/lib/pakyow/connection/multipart_input.rb +24 -0
- data/lib/pakyow/connection/multipart_parser.rb +112 -0
- data/lib/pakyow/connection/params.rb +29 -0
- data/lib/pakyow/connection/query_parser.rb +174 -0
- data/lib/pakyow/connection/statuses.rb +119 -0
- data/lib/pakyow/connection.rb +568 -0
- data/lib/pakyow/endpoints.rb +94 -0
- data/lib/pakyow/environment/actions/dispatch.rb +37 -0
- data/lib/pakyow/environment/actions/input_parser.rb +21 -0
- data/lib/pakyow/environment/actions/logger.rb +33 -0
- data/lib/pakyow/environment/actions/normalizer.rb +73 -0
- data/lib/pakyow/environment/behavior/config.rb +166 -0
- data/lib/pakyow/environment/behavior/initializers.rb +21 -0
- data/lib/pakyow/environment/behavior/input_parsing.rb +54 -0
- data/lib/pakyow/environment/behavior/plugins.rb +23 -0
- data/lib/pakyow/environment/behavior/restarting.rb +54 -0
- data/lib/pakyow/environment/behavior/running.rb +129 -0
- data/lib/pakyow/environment/behavior/silencing.rb +23 -0
- data/lib/pakyow/environment/behavior/timezone.rb +21 -0
- data/lib/pakyow/environment/behavior/watching.rb +75 -0
- data/lib/pakyow/environment.rb +381 -0
- data/lib/pakyow/error.rb +273 -0
- data/lib/pakyow/errors.rb +97 -0
- data/lib/pakyow/framework.rb +39 -0
- data/lib/pakyow/generator.rb +138 -0
- data/lib/pakyow/generators/project/default/%dot%env.erb +1 -0
- data/lib/pakyow/generators/project/default/%dot%gitignore +11 -0
- data/lib/pakyow/generators/project/default/%dot%ruby-version.erb +1 -0
- data/lib/pakyow/generators/project/default/Gemfile.erb +28 -0
- data/lib/pakyow/generators/project/default/README.md +14 -0
- data/lib/pakyow/generators/project/default/config/application.rb.erb +17 -0
- data/lib/pakyow/generators/project/default/config/environment.rb +11 -0
- data/lib/pakyow/generators/project/default/config/initializers/application/keep +0 -0
- data/lib/pakyow/generators/project/default/config/initializers/environment/keep +0 -0
- data/lib/pakyow/generators/project/default/database/keep +0 -0
- data/lib/pakyow/generators/project/default/frontend/assets/images/keep +0 -0
- data/lib/pakyow/generators/project/default/frontend/assets/packs/keep +0 -0
- data/lib/pakyow/generators/project/default/frontend/assets/styles/keep +0 -0
- data/lib/pakyow/generators/project/default/frontend/includes/keep +0 -0
- data/lib/pakyow/generators/project/default/frontend/layouts/default.html.erb +19 -0
- data/lib/pakyow/generators/project/default/frontend/pages/keep +0 -0
- data/lib/pakyow/generators/project/default/public/favicon.ico +0 -0
- data/lib/pakyow/generators/project/default/public/robots.txt +1 -0
- data/lib/pakyow/generators/project.rb +29 -0
- data/lib/pakyow/helpers/app.rb +28 -0
- data/lib/pakyow/helpers/connection.rb +45 -0
- data/lib/pakyow/info.rb +26 -0
- data/lib/pakyow/integrations/bootsnap.rb +18 -0
- data/lib/pakyow/integrations/bundler/require.rb +7 -0
- data/lib/pakyow/integrations/bundler/setup.rb +7 -0
- data/lib/pakyow/integrations/dotenv.rb +9 -0
- data/lib/pakyow/loader.rb +31 -0
- data/lib/pakyow/logger/colorizer.rb +38 -0
- data/lib/pakyow/logger/destination.rb +17 -0
- data/lib/pakyow/logger/formatter.rb +22 -0
- data/lib/pakyow/logger/formatters/human.rb +101 -0
- data/lib/pakyow/logger/formatters/json.rb +99 -0
- data/lib/pakyow/logger/formatters/logfmt.rb +50 -0
- data/lib/pakyow/logger/multiplexed.rb +19 -0
- data/lib/pakyow/logger/thread_local.rb +29 -0
- data/lib/pakyow/logger/timekeeper.rb +64 -0
- data/lib/pakyow/logger.rb +125 -0
- data/lib/pakyow/operation.rb +71 -0
- data/lib/pakyow/plugin/helper_caller.rb +20 -0
- data/lib/pakyow/plugin/lookup.rb +33 -0
- data/lib/pakyow/plugin/state.rb +68 -0
- data/lib/pakyow/plugin.rb +367 -0
- data/lib/pakyow/process_manager.rb +53 -0
- data/lib/pakyow/processes/proxy.rb +67 -0
- data/lib/pakyow/processes/server.rb +32 -0
- data/lib/pakyow/rack/compatibility.rb +68 -0
- data/lib/pakyow/task.rb +315 -0
- data/lib/pakyow/tasks/boot.rake +21 -0
- data/lib/pakyow/tasks/create.rake +32 -0
- data/lib/pakyow/tasks/help.rake +17 -0
- data/lib/pakyow/tasks/info/endpoints.rake +72 -0
- data/lib/pakyow/tasks/info.rake +31 -0
- data/lib/pakyow/tasks/irb.rake +11 -0
- data/lib/pakyow/tasks/prelaunch.rake +37 -0
- data/lib/pakyow/types.rb +32 -0
- data/lib/pakyow/validations/acceptance.rb +37 -0
- data/lib/pakyow/validations/email.rb +28 -0
- data/lib/pakyow/validations/inline.rb +32 -0
- data/lib/pakyow/validations/length.rb +44 -0
- data/lib/pakyow/validations/presence.rb +41 -0
- data/lib/pakyow/validations.rb +8 -0
- data/lib/pakyow/validator.rb +81 -0
- data/lib/pakyow/verifier.rb +177 -0
- data/lib/pakyow.rb +5 -0
- metadata +267 -65
- data/pakyow-core/CHANGELOG.md +0 -128
- data/pakyow-core/LICENSE +0 -20
- data/pakyow-core/lib/pakyow/core/app.rb +0 -82
- data/pakyow-core/lib/pakyow/core/app_context.rb +0 -10
- data/pakyow-core/lib/pakyow/core/base.rb +0 -61
- data/pakyow-core/lib/pakyow/core/call_context.rb +0 -171
- data/pakyow-core/lib/pakyow/core/config/app.rb +0 -49
- data/pakyow-core/lib/pakyow/core/config/cookies.rb +0 -4
- data/pakyow-core/lib/pakyow/core/config/logger.rb +0 -34
- data/pakyow-core/lib/pakyow/core/config/reloader.rb +0 -10
- data/pakyow-core/lib/pakyow/core/config/server.rb +0 -10
- data/pakyow-core/lib/pakyow/core/config/session.rb +0 -41
- data/pakyow-core/lib/pakyow/core/config.rb +0 -95
- data/pakyow-core/lib/pakyow/core/errors.rb +0 -16
- data/pakyow-core/lib/pakyow/core/helpers/configuring.rb +0 -142
- data/pakyow-core/lib/pakyow/core/helpers/hooks.rb +0 -106
- data/pakyow-core/lib/pakyow/core/helpers/running.rb +0 -124
- data/pakyow-core/lib/pakyow/core/helpers.rb +0 -61
- data/pakyow-core/lib/pakyow/core/loader.rb +0 -32
- data/pakyow-core/lib/pakyow/core/middleware/logger.rb +0 -146
- data/pakyow-core/lib/pakyow/core/middleware/override.rb +0 -3
- data/pakyow-core/lib/pakyow/core/middleware/reloader.rb +0 -23
- data/pakyow-core/lib/pakyow/core/middleware/req_path_normalizer.rb +0 -49
- data/pakyow-core/lib/pakyow/core/middleware/session.rb +0 -5
- data/pakyow-core/lib/pakyow/core/middleware/static.rb +0 -76
- data/pakyow-core/lib/pakyow/core/multilog.rb +0 -19
- data/pakyow-core/lib/pakyow/core/request.rb +0 -119
- data/pakyow-core/lib/pakyow/core/response.rb +0 -135
- data/pakyow-core/lib/pakyow/core/route_eval.rb +0 -254
- data/pakyow-core/lib/pakyow/core/route_expansion_eval.rb +0 -115
- data/pakyow-core/lib/pakyow/core/route_lookup.rb +0 -41
- data/pakyow-core/lib/pakyow/core/route_merger.rb +0 -76
- data/pakyow-core/lib/pakyow/core/route_module.rb +0 -21
- data/pakyow-core/lib/pakyow/core/route_set.rb +0 -74
- data/pakyow-core/lib/pakyow/core/route_template_defaults.rb +0 -43
- data/pakyow-core/lib/pakyow/core/route_template_eval.rb +0 -72
- data/pakyow-core/lib/pakyow/core/router.rb +0 -181
- data/pakyow-core/lib/pakyow/core.rb +0 -8
- data/pakyow-core/lib/pakyow-core.rb +0 -1
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/loader"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
class Plugin
|
7
|
+
# @api private
|
8
|
+
class State
|
9
|
+
def initialize(plugin, path: plugin.class.plugin_path)
|
10
|
+
@plugin, @path = plugin, path
|
11
|
+
end
|
12
|
+
|
13
|
+
def backend_path(aspect)
|
14
|
+
File.join(@path, "backend", aspect.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def frontend_path
|
18
|
+
File.join(@path, "frontend")
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_frontend
|
22
|
+
@plugin.state(:templates) << Presenter::Templates.new(
|
23
|
+
@plugin.config.name,
|
24
|
+
frontend_path,
|
25
|
+
config: {
|
26
|
+
prefix: @plugin.class.mount_path
|
27
|
+
},
|
28
|
+
processor: Presenter::ProcessorCaller.new(
|
29
|
+
@plugin.parent.state(:processor)
|
30
|
+
)
|
31
|
+
).tap do |plugin_templates|
|
32
|
+
if app_templates = @plugin.parent.state(:templates).find { |templates| templates.name == :default }
|
33
|
+
plugin_templates.paths.each do |path|
|
34
|
+
plugin_info = plugin_templates.info(path)
|
35
|
+
|
36
|
+
# Use the app's layout, if available.
|
37
|
+
#
|
38
|
+
if app_templates.layouts.include?(plugin_info[:page].info(:layout))
|
39
|
+
plugin_info[:layout] = app_templates.layout(plugin_info[:page].info(:layout).to_sym)
|
40
|
+
plugin_info[:partials].merge!(app_templates.includes)
|
41
|
+
end
|
42
|
+
|
43
|
+
if app_info = app_templates.info(path)
|
44
|
+
# Define the plugin view as the `plug` partial so that it can be included.
|
45
|
+
#
|
46
|
+
plugin_info[:partials][:plug] = Presenter::Partial.from_object(
|
47
|
+
:plug, plugin_info[:page].object
|
48
|
+
)
|
49
|
+
|
50
|
+
# Set the layout for the page.
|
51
|
+
#
|
52
|
+
plugin_info[:layout] = app_templates.layout(app_info[:page].info(:layout).to_sym)
|
53
|
+
|
54
|
+
# Include the app partials, since we're using a page from the app that might include them.
|
55
|
+
#
|
56
|
+
plugin_info[:partials].merge!(app_info[:partials])
|
57
|
+
|
58
|
+
# Finally, override the page with the one from the app.
|
59
|
+
#
|
60
|
+
plugin_info[:page] = app_info[:page]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,367 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/class_state"
|
4
|
+
require "pakyow/support/configurable"
|
5
|
+
require "pakyow/support/definable"
|
6
|
+
require "pakyow/support/hookable"
|
7
|
+
require "pakyow/support/pipeline"
|
8
|
+
|
9
|
+
require "pakyow/behavior/aspects"
|
10
|
+
require "pakyow/behavior/endpoints"
|
11
|
+
require "pakyow/behavior/frameworks"
|
12
|
+
require "pakyow/behavior/helpers"
|
13
|
+
require "pakyow/behavior/isolating"
|
14
|
+
require "pakyow/behavior/operations"
|
15
|
+
require "pakyow/behavior/pipeline"
|
16
|
+
require "pakyow/behavior/rescuing"
|
17
|
+
require "pakyow/behavior/restarting"
|
18
|
+
|
19
|
+
require "pakyow/app"
|
20
|
+
require "pakyow/endpoints"
|
21
|
+
|
22
|
+
require "pakyow/plugin/helper_caller"
|
23
|
+
|
24
|
+
module Pakyow
|
25
|
+
# Base plugin class.
|
26
|
+
#
|
27
|
+
class Plugin
|
28
|
+
require "pakyow/plugin/state"
|
29
|
+
|
30
|
+
extend Support::ClassState
|
31
|
+
class_state :__enabled_features, default: []
|
32
|
+
class_state :__disabled_features, default: []
|
33
|
+
|
34
|
+
include Support::Configurable
|
35
|
+
|
36
|
+
setting :name
|
37
|
+
|
38
|
+
setting :root do
|
39
|
+
plugin_path
|
40
|
+
end
|
41
|
+
|
42
|
+
setting :src do
|
43
|
+
File.join(config.root, "backend")
|
44
|
+
end
|
45
|
+
|
46
|
+
setting :lib do
|
47
|
+
File.join(config.src, "lib")
|
48
|
+
end
|
49
|
+
|
50
|
+
configurable :tasks do
|
51
|
+
setting :prelaunch, []
|
52
|
+
end
|
53
|
+
|
54
|
+
include Support::Definable
|
55
|
+
include Support::Hookable
|
56
|
+
include Support::Pipeline
|
57
|
+
|
58
|
+
# Use the same events as app.
|
59
|
+
#
|
60
|
+
events(*App.events)
|
61
|
+
|
62
|
+
# Include behavior so that plugin behaves like an app.
|
63
|
+
#
|
64
|
+
include Behavior::Aspects
|
65
|
+
include Behavior::Endpoints
|
66
|
+
include Behavior::Frameworks
|
67
|
+
include Behavior::Helpers
|
68
|
+
include Behavior::Isolating
|
69
|
+
include Behavior::Operations
|
70
|
+
include Behavior::Pipeline
|
71
|
+
include Behavior::Rescuing
|
72
|
+
include Behavior::Restarting
|
73
|
+
|
74
|
+
attr_reader :parent
|
75
|
+
|
76
|
+
def initialize(parent, &block)
|
77
|
+
super()
|
78
|
+
|
79
|
+
@parent = parent
|
80
|
+
@state = []
|
81
|
+
@endpoints = Endpoints.new
|
82
|
+
@features = self.class.features
|
83
|
+
@key = build_key
|
84
|
+
|
85
|
+
performing :configure do
|
86
|
+
configure!(@parent.environment)
|
87
|
+
end
|
88
|
+
|
89
|
+
performing :initialize do
|
90
|
+
if block_given?
|
91
|
+
instance_exec(&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Load state prior to calling the load hooks so that helpers are available.
|
95
|
+
#
|
96
|
+
load_state
|
97
|
+
|
98
|
+
# We still want to call the load hooks so that behavior works properly.
|
99
|
+
#
|
100
|
+
performing :load do; end
|
101
|
+
|
102
|
+
defined!
|
103
|
+
end
|
104
|
+
|
105
|
+
create_helper_contexts
|
106
|
+
|
107
|
+
if respond_to?(:boot)
|
108
|
+
boot
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def booted
|
113
|
+
call_hooks :after, :boot
|
114
|
+
end
|
115
|
+
|
116
|
+
def feature?(name)
|
117
|
+
name = name.to_sym
|
118
|
+
@features.any? { |feature|
|
119
|
+
feature[:name] == name
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def call(connection)
|
124
|
+
super(isolated(:Connection).from_connection(connection, :@app => self))
|
125
|
+
end
|
126
|
+
|
127
|
+
def method_missing(method_name, *args, &block)
|
128
|
+
if @parent.respond_to?(method_name)
|
129
|
+
@parent.public_send(method_name, *args, &block)
|
130
|
+
else
|
131
|
+
super
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def respond_to_missing?(method_name, include_private = false)
|
136
|
+
@parent.respond_to?(method_name) || super
|
137
|
+
end
|
138
|
+
|
139
|
+
def helpers(connection)
|
140
|
+
@helper_class.new(self, connection)
|
141
|
+
end
|
142
|
+
|
143
|
+
def __object_name
|
144
|
+
self.class.__object_name
|
145
|
+
end
|
146
|
+
|
147
|
+
def plugin_path
|
148
|
+
self.class.plugin_path
|
149
|
+
end
|
150
|
+
|
151
|
+
def helper_caller(helper_context, connection, call_context)
|
152
|
+
connection = connection.class.from_connection(connection, :@app => self)
|
153
|
+
|
154
|
+
HelperCaller.new(
|
155
|
+
plugin: self,
|
156
|
+
connection: connection,
|
157
|
+
helpers: @helper_contexts[helper_context.to_sym].new(connection, call_context)
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
def load_frontend
|
162
|
+
@state.each(&:load_frontend)
|
163
|
+
end
|
164
|
+
|
165
|
+
def exposed_value_name(name)
|
166
|
+
prefix = if self.class.__object_name.name == :default
|
167
|
+
self.class.plugin_name
|
168
|
+
else
|
169
|
+
"#{self.class.plugin_name}(#{self.class.__object_name.name})"
|
170
|
+
end
|
171
|
+
|
172
|
+
:"__#{prefix}.#{name}"
|
173
|
+
end
|
174
|
+
|
175
|
+
def _dump(_)
|
176
|
+
Marshal.dump(
|
177
|
+
{
|
178
|
+
parent: {
|
179
|
+
name: @parent.config.name
|
180
|
+
},
|
181
|
+
|
182
|
+
plugin_name: self.class.plugin_name,
|
183
|
+
plugin_path: self.class.plugin_path,
|
184
|
+
mount_path: self.class.mount_path
|
185
|
+
}
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
def self._load(state)
|
190
|
+
state = Marshal.load(state)
|
191
|
+
Pakyow.app(state[:parent][:name]).plugs.find { |plug|
|
192
|
+
plug.class.plugin_name == state[:plugin_name] &&
|
193
|
+
plug.class.plugin_path == state[:plugin_path] &&
|
194
|
+
plug.class.mount_path == state[:mount_path]
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
def frontend_key(name = nil)
|
199
|
+
if name
|
200
|
+
:"@#{@key}.#{name}"
|
201
|
+
else
|
202
|
+
@key
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def build_key
|
209
|
+
namespace = self.class.__object_name.namespace.parts.last
|
210
|
+
@key = case namespace
|
211
|
+
when :default
|
212
|
+
:"#{self.class.plugin_name}"
|
213
|
+
else
|
214
|
+
:"#{self.class.plugin_name}.#{namespace}"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def load_aspect(aspect)
|
219
|
+
@state.each do |state|
|
220
|
+
super(aspect, path: state.backend_path(aspect), target: self)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def load_state
|
225
|
+
load_global_state
|
226
|
+
load_feature_state
|
227
|
+
end
|
228
|
+
|
229
|
+
def load_global_state
|
230
|
+
@state << State.new(self)
|
231
|
+
end
|
232
|
+
|
233
|
+
def load_feature_state
|
234
|
+
@features.each do |feature|
|
235
|
+
@state << State.new(self, path: feature[:path])
|
236
|
+
|
237
|
+
initializer = File.join(feature[:path], "initializer.rb")
|
238
|
+
if File.exist?(initializer)
|
239
|
+
instance_eval(File.read(initializer), initializer)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def load_endpoints
|
245
|
+
state.each_with_object(@endpoints) do |(_, state_object), endpoints|
|
246
|
+
state_object.instances.each do |state_instance|
|
247
|
+
endpoints.load(state_instance)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
define_app_endpoints
|
252
|
+
end
|
253
|
+
|
254
|
+
def define_app_endpoints
|
255
|
+
@endpoints.each do |endpoint|
|
256
|
+
# Register endpoints accessible for backend path building.
|
257
|
+
#
|
258
|
+
@parent.endpoints << Endpoint.new(
|
259
|
+
name: [config.name.to_s, endpoint.name].join("_"),
|
260
|
+
method: :get,
|
261
|
+
builder: endpoint.builder
|
262
|
+
)
|
263
|
+
|
264
|
+
# Register endpoints accessible for frontend path building.
|
265
|
+
#
|
266
|
+
namespace = self.class.__object_name.namespace.parts.last
|
267
|
+
|
268
|
+
endpoint_name = if namespace == :default
|
269
|
+
:"@#{self.class.plugin_name}.#{endpoint.name}"
|
270
|
+
else
|
271
|
+
:"@#{self.class.plugin_name}(#{namespace}).#{endpoint.name}"
|
272
|
+
end
|
273
|
+
|
274
|
+
@parent.endpoints << Endpoint.new(
|
275
|
+
name: endpoint_name,
|
276
|
+
method: :get,
|
277
|
+
builder: endpoint.builder
|
278
|
+
)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def create_helper_contexts
|
283
|
+
@helper_contexts = %i(global passive active).each_with_object({}) { |context, helper_contexts|
|
284
|
+
helper_class = Class.new do
|
285
|
+
def initialize(connection, context)
|
286
|
+
@connection, @context = connection, context
|
287
|
+
end
|
288
|
+
|
289
|
+
def method_missing(method_name, *args, &block)
|
290
|
+
if @context.respond_to?(method_name)
|
291
|
+
@context.public_send(method_name, *args, &block)
|
292
|
+
else
|
293
|
+
super
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def respond_to_missing?(method_name, include_private = false)
|
298
|
+
@context.respond_to?(method_name, include_private) || super
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
self.class.include_helpers(context, helper_class)
|
303
|
+
helper_contexts[context] = helper_class
|
304
|
+
}
|
305
|
+
end
|
306
|
+
|
307
|
+
class << self
|
308
|
+
attr_reader :plugin_name, :plugin_path, :mount_path
|
309
|
+
|
310
|
+
# rubocop:disable Naming/MethodName
|
311
|
+
def Plugin(name, path)
|
312
|
+
Class.new(self) do
|
313
|
+
@plugin_name = name
|
314
|
+
@plugin_path = path
|
315
|
+
end
|
316
|
+
end
|
317
|
+
# rubocop:enabled Naming/MethodName
|
318
|
+
|
319
|
+
def inherited(plugin_class)
|
320
|
+
super
|
321
|
+
|
322
|
+
if instance_variable_defined?(:@plugin_name)
|
323
|
+
plugin_class.instance_variable_set(:@plugin_name, instance_variable_get(:@plugin_name))
|
324
|
+
plugin_class.instance_variable_set(:@plugin_path, instance_variable_get(:@plugin_path))
|
325
|
+
|
326
|
+
unless Pakyow.plugins.include?(@plugin_name)
|
327
|
+
Pakyow.register_plugin(@plugin_name, plugin_class)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def enable(*features)
|
333
|
+
@__enabled_features.concat(features)
|
334
|
+
end
|
335
|
+
|
336
|
+
def disable(*features)
|
337
|
+
@__disabled_features.concat(features)
|
338
|
+
end
|
339
|
+
|
340
|
+
def features
|
341
|
+
Dir.glob(File.join(plugin_path, "features", "*")).map { |feature_path|
|
342
|
+
{
|
343
|
+
name: File.basename(feature_path).to_sym,
|
344
|
+
path: feature_path
|
345
|
+
}
|
346
|
+
}.tap do |features|
|
347
|
+
features.delete_if do |feature|
|
348
|
+
@__disabled_features.include?(feature[:name])
|
349
|
+
end
|
350
|
+
|
351
|
+
if @__enabled_features.any?
|
352
|
+
features.keep_if do |feature|
|
353
|
+
@__enabled_features.include?(feature[:name])
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context = self
|
361
|
+
Pakyow.singleton_class.class_eval do
|
362
|
+
define_method :Plugin do |name, path|
|
363
|
+
context.Plugin(name, path)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "process/group"
|
4
|
+
|
5
|
+
require "pakyow/support/inflector"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
class ProcessManager
|
9
|
+
def initialize
|
10
|
+
@group, @processes, @stopped = Process::Group.new, [], false
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(process)
|
14
|
+
process = process.dup
|
15
|
+
run_process(process)
|
16
|
+
@processes << process
|
17
|
+
end
|
18
|
+
|
19
|
+
def wait
|
20
|
+
@group.wait
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop(signal = :INT)
|
24
|
+
@stopped = true
|
25
|
+
@group.kill(signal)
|
26
|
+
end
|
27
|
+
|
28
|
+
def restart
|
29
|
+
@group.running.each do |pid, forked|
|
30
|
+
if forked.instance_variable_get(:@options)[:restartable]
|
31
|
+
Process.kill(:INT, pid)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def run_process(process)
|
39
|
+
Fiber.new {
|
40
|
+
until @stopped
|
41
|
+
status = @group.fork(process) {
|
42
|
+
begin
|
43
|
+
Async::Reactor.run(&process[:block])
|
44
|
+
rescue Interrupt
|
45
|
+
end
|
46
|
+
}
|
47
|
+
|
48
|
+
break unless status.success?
|
49
|
+
end
|
50
|
+
}.resume
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Processes
|
5
|
+
class Proxy
|
6
|
+
class << self
|
7
|
+
def find_local_port
|
8
|
+
server = TCPServer.new("127.0.0.1", 0)
|
9
|
+
port = server.addr[1]
|
10
|
+
server.close
|
11
|
+
port
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(host:, port:, proxy_port:)
|
16
|
+
@host, @port, @proxy_port = host, port, proxy_port
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
endpoint = Async::HTTP::Endpoint.parse(
|
21
|
+
"http://#{@host}:#{@port}"
|
22
|
+
)
|
23
|
+
|
24
|
+
server = Server.new(
|
25
|
+
host: @host, port: @proxy_port, forwarded: "#{@host}:#{@port}"
|
26
|
+
)
|
27
|
+
|
28
|
+
Async::Reactor.run do
|
29
|
+
Async::HTTP::Server.new(server, endpoint).run
|
30
|
+
|
31
|
+
if !ENV.key?("PW_RESPAWN")
|
32
|
+
Pakyow.logger << Pakyow::Processes::Server.running_text(
|
33
|
+
scheme: "http", host: @host, port: @port
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Server
|
40
|
+
def initialize(port:, host:, forwarded:)
|
41
|
+
@port, @host, @forwarded = port, host, forwarded
|
42
|
+
@destination = "#{@host}:#{@port}"
|
43
|
+
@client = Async::HTTP::Client.new(
|
44
|
+
Async::HTTP::Endpoint.parse(
|
45
|
+
File.join("http://#{@destination}")
|
46
|
+
)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(request, total_waits = 0)
|
51
|
+
@client.call(request)
|
52
|
+
rescue
|
53
|
+
if total_waits == 30
|
54
|
+
Async::HTTP::Protocol::Response.new(
|
55
|
+
nil, 404, [], Async::HTTP::Body::Buffered.wrap(
|
56
|
+
StringIO.new("app did not respond")
|
57
|
+
)
|
58
|
+
)
|
59
|
+
else
|
60
|
+
Async::Task.current.sleep 0.5
|
61
|
+
call(request, total_waits + 1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "async/http/server"
|
4
|
+
|
5
|
+
require "pakyow/support/extension"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
module Processes
|
9
|
+
class Server
|
10
|
+
class << self
|
11
|
+
def running_text(scheme:, host:, port:)
|
12
|
+
text = String.new("Pakyow › #{Pakyow.env.capitalize}")
|
13
|
+
text << " › #{scheme}://#{host}:#{port}"
|
14
|
+
|
15
|
+
Support::CLI.style.blue.bold(
|
16
|
+
text
|
17
|
+
) + Support::CLI.style.italic("\nUse Ctrl-C to shut down the environment.")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(endpoint:, protocol:, scheme:)
|
22
|
+
@endpoint, @protocol, @scheme = endpoint, protocol, scheme
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
Async::HTTP::Server.new(
|
27
|
+
Pakyow.boot, @endpoint, @protocol, @scheme
|
28
|
+
).run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "protocol/http/headers"
|
4
|
+
require "rack/request"
|
5
|
+
|
6
|
+
require "pakyow/environment"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Rack
|
10
|
+
class Connection < ::Pakyow::Connection
|
11
|
+
def initialize(rack_env)
|
12
|
+
super(::Rack::Request.new(rack_env))
|
13
|
+
end
|
14
|
+
|
15
|
+
def query
|
16
|
+
@request.query_string
|
17
|
+
end
|
18
|
+
|
19
|
+
def fullpath
|
20
|
+
@request.fullpath
|
21
|
+
end
|
22
|
+
|
23
|
+
def request_header(key)
|
24
|
+
normalize_header_value(key, @request.get_header(normalize_header(key)))
|
25
|
+
end
|
26
|
+
|
27
|
+
def request_header?(key)
|
28
|
+
@request.has_header?(normalize_header(key))
|
29
|
+
end
|
30
|
+
|
31
|
+
def ip
|
32
|
+
@request.ip
|
33
|
+
end
|
34
|
+
|
35
|
+
def hijack?
|
36
|
+
@request.env["rack.hijack?"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def hijack!
|
40
|
+
@request.env["rack.hijack"].call
|
41
|
+
end
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
def request_method
|
45
|
+
@request.request_method
|
46
|
+
end
|
47
|
+
|
48
|
+
# @api private
|
49
|
+
def request_path
|
50
|
+
@request.fullpath
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def normalize_header(key)
|
56
|
+
key.to_s.upcase.gsub("-", "_")
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalize_header_value(key, value)
|
60
|
+
if value && policy = Protocol::HTTP::Headers::MERGE_POLICY[key.to_s.downcase.gsub("_", "-")]
|
61
|
+
policy.new(value.to_s)
|
62
|
+
else
|
63
|
+
value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|