macaw_framework 0.2.0 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +6 -2
- data/README.md +31 -7
- data/lib/macaw_framework/aspects/cache_aspect.rb +18 -6
- data/lib/macaw_framework/aspects/logging_aspect.rb +2 -2
- data/lib/macaw_framework/aspects/prometheus_aspect.rb +1 -1
- data/lib/macaw_framework/core/server.rb +61 -16
- data/lib/macaw_framework/data_filters/response_data_filter.rb +31 -0
- data/lib/macaw_framework/errors/too_many_requests_error.rb +4 -0
- data/lib/macaw_framework/middlewares/caching_middleware.rb +6 -3
- data/lib/macaw_framework/middlewares/prometheus_middleware.rb +1 -1
- data/lib/macaw_framework/middlewares/rate_limiter_middleware.rb +31 -0
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +13 -13
- data/sig/macaw_framework/macaw.rbs +9 -2
- data/sig/server.rbs +3 -2
- metadata +7 -4
- /data/lib/macaw_framework/{middlewares → data_filters}/request_data_filtering.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b35cc5b2fba0adc8ded0f76db41699323cc3957d54382d19e554d0e3dc77f51
|
4
|
+
data.tar.gz: bcd983f6afe8b8864b5d2c012c120ead8290b521ed66f49477f8defb7eed2ede
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a7f7ef95d76e906b706a036d8cb299ba1b5e3be607ba8cdc13da216b11665b019635bca062ac83fc3067a18ab36148df12d3af2bdbc0fbe42fa3a8e0cb2c018
|
7
|
+
data.tar.gz: 56a97dff9ddac5f4142b82d441de3264d4044ace0f8f9496a2e0f49a8e384c6cf57ed705bcf68dd051c536b0dc4e4b9a643161f6563a7bcfe095f2b6f691e5ff
|
data/CHANGELOG.md
CHANGED
@@ -34,3 +34,10 @@
|
|
34
34
|
- Adding middleware for integration with Prometheus to collect metrics
|
35
35
|
- Adding a simple caching mechanism that can be enabled separately for each endpoint
|
36
36
|
- Performance and functional optimizations
|
37
|
+
|
38
|
+
## [1.0.0] - 2023-04-28
|
39
|
+
|
40
|
+
- Adding support to HTTPS/SSL using security certificates
|
41
|
+
- Implemented a middleware for rate limiting to prevent DoS attacks
|
42
|
+
- Improvement of caching strategy to ignore optional headers
|
43
|
+
- First production-ready version
|
data/Gemfile
CHANGED
@@ -11,6 +11,10 @@ gem "minitest", "~> 5.0"
|
|
11
11
|
|
12
12
|
gem "rubocop", "~> 1.21"
|
13
13
|
|
14
|
-
gem "simplecov", "~> 0.22.0"
|
15
|
-
|
16
14
|
gem "prometheus-client", "~> 4.1"
|
15
|
+
|
16
|
+
group :test do
|
17
|
+
gem "simplecov", "~> 0.21.2"
|
18
|
+
gem "simplecov-json"
|
19
|
+
gem "simplecov_json_formatter", "~> 0.1.2"
|
20
|
+
end
|
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# MacawFramework
|
2
2
|
|
3
|
-
<img src="macaw_logo.png" alt= “” style="width: 30%;height: 30%;margin-left: 35%">
|
4
|
-
|
5
3
|
This is a framework for developing web applications. Please have in mind that this is still a work in progress and
|
6
4
|
it is strongly advised to not use it for production purposes for now. Actually it supports only HTTP. and HTTPS/SSL
|
7
5
|
support will be implemented soon. Anyone who wishes to contribute is welcome.
|
@@ -31,13 +29,39 @@ in the same directory of the script that will start the application with the fol
|
|
31
29
|
"threads": 10,
|
32
30
|
"cache": {
|
33
31
|
"cache_invalidation": 3600
|
32
|
+
},
|
33
|
+
"prometheus": {
|
34
|
+
"endpoint": "/metrics"
|
35
|
+
},
|
36
|
+
"rate_limiting": {
|
37
|
+
"window": 10,
|
38
|
+
"max_requests": 3,
|
39
|
+
"ignore_headers": [
|
40
|
+
"header-to-be-ignored-from-caching-strategy",
|
41
|
+
"another-header-to-be-ignored-from-caching-strategy"
|
42
|
+
]
|
43
|
+
},
|
44
|
+
"ssl": {
|
45
|
+
"ssl": {
|
46
|
+
"cert_file_name": "path/to/cert/file/file.crt",
|
47
|
+
"key_file_name": "path/to/cert/key/file.key"
|
48
|
+
}
|
34
49
|
}
|
35
50
|
}
|
36
51
|
}
|
37
52
|
```
|
38
53
|
|
39
54
|
Cache invalidation time should be specified in seconds. In order to enable caching, The application.json file
|
40
|
-
should exist in the app main directory and it need the `cache_invalidation` config set.
|
55
|
+
should exist in the app main directory and it need the `cache_invalidation` config set. It is possible to
|
56
|
+
provide a list of strings in the property `ignore_headers`. All the client headers with the same name of any
|
57
|
+
of the strings provided will be ignored from caching strategy. This is useful to exclude headers like
|
58
|
+
correlation IDs from the caching strategy.
|
59
|
+
|
60
|
+
Rate Limit window should also be specified in seconds. Rate limit will be activated only if the `rate_limiting` config
|
61
|
+
exists inside `application.json`.
|
62
|
+
|
63
|
+
If the SSL configuration is provided in the `application.json` file with valid certificate and key files, the TCP server
|
64
|
+
will be wrapped with HTTPS security using the provided certificate.
|
41
65
|
|
42
66
|
Example of usage:
|
43
67
|
|
@@ -51,7 +75,7 @@ m.get('/hello_world', cache: true) do |context|
|
|
51
75
|
context[:body] # Returns the request body as string
|
52
76
|
context[:params] # Returns query parameters and path variables as a hash
|
53
77
|
context[:headers] # Returns headers as a hash
|
54
|
-
return JSON.pretty_generate({ hello_message: 'Hello World!' }), 200
|
78
|
+
return JSON.pretty_generate({ hello_message: 'Hello World!' }), 200, {"Content-Type" => "application/json"}
|
55
79
|
end
|
56
80
|
|
57
81
|
m.post('/hello_world/:path_variable') do |context|
|
@@ -70,9 +94,9 @@ The example above starts a server and creates a GET endpoint at localhost/hello_
|
|
70
94
|
If prometheus is enabled, a get endpoint will be defined at path `/metrics` to collect prometheus metrics. This path
|
71
95
|
is configurable via the `application.json` file.
|
72
96
|
|
73
|
-
The verb methods must always return a string or nil (used as the response)
|
74
|
-
code to be returned to the client. If an endpoint doesn't return a value or
|
75
|
-
code, a default 200 OK status will be sent as the response.
|
97
|
+
The verb methods must always return a string or nil (used as the response), a number corresponding to the HTTP status
|
98
|
+
code to be returned to the client and the response headers as a Hash or nil. If an endpoint doesn't return a value or
|
99
|
+
returns nil for body, status code and headers, a default 200 OK status will be sent as the response.
|
76
100
|
|
77
101
|
## Contributing
|
78
102
|
|
@@ -3,12 +3,24 @@
|
|
3
3
|
##
|
4
4
|
# Aspect that provide cache for the endpoints.
|
5
5
|
module CacheAspect
|
6
|
-
def call_endpoint(cache,
|
7
|
-
return super(*args) unless endpoints_to_cache.include?(args[0])
|
8
|
-
return cache.cache[args[2..].to_s.to_sym][0] unless cache.cache[args[2..].to_s.to_sym].nil?
|
6
|
+
def call_endpoint(cache, *args)
|
7
|
+
return super(*args) unless !cache[:cache].nil? && cache[:endpoints_to_cache].include?(args[0])
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
cache_filtered_name = cache_name_filter(args[1], cache[:ignored_headers])
|
10
|
+
|
11
|
+
cache[:cache].mutex.synchronize do
|
12
|
+
return cache[:cache].cache[cache_filtered_name][0] unless cache[:cache].cache[cache_filtered_name].nil?
|
13
|
+
|
14
|
+
response = super(*args)
|
15
|
+
cache[:cache].cache[cache_filtered_name] = [response, Time.now]
|
16
|
+
response
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def cache_name_filter(client_data, ignored_headers)
|
23
|
+
filtered_headers = client_data[:headers].filter { |key, _value| !ignored_headers.include?(key) }
|
24
|
+
[{ body: client_data[:body], params: client_data[:params], headers: filtered_headers }].to_s.to_sym
|
13
25
|
end
|
14
26
|
end
|
@@ -8,8 +8,8 @@ require "logger"
|
|
8
8
|
# in the framework.
|
9
9
|
module LoggingAspect
|
10
10
|
def call_endpoint(logger, *args)
|
11
|
-
endpoint_name = args[
|
12
|
-
logger.info("Request received for #{endpoint_name} with arguments: #{args[
|
11
|
+
endpoint_name = args[1].split(".")[1..].join("/")
|
12
|
+
logger.info("Request received for #{endpoint_name} with arguments: #{args[2..]}")
|
13
13
|
|
14
14
|
begin
|
15
15
|
response = super(*args)
|
@@ -13,7 +13,7 @@ module PrometheusAspect
|
|
13
13
|
ensure
|
14
14
|
duration = (Time.now - start_time) * 1_000
|
15
15
|
|
16
|
-
endpoint_name = args[
|
16
|
+
endpoint_name = args[2].split(".").join("/")
|
17
17
|
|
18
18
|
prometheus_middleware.request_duration_milliseconds.with_labels(endpoint: endpoint_name).observe(duration)
|
19
19
|
prometheus_middleware.request_count.with_labels(endpoint: endpoint_name).increment
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../middlewares/rate_limiter_middleware"
|
4
|
+
require_relative "../data_filters/response_data_filter"
|
5
|
+
require_relative "../errors/too_many_requests_error"
|
3
6
|
require_relative "../aspects/prometheus_aspect"
|
4
7
|
require_relative "../aspects/logging_aspect"
|
5
|
-
require_relative "../utils/http_status_code"
|
6
8
|
require_relative "../aspects/cache_aspect"
|
9
|
+
require "openssl"
|
7
10
|
|
8
11
|
##
|
9
12
|
# Class responsible for providing a default
|
@@ -12,7 +15,6 @@ class Server
|
|
12
15
|
prepend CacheAspect
|
13
16
|
prepend LoggingAspect
|
14
17
|
prepend PrometheusAspect
|
15
|
-
include HttpStatusCode
|
16
18
|
# rubocop:disable Metrics/ParameterLists
|
17
19
|
|
18
20
|
##
|
@@ -25,18 +27,20 @@ class Server
|
|
25
27
|
# @param {CachingMiddleware} cache
|
26
28
|
# @param {Prometheus::Client:Registry} prometheus
|
27
29
|
# @return {Server}
|
28
|
-
def initialize(macaw,
|
29
|
-
|
30
|
-
@
|
31
|
-
@bind = bind
|
30
|
+
def initialize(macaw, endpoints_to_cache = nil, cache = nil, prometheus = nil, prometheus_mw = nil)
|
31
|
+
@port = macaw.port
|
32
|
+
@bind = macaw.bind
|
32
33
|
@macaw = macaw
|
33
|
-
@macaw_log =
|
34
|
-
@num_threads =
|
34
|
+
@macaw_log = macaw.macaw_log
|
35
|
+
@num_threads = macaw.threads
|
35
36
|
@work_queue = Queue.new
|
36
|
-
|
37
|
-
|
37
|
+
ignored_headers = set_rate_limiting
|
38
|
+
set_ssl
|
39
|
+
@rate_limit ||= nil
|
40
|
+
ignored_headers ||= nil
|
41
|
+
@cache = { cache: cache, endpoints_to_cache: endpoints_to_cache || [], ignored_headers: ignored_headers }
|
38
42
|
@prometheus = prometheus
|
39
|
-
@prometheus_middleware =
|
43
|
+
@prometheus_middleware = prometheus_mw
|
40
44
|
@workers = []
|
41
45
|
end
|
42
46
|
|
@@ -46,6 +50,7 @@ class Server
|
|
46
50
|
# Start running the webserver.
|
47
51
|
def run
|
48
52
|
@server = TCPServer.new(@bind, @port)
|
53
|
+
@server = OpenSSL::SSL::SSLServer.new(@server, @context) if @context
|
49
54
|
@num_threads.times do
|
50
55
|
@workers << Thread.new do
|
51
56
|
loop do
|
@@ -59,6 +64,8 @@ class Server
|
|
59
64
|
|
60
65
|
loop do
|
61
66
|
@work_queue << @server.accept
|
67
|
+
rescue OpenSSL::SSL::SSLError => e
|
68
|
+
@macaw_log.error("SSL error: #{e.message}")
|
62
69
|
rescue IOError, Errno::EBADF
|
63
70
|
break
|
64
71
|
end
|
@@ -77,13 +84,19 @@ class Server
|
|
77
84
|
def handle_client(client)
|
78
85
|
path, method_name, headers, body, parameters = RequestDataFiltering.parse_request_data(client, @macaw.routes)
|
79
86
|
raise EndpointNotMappedError unless @macaw.respond_to?(method_name)
|
87
|
+
raise TooManyRequestsError unless @rate_limit.nil? || @rate_limit.allow?(client.peeraddr[3])
|
88
|
+
|
89
|
+
client_data = get_client_data(body, headers, parameters)
|
80
90
|
|
81
91
|
@macaw_log.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
|
82
|
-
message, status = call_endpoint(@prometheus_middleware, @macaw_log, @cache,
|
83
|
-
|
92
|
+
message, status, response_headers = call_endpoint(@prometheus_middleware, @macaw_log, @cache,
|
93
|
+
method_name, client_data)
|
84
94
|
status ||= 200
|
85
95
|
message ||= nil
|
86
|
-
|
96
|
+
response_headers ||= nil
|
97
|
+
client.puts ResponseDataFilter.mount_response(status, response_headers, message)
|
98
|
+
rescue TooManyRequestsError
|
99
|
+
client.print "HTTP/1.1 429 Too Many Requests\r\n\r\n"
|
87
100
|
rescue EndpointNotMappedError
|
88
101
|
client.print "HTTP/1.1 404 Not Found\r\n\r\n"
|
89
102
|
rescue StandardError => e
|
@@ -93,7 +106,39 @@ class Server
|
|
93
106
|
client.close
|
94
107
|
end
|
95
108
|
|
96
|
-
def
|
97
|
-
@macaw.
|
109
|
+
def set_rate_limiting
|
110
|
+
if @macaw.config&.dig("macaw", "rate_limiting")
|
111
|
+
ignored_headers = @macaw.config["macaw"]["rate_limiting"]["ignore_headers"] || []
|
112
|
+
@rate_limit = RateLimiterMiddleware.new(
|
113
|
+
@macaw.config["macaw"]["rate_limiting"]["window"].to_i || 1,
|
114
|
+
@macaw.config["macaw"]["rate_limiting"]["max_requests"].to_i || 60
|
115
|
+
)
|
116
|
+
end
|
117
|
+
ignored_headers
|
118
|
+
end
|
119
|
+
|
120
|
+
def set_ssl
|
121
|
+
if @macaw.config&.dig("macaw", "ssl")
|
122
|
+
@context = OpenSSL::SSL::SSLContext.new
|
123
|
+
@context.cert = OpenSSL::X509::Certificate.new(File.read(@macaw.config["macaw"]["ssl"]["cert_file_name"]))
|
124
|
+
@context.key = OpenSSL::PKey::RSA.new(File.read(@macaw.config["macaw"]["ssl"]["key_file_name"]))
|
125
|
+
end
|
126
|
+
@context ||= nil
|
127
|
+
rescue IOError => e
|
128
|
+
@macaw_log.error("It was not possible to read files #{@macaw.config["macaw"]["ssl"]["cert_file_name"]} and
|
129
|
+
#{@macaw.config["macaw"]["ssl"]["key_file_name"]}. Please assure the files exists and their names are correct.")
|
130
|
+
@macaw_log.error(e.backtrace)
|
131
|
+
raise e
|
132
|
+
end
|
133
|
+
|
134
|
+
def call_endpoint(name, client_data)
|
135
|
+
@macaw.send(
|
136
|
+
name.to_sym,
|
137
|
+
{ headers: client_data[:headers], body: client_data[:body], params: client_data[:parameters] }
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_client_data(body, headers, parameters)
|
142
|
+
{ body: body, headers: headers, parameters: parameters }
|
98
143
|
end
|
99
144
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../utils/http_status_code"
|
4
|
+
|
5
|
+
##
|
6
|
+
# Module responsible to filter and mount HTTP responses
|
7
|
+
module ResponseDataFilter
|
8
|
+
include HttpStatusCode
|
9
|
+
|
10
|
+
def self.mount_response(status, headers, body)
|
11
|
+
"#{mount_first_response_line(status, headers)}#{mount_response_headers(headers)}#{body}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.mount_first_response_line(status, headers)
|
15
|
+
separator = " \r\n\r\n"
|
16
|
+
separator = " \r\n" unless headers.nil?
|
17
|
+
|
18
|
+
"HTTP/1.1 #{status} #{HTTP_STATUS_CODE_MAP[status]}#{separator}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.mount_response_headers(headers)
|
22
|
+
return nil if headers.nil?
|
23
|
+
|
24
|
+
response = ""
|
25
|
+
headers.each do |key, value|
|
26
|
+
response += "#{key}: #{value}\r\n"
|
27
|
+
end
|
28
|
+
response += "\r\n\r\n"
|
29
|
+
response
|
30
|
+
end
|
31
|
+
end
|
@@ -4,15 +4,18 @@
|
|
4
4
|
# Middleware responsible for storing and
|
5
5
|
# invalidating cache.
|
6
6
|
class CachingMiddleware
|
7
|
-
attr_accessor :cache
|
7
|
+
attr_accessor :cache, :mutex
|
8
8
|
|
9
9
|
def initialize(inv_time_seconds = 3_600)
|
10
10
|
@cache = {}
|
11
|
+
@mutex = Mutex.new
|
11
12
|
Thread.new do
|
12
13
|
loop do
|
13
14
|
sleep(1)
|
14
|
-
@
|
15
|
-
@cache.
|
15
|
+
@mutex.synchronize do
|
16
|
+
@cache.each_pair do |key, value|
|
17
|
+
@cache.delete(key) if Time.now - value[1] >= inv_time_seconds
|
18
|
+
end
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
@@ -42,7 +42,7 @@ class PrometheusMiddleware
|
|
42
42
|
def prometheus_endpoint(prometheus_registry, configurations, macaw)
|
43
43
|
endpoint = configurations["macaw"]["prometheus"]["endpoint"] || "/metrics"
|
44
44
|
macaw.get(endpoint) do |_context|
|
45
|
-
[Prometheus::Client::Formats::Text.marshal(prometheus_registry), 200]
|
45
|
+
[Prometheus::Client::Formats::Text.marshal(prometheus_registry), 200, { "Content-Type" => "plaintext" }]
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# Middleware responsible for implementing
|
5
|
+
# rate limiting
|
6
|
+
class RateLimiterMiddleware
|
7
|
+
attr_reader :window_size, :max_requests
|
8
|
+
|
9
|
+
def initialize(window_size, max_requests)
|
10
|
+
@window_size = window_size
|
11
|
+
@max_requests = max_requests
|
12
|
+
@client_timestamps = Hash.new { |key, value| key[value] = [] }
|
13
|
+
@mutex = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def allow?(client_id)
|
17
|
+
@mutex.synchronize do
|
18
|
+
now = Time.now.to_i
|
19
|
+
timestamps = @client_timestamps[client_id]
|
20
|
+
|
21
|
+
timestamps.reject! { |timestamp| timestamp <= now - window_size }
|
22
|
+
|
23
|
+
if timestamps.length < max_requests
|
24
|
+
timestamps << now
|
25
|
+
true
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/macaw_framework.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative "macaw_framework/errors/endpoint_not_mapped_error"
|
4
4
|
require_relative "macaw_framework/middlewares/prometheus_middleware"
|
5
|
-
require_relative "macaw_framework/
|
5
|
+
require_relative "macaw_framework/data_filters/request_data_filtering"
|
6
6
|
require_relative "macaw_framework/middlewares/caching_middleware"
|
7
7
|
require_relative "macaw_framework/core/server"
|
8
8
|
require_relative "macaw_framework/version"
|
@@ -18,7 +18,7 @@ module MacawFramework
|
|
18
18
|
class Macaw
|
19
19
|
##
|
20
20
|
# Array containing the routes defined in the application
|
21
|
-
attr_reader :routes
|
21
|
+
attr_reader :routes, :port, :bind, :threads, :macaw_log, :config
|
22
22
|
|
23
23
|
##
|
24
24
|
# @param {Logger} custom_log
|
@@ -26,27 +26,27 @@ module MacawFramework
|
|
26
26
|
begin
|
27
27
|
@routes = []
|
28
28
|
@macaw_log ||= custom_log.nil? ? Logger.new($stdout) : custom_log
|
29
|
-
config = JSON.parse(File.read("application.json"))
|
30
|
-
@port = config["macaw"]["port"] || 8080
|
31
|
-
@bind = config["macaw"]["bind"] || "localhost"
|
32
|
-
@threads = config["macaw"]["threads"] || 5
|
33
|
-
unless config["macaw"]["cache"].nil?
|
34
|
-
@cache = CachingMiddleware.new(config["macaw"]["cache"]["cache_invalidation"].to_i || 3_600)
|
29
|
+
@config = JSON.parse(File.read("application.json"))
|
30
|
+
@port = @config["macaw"]["port"] || 8080
|
31
|
+
@bind = @config["macaw"]["bind"] || "localhost"
|
32
|
+
@threads = @config["macaw"]["threads"] || 5
|
33
|
+
unless @config["macaw"]["cache"].nil?
|
34
|
+
@cache = CachingMiddleware.new(@config["macaw"]["cache"]["cache_invalidation"].to_i || 3_600)
|
35
35
|
end
|
36
|
-
@prometheus = Prometheus::Client::Registry.new if config["macaw"]["prometheus"]
|
37
|
-
@prometheus_middleware = PrometheusMiddleware.new if config["macaw"]["prometheus"]
|
38
|
-
@prometheus_middleware.configure_prometheus(@prometheus, config, self) if config["macaw"]["prometheus"]
|
36
|
+
@prometheus = Prometheus::Client::Registry.new if @config["macaw"]["prometheus"]
|
37
|
+
@prometheus_middleware = PrometheusMiddleware.new if @config["macaw"]["prometheus"]
|
38
|
+
@prometheus_middleware.configure_prometheus(@prometheus, @config, self) if @config["macaw"]["prometheus"]
|
39
39
|
rescue StandardError => e
|
40
40
|
@macaw_log.error(e.message)
|
41
41
|
end
|
42
42
|
@port ||= 8080
|
43
43
|
@bind ||= "localhost"
|
44
|
+
@config ||= nil
|
44
45
|
@threads ||= 5
|
45
46
|
@endpoints_to_cache = []
|
46
47
|
@prometheus ||= nil
|
47
48
|
@prometheus_middleware ||= nil
|
48
|
-
@server = server.new(self, @
|
49
|
-
@prometheus_middleware)
|
49
|
+
@server = server.new(self, @endpoints_to_cache, @cache, @prometheus, @prometheus_middleware)
|
50
50
|
end
|
51
51
|
|
52
52
|
##
|
@@ -1,18 +1,25 @@
|
|
1
1
|
module MacawFramework
|
2
2
|
class Macaw
|
3
|
-
@bind:
|
3
|
+
@bind: String
|
4
4
|
@cache: untyped
|
5
|
+
@config: Hash[String, untyped]
|
5
6
|
@endpoints_to_cache: Array[String]
|
6
7
|
@macaw_log: Logger
|
7
|
-
@port: int
|
8
8
|
|
9
9
|
@prometheus: untyped
|
10
|
+
@prometheus_middleware: untyped
|
10
11
|
@server: Server
|
11
12
|
|
12
13
|
@threads: Integer
|
13
14
|
|
15
|
+
attr_reader bind: String
|
16
|
+
attr_reader config: Hash[String, untyped]
|
17
|
+
attr_reader macaw_log: Logger
|
18
|
+
attr_reader port: Integer
|
14
19
|
attr_reader routes: Array[String]
|
15
20
|
|
21
|
+
attr_reader threads: Integer
|
22
|
+
|
16
23
|
def delete: -> nil
|
17
24
|
|
18
25
|
def get: -> nil
|
data/sig/server.rbs
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Server
|
2
2
|
@bind: String
|
3
|
-
@cache:
|
3
|
+
@cache: Hash[Symbol, Array]
|
4
|
+
@context: OpenSSL::SSL::SSLContext
|
4
5
|
@endpoints_to_cache: Array[String]
|
5
6
|
@macaw: MacawFramework::Macaw
|
6
7
|
@macaw_log: Logger
|
@@ -9,7 +10,7 @@ class Server
|
|
9
10
|
|
10
11
|
@prometheus: untyped
|
11
12
|
@prometheus_middleware: untyped
|
12
|
-
@server: TCPServer
|
13
|
+
@server: TCPServer|OpenSSL::SSL::SSLServer
|
13
14
|
|
14
15
|
@threads: Integer
|
15
16
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: macaw_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aria Diniz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prometheus-client
|
@@ -43,10 +43,13 @@ files:
|
|
43
43
|
- lib/macaw_framework/aspects/logging_aspect.rb
|
44
44
|
- lib/macaw_framework/aspects/prometheus_aspect.rb
|
45
45
|
- lib/macaw_framework/core/server.rb
|
46
|
+
- lib/macaw_framework/data_filters/request_data_filtering.rb
|
47
|
+
- lib/macaw_framework/data_filters/response_data_filter.rb
|
46
48
|
- lib/macaw_framework/errors/endpoint_not_mapped_error.rb
|
49
|
+
- lib/macaw_framework/errors/too_many_requests_error.rb
|
47
50
|
- lib/macaw_framework/middlewares/caching_middleware.rb
|
48
51
|
- lib/macaw_framework/middlewares/prometheus_middleware.rb
|
49
|
-
- lib/macaw_framework/middlewares/
|
52
|
+
- lib/macaw_framework/middlewares/rate_limiter_middleware.rb
|
50
53
|
- lib/macaw_framework/utils/http_status_code.rb
|
51
54
|
- lib/macaw_framework/version.rb
|
52
55
|
- macaw_logo.png
|
@@ -79,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
82
|
- !ruby/object:Gem::Version
|
80
83
|
version: '0'
|
81
84
|
requirements: []
|
82
|
-
rubygems_version: 3.4.
|
85
|
+
rubygems_version: 3.4.12
|
83
86
|
signing_key:
|
84
87
|
specification_version: 4
|
85
88
|
summary: A web framework still in development.
|
File without changes
|