phaedra 0.3.2 → 0.5.2
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.
- checksums.yaml +4 -4
- data/README.md +9 -3
- data/example/Dockerfile +46 -0
- data/example/api/simple.rb +2 -2
- data/example/api/the-time.rb +2 -2
- data/example/config.ru +1 -1
- data/example/docker-compose.yml +8 -0
- data/example/phaedra/initializers.rb +11 -0
- data/lib/phaedra.rb +2 -4
- data/lib/phaedra/base.rb +6 -2
- data/lib/phaedra/concerns/callbacks_actionable.rb +6 -6
- data/lib/phaedra/initializers_module.rb +69 -0
- data/lib/phaedra/rack_app.rb +3 -0
- data/lib/phaedra/rack_middleware.rb +2 -0
- data/lib/phaedra/rack_middleware/not_found.rb +21 -0
- data/lib/phaedra/rack_middleware/static.rb +26 -0
- data/lib/phaedra/startup_initializers.rb +9 -0
- data/lib/phaedra/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00d5ba6f3bc10860baef3bf63867665db4ef610b7cf14a8281495cf929339bc3
|
4
|
+
data.tar.gz: 5d1c500a8cbe79a89182497e7881fdeba3d129e5e2f2ddcce19012f9ae713171
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f3a8145df4a02f5362dfffb66f1de44ccd650425504007f2f49fa666c68bd9d228d0e8ade98daa2d318c57b220013009bd2c9b37d10d375a7cecca2cee0c4ac
|
7
|
+
data.tar.gz: f0effbf926248e56c67da411bd688cc3f6783d7710bdedf141029d523b4e55667df18b1e509cb68aa55795a01b74369ac8e007a91754ac9b3c6046741d166258
|
data/README.md
CHANGED
@@ -118,7 +118,13 @@ All you have to do is create a static site repo ([Bridgetown](https://www.bridge
|
|
118
118
|
|
119
119
|
We recommend using OpenFaaS' dockerfile template so you can define your own `Dockerfile` to book Rack + Phaedra using the Puma web server. This also allows you to customize the Docker image configuration to install and configure other tools as necessary.
|
120
120
|
|
121
|
-
First
|
121
|
+
First make sure you've added Puma to your Gemfile:
|
122
|
+
|
123
|
+
```
|
124
|
+
gem "puma"
|
125
|
+
```
|
126
|
+
|
127
|
+
Then make sure you've pulled down the OpenFaaS template:
|
122
128
|
|
123
129
|
```sh
|
124
130
|
faas-cli template store pull dockerfile
|
@@ -174,7 +180,7 @@ Next add the `config.ru` file to boot Rack:
|
|
174
180
|
```ruby
|
175
181
|
# testphaedra/config.ru
|
176
182
|
|
177
|
-
require "phaedra"
|
183
|
+
require "phaedra/rack_app"
|
178
184
|
|
179
185
|
run Phaedra::RackApp.new
|
180
186
|
```
|
@@ -210,7 +216,7 @@ In case you're wondering: yes, with Phaedra you can write multiple Ruby function
|
|
210
216
|
Booting Phaedra up as Rack app is very simple. All you need to do is add a `config.ru` file alongside your `api` folder:
|
211
217
|
|
212
218
|
```ruby
|
213
|
-
require "phaedra"
|
219
|
+
require "phaedra/rack_app"
|
214
220
|
|
215
221
|
run Phaedra::RackApp.new
|
216
222
|
```
|
data/example/Dockerfile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
FROM ruby:2.6-alpine3.11 as builder
|
2
|
+
|
3
|
+
RUN apk add --no-cache --virtual \\
|
4
|
+
#
|
5
|
+
# required
|
6
|
+
bash tzdata build-base libffi-dev \\
|
7
|
+
#
|
8
|
+
# nice to haves
|
9
|
+
curl git
|
10
|
+
|
11
|
+
FROM builder as phaedra-app
|
12
|
+
|
13
|
+
# This is to fix an issue on Linux with permissions issues
|
14
|
+
ARG USER_ID=${USER_ID:-1000}
|
15
|
+
ARG GROUP_ID=${GROUP_ID:-1000}
|
16
|
+
ARG DOCKER_USER=${DOCKER_USER:-user}
|
17
|
+
ARG APP_DIR=${APP_DIR:-/home/user/phaedra-app}
|
18
|
+
|
19
|
+
# Change with --build-arg PHAEDRA_ENV=production
|
20
|
+
ARG PHAEDRA_ENV=staging
|
21
|
+
ENV PHAEDRA_ENV=$PHAEDRA_ENV
|
22
|
+
|
23
|
+
# Create a non-root user
|
24
|
+
RUN addgroup -g $GROUP_ID -S $GROUP_ID
|
25
|
+
RUN adduser --disabled-password -G $GROUP_ID --uid $USER_ID -S $DOCKER_USER
|
26
|
+
|
27
|
+
# Create and then own the directory to fix permissions issues
|
28
|
+
RUN mkdir -p $APP_DIR
|
29
|
+
RUN chown -R $USER_ID:$GROUP_ID $APP_DIR
|
30
|
+
|
31
|
+
# Define the user running the container
|
32
|
+
USER $USER_ID:$GROUP_ID
|
33
|
+
|
34
|
+
# . now == $APP_DIR
|
35
|
+
WORKDIR $APP_DIR
|
36
|
+
|
37
|
+
# COPY is run as a root user, not as the USER defined above, so we must chown it
|
38
|
+
COPY --chown=$USER_ID:$GROUP_ID Gemfile* ./
|
39
|
+
RUN gem install bundler
|
40
|
+
RUN bundle install
|
41
|
+
|
42
|
+
COPY --chown=$USER_ID:$GROUP_ID . .
|
43
|
+
|
44
|
+
EXPOSE 8080
|
45
|
+
|
46
|
+
CMD ["bundle", "exec", "rackup", "-p", "8080", "-o", "0.0.0.0"]
|
data/example/api/simple.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
require_relative "../phaedra/initializers"
|
2
2
|
|
3
3
|
class PhaedraFunction < Phaedra::Base
|
4
4
|
def get(params)
|
5
5
|
response["Content-Type"] = "text/html; charset=utf-8"
|
6
|
-
"<p
|
6
|
+
"<p>😁 #{Phaedra.the_time} - #{ENV["PHAEDRA_ENV"]} - #{Time.new}</p>"
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
data/example/api/the-time.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
require_relative "../phaedra/initializers"
|
2
2
|
|
3
3
|
class PhaedraFunction < Phaedra::Base
|
4
4
|
before_action :earlier_stuff
|
5
5
|
|
6
6
|
def get(params)
|
7
|
-
"The
|
7
|
+
"The ?search param is #{params[:search]}"
|
8
8
|
end
|
9
9
|
|
10
10
|
def post(params)
|
data/example/config.ru
CHANGED
data/lib/phaedra.rb
CHANGED
data/lib/phaedra/base.rb
CHANGED
@@ -7,6 +7,10 @@ module Phaedra
|
|
7
7
|
class Base
|
8
8
|
include CallbacksActionable
|
9
9
|
|
10
|
+
before_action do
|
11
|
+
Initializers.run
|
12
|
+
end
|
13
|
+
|
10
14
|
# Used by WEBrick
|
11
15
|
def self.get_instance(server, *options)
|
12
16
|
self.new(server, *options)
|
@@ -112,7 +116,7 @@ module Phaedra
|
|
112
116
|
|
113
117
|
def set_initial_status
|
114
118
|
@res.status = 200
|
115
|
-
@res["Content-Type"] = "application/json"
|
119
|
+
@res["Content-Type"] = "application/json; charset=utf-8"
|
116
120
|
end
|
117
121
|
|
118
122
|
def call_method_action(params)
|
@@ -123,7 +127,7 @@ module Phaedra
|
|
123
127
|
def complete_response
|
124
128
|
if @res.body.is_a?(String) && !@res["Content-Type"].start_with?("text/")
|
125
129
|
@res["Content-Type"] = "text/plain; charset=utf-8"
|
126
|
-
elsif @res["Content-Type"]
|
130
|
+
elsif @res["Content-Type"].start_with? "application/json"
|
127
131
|
@res.body = @res.body.to_json
|
128
132
|
end
|
129
133
|
end
|
@@ -11,14 +11,14 @@ module Phaedra
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
-
def before_action(*args)
|
15
|
-
set_callback :action, :before, *args
|
14
|
+
def before_action(*args, &block)
|
15
|
+
set_callback :action, :before, *args, &block
|
16
16
|
end
|
17
|
-
def after_action(*args)
|
18
|
-
set_callback :action, :after, *args
|
17
|
+
def after_action(*args, &block)
|
18
|
+
set_callback :action, :after, *args, &block
|
19
19
|
end
|
20
|
-
def around_action(*args)
|
21
|
-
set_callback :action, :around, *args
|
20
|
+
def around_action(*args, &block)
|
21
|
+
set_callback :action, :around, *args, &block
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Initializers
|
3
|
+
Registration = Struct.new(
|
4
|
+
:origin,
|
5
|
+
:priority,
|
6
|
+
:block,
|
7
|
+
keyword_init: true
|
8
|
+
) do
|
9
|
+
def to_s
|
10
|
+
"#{owner}:#{priority} for #{block}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
DEFAULT_PRIORITY = 20
|
15
|
+
|
16
|
+
PRIORITY_MAP = {
|
17
|
+
low: 10,
|
18
|
+
normal: 20,
|
19
|
+
high: 30,
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# initial empty hooks
|
23
|
+
@registry = []
|
24
|
+
|
25
|
+
NotAvailable = Class.new(RuntimeError)
|
26
|
+
Uncallable = Class.new(RuntimeError)
|
27
|
+
|
28
|
+
# Ensure the priority is a Fixnum
|
29
|
+
def self.priority_value(priority)
|
30
|
+
return priority if priority.is_a?(Integer)
|
31
|
+
|
32
|
+
PRIORITY_MAP[priority] || DEFAULT_PRIORITY
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.register(origin, priority: DEFAULT_PRIORITY, &block)
|
36
|
+
raise Uncallable, "Initializers must respond to :call" unless block.respond_to? :call
|
37
|
+
|
38
|
+
@registry << Registration.new(
|
39
|
+
origin: origin,
|
40
|
+
priority: priority_value(priority),
|
41
|
+
block: block
|
42
|
+
)
|
43
|
+
|
44
|
+
block
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.remove(origin)
|
48
|
+
@registry.delete_if { |item| item.origin == origin }
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.run(force: false)
|
52
|
+
if !@initializers_ran || force
|
53
|
+
prioritized_initializers.each do |initializer|
|
54
|
+
initializer.block.call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@initializers_ran = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.prioritized_initializers
|
62
|
+
# sort initializers according to priority and load order
|
63
|
+
grouped_initializers = @registry.group_by(&:priority)
|
64
|
+
grouped_initializers.keys.sort.reverse.map do |priority|
|
65
|
+
grouped_initializers[priority]
|
66
|
+
end.flatten
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/phaedra/rack_app.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Middleware
|
3
|
+
class NotFound
|
4
|
+
def initialize(app, path, content_type = 'text/html; charset=utf-8')
|
5
|
+
@app = app
|
6
|
+
@content = File.read(path)
|
7
|
+
@length = @content.bytesize.to_s
|
8
|
+
@content_type = content_type
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
response = @app.call(env)
|
13
|
+
if response[0] == 404
|
14
|
+
[404, {'Content-Type' => @content_type, 'Content-Length' => @length}, [@content]]
|
15
|
+
else
|
16
|
+
response
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Middleware
|
3
|
+
# Based on Rack::TryStatic middleware
|
4
|
+
# https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/try_static.rb
|
5
|
+
|
6
|
+
class Static
|
7
|
+
def initialize(app, options)
|
8
|
+
@app = app
|
9
|
+
@try = ["", ".html", "index.html", "/index.html", *options[:try]]
|
10
|
+
@static = Rack::Static.new(
|
11
|
+
lambda { |_| [404, {}, []] },
|
12
|
+
options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
orig_path = env['PATH_INFO']
|
17
|
+
found = nil
|
18
|
+
@try.each do |path|
|
19
|
+
resp = @static.call(env.merge!({'PATH_INFO' => orig_path + path}))
|
20
|
+
break if !(403..405).include?(resp[0]) && found = resp
|
21
|
+
end
|
22
|
+
found or @app.call(env.merge!('PATH_INFO' => orig_path))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/phaedra/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phaedra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jared White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -80,14 +80,22 @@ files:
|
|
80
80
|
- LICENSE.txt
|
81
81
|
- README.md
|
82
82
|
- Rakefile
|
83
|
+
- example/Dockerfile
|
83
84
|
- example/Gemfile
|
84
85
|
- example/api/simple.rb
|
85
86
|
- example/api/the-time.rb
|
86
87
|
- example/config.ru
|
88
|
+
- example/docker-compose.yml
|
89
|
+
- example/phaedra/initializers.rb
|
87
90
|
- lib/phaedra.rb
|
88
91
|
- lib/phaedra/base.rb
|
89
92
|
- lib/phaedra/concerns/callbacks_actionable.rb
|
93
|
+
- lib/phaedra/initializers_module.rb
|
90
94
|
- lib/phaedra/rack_app.rb
|
95
|
+
- lib/phaedra/rack_middleware.rb
|
96
|
+
- lib/phaedra/rack_middleware/not_found.rb
|
97
|
+
- lib/phaedra/rack_middleware/static.rb
|
98
|
+
- lib/phaedra/startup_initializers.rb
|
91
99
|
- lib/phaedra/version.rb
|
92
100
|
- phaedra.gemspec
|
93
101
|
homepage: https://github.com/whitefusionhq/phaedra
|
@@ -109,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
117
|
- !ruby/object:Gem::Version
|
110
118
|
version: '0'
|
111
119
|
requirements: []
|
112
|
-
rubygems_version: 3.0.
|
120
|
+
rubygems_version: 3.0.8
|
113
121
|
signing_key:
|
114
122
|
specification_version: 4
|
115
123
|
summary: Write serverless Ruby functions via a REST-like microframework compatible
|