fbe 0.48.5 → 0.48.6
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/.github/workflows/actionlint.yml +1 -7
- data/.github/workflows/codecov.yml +2 -2
- data/.github/workflows/markdown-lint.yml +1 -1
- data/.github/workflows/rake.yml +1 -2
- data/.github/workflows/typos.yml +1 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +18 -2
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +31 -31
- data/README.md +1 -1
- data/REUSE.toml +1 -0
- data/fbe.gemspec +1 -1
- data/lib/fbe/award.rb +1 -1
- data/lib/fbe/conclude.rb +4 -2
- data/lib/fbe/consider.rb +5 -1
- data/lib/fbe/delete.rb +7 -1
- data/lib/fbe/delete_one.rb +11 -2
- data/lib/fbe/fake_octokit.rb +1797 -0
- data/lib/fbe/fb.rb +31 -28
- data/lib/fbe/github_graph.rb +15 -8
- data/lib/fbe/if_absent.rb +1 -1
- data/lib/fbe/iterate.rb +27 -14
- data/lib/fbe/just_one.rb +5 -2
- data/lib/fbe/kill_if.rb +1 -0
- data/lib/fbe/middleware/formatter.rb +12 -11
- data/lib/fbe/middleware/rate_limit.rb +96 -48
- data/lib/fbe/middleware/sqlite_store.rb +12 -4
- data/lib/fbe/octo.rb +187 -1944
- data/lib/fbe/over.rb +7 -3
- data/lib/fbe/overwrite.rb +31 -2
- data/lib/fbe/pmp.rb +56 -34
- data/lib/fbe/regularly.rb +2 -2
- data/lib/fbe/repeatedly.rb +2 -2
- data/lib/fbe/sec.rb +4 -5
- data/lib/fbe/tombstone.rb +1 -1
- data/lib/fbe/unmask_repos.rb +1 -2
- data/lib/fbe.rb +1 -1
- metadata +4 -2
data/lib/fbe/fb.rb
CHANGED
|
@@ -31,34 +31,37 @@ def Fbe.fb(fb: $fb, global: $global, options: $options, loog: $loog)
|
|
|
31
31
|
raise(Fbe::Error, 'The $global is not set') if global.nil?
|
|
32
32
|
raise(Fbe::Error, 'The $options is not set') if options.nil?
|
|
33
33
|
raise(Fbe::Error, 'The $loog is not set') if loog.nil?
|
|
34
|
-
global[:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
global[:mutex] ||= Mutex.new
|
|
35
|
+
global[:mutex].synchronize do
|
|
36
|
+
global[:fb] ||=
|
|
37
|
+
begin
|
|
38
|
+
rules = Dir.glob(File.join(File.join(__dir__, '../../rules'), '*.fe')).map { |f| File.read(f) }
|
|
39
|
+
fbe = Factbase::Rules.new(
|
|
40
|
+
fb,
|
|
41
|
+
"(and \n#{rules.join("\n")}\n)",
|
|
42
|
+
uid: '_id'
|
|
43
|
+
)
|
|
44
|
+
fbe =
|
|
45
|
+
Factbase::Pre.new(fbe) do |f, fbt|
|
|
46
|
+
max = fbt.query('(max _id)').one
|
|
47
|
+
f._id = (max.nil? ? 0 : max) + 1
|
|
48
|
+
f._time = Time.now
|
|
49
|
+
f._version = [Factbase::VERSION, Judges::VERSION, options.action_version].compact.join('/')
|
|
50
|
+
f._job = Integer(options.job_id.to_s, 10) if options.job_id
|
|
51
|
+
end
|
|
52
|
+
Factbase::Impatient.new(
|
|
53
|
+
Factbase::Logged.new(
|
|
54
|
+
Factbase::SyncFactbase.new(
|
|
55
|
+
Factbase::IndexedFactbase.new(
|
|
56
|
+
Factbase::CachedFactbase.new(
|
|
57
|
+
fbe
|
|
58
|
+
)
|
|
56
59
|
)
|
|
57
|
-
)
|
|
60
|
+
),
|
|
61
|
+
loog
|
|
58
62
|
),
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
63
|
+
timeout: 60
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
64
67
|
end
|
data/lib/fbe/github_graph.rb
CHANGED
|
@@ -15,13 +15,16 @@ require_relative '../fbe'
|
|
|
15
15
|
# @param [Loog] loog Logging facility
|
|
16
16
|
# @return [Fbe::Graph] The instance of the class
|
|
17
17
|
def Fbe.github_graph(options: $options, global: $global, loog: $loog)
|
|
18
|
-
global[:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
global[:mutex] ||= Mutex.new
|
|
19
|
+
global[:mutex].synchronize do
|
|
20
|
+
global[:github_graph] ||=
|
|
21
|
+
if options.testing.nil?
|
|
22
|
+
Fbe::Graph.new(token: options.github_token || ENV.fetch('GITHUB_TOKEN', nil))
|
|
23
|
+
else
|
|
24
|
+
loog.debug('The connection to GitHub GraphQL API is mocked')
|
|
25
|
+
Fbe::Graph::Fake.new
|
|
26
|
+
end
|
|
27
|
+
end
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
# A client to GitHub GraphQL.
|
|
@@ -45,6 +48,9 @@ class Fbe::Graph # rubocop:disable Metrics/ClassLength
|
|
|
45
48
|
# puts result.viewer.login #=> "octocat"
|
|
46
49
|
def query(qry)
|
|
47
50
|
result = client.query(client.parse(qry))
|
|
51
|
+
unless result.errors.empty?
|
|
52
|
+
raise(Fbe::Error, "GitHub GraphQL query failed: #{result.errors.messages.values.flatten.join('; ')}")
|
|
53
|
+
end
|
|
48
54
|
result.data
|
|
49
55
|
end
|
|
50
56
|
|
|
@@ -487,11 +493,12 @@ class Fbe::Graph # rubocop:disable Metrics/ClassLength
|
|
|
487
493
|
total = 0
|
|
488
494
|
cursor = nil
|
|
489
495
|
loop do
|
|
496
|
+
after = "after: \"#{cursor}\", " unless cursor.nil?
|
|
490
497
|
result = query(
|
|
491
498
|
<<~GRAPHQL
|
|
492
499
|
{
|
|
493
500
|
repository(owner: "#{owner}", name: "#{name}") {
|
|
494
|
-
releases(first: 25,
|
|
501
|
+
releases(#{after}first: 25, orderBy: { field: CREATED_AT, direction: DESC }) {
|
|
495
502
|
nodes {
|
|
496
503
|
isDraft
|
|
497
504
|
publishedAt
|
data/lib/fbe/if_absent.rb
CHANGED
|
@@ -62,7 +62,7 @@ def Fbe.if_absent(fb: Fbe.fb, always: false)
|
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
yield(f)
|
|
65
|
-
q = attrs.except(
|
|
65
|
+
q = attrs.except(:_id, :_time, :_version).map do |k, v|
|
|
66
66
|
vv = v.to_s
|
|
67
67
|
if v.is_a?(String)
|
|
68
68
|
vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'"
|
data/lib/fbe/iterate.rb
CHANGED
|
@@ -148,6 +148,24 @@ class Fbe::Iterate
|
|
|
148
148
|
@repeats = repeats
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
# Sets the initial value for iteration tracking.
|
|
152
|
+
#
|
|
153
|
+
# This value is used as the starting point when no marker exists in the
|
|
154
|
+
# factbase for the current iteration label. It is also used as the
|
|
155
|
+
# restart value when a query returns nil, causing the iteration for
|
|
156
|
+
# that repository to begin again from this value.
|
|
157
|
+
#
|
|
158
|
+
# @param [Integer] value The initial value for iteration tracking
|
|
159
|
+
# @return [nil] Nothing is returned
|
|
160
|
+
# @raise [RuntimeError] If value is nil or not an Integer
|
|
161
|
+
# @example Start iteration from issue number 100
|
|
162
|
+
# iterator.since!(100)
|
|
163
|
+
def since!(value)
|
|
164
|
+
raise(Fbe::Error, 'Cannot set "since" to nil') if value.nil?
|
|
165
|
+
raise(Fbe::Error, 'The "since" must be an Integer') unless value.is_a?(Integer)
|
|
166
|
+
@since = value
|
|
167
|
+
end
|
|
168
|
+
|
|
151
169
|
# Sets the query to execute for each iteration.
|
|
152
170
|
#
|
|
153
171
|
# The query can use two special variables:
|
|
@@ -254,19 +272,14 @@ class Fbe::Iterate
|
|
|
254
272
|
).map { |n| oct.repo_id_by_name(n) }
|
|
255
273
|
started = Time.now
|
|
256
274
|
restarted = []
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
(eq repository #{repo}))
|
|
266
|
-
(first #{@label}))"
|
|
267
|
-
).one&.first || @since
|
|
268
|
-
]
|
|
269
|
-
end
|
|
275
|
+
markers = {}
|
|
276
|
+
@fb.query("(and (eq what 'iterate') (eq where 'github'))").each do |f|
|
|
277
|
+
r = f['repository']&.first
|
|
278
|
+
next if r.nil? || markers.key?(r)
|
|
279
|
+
v = f[@label.to_s]&.first
|
|
280
|
+
markers[r] = v unless v.nil?
|
|
281
|
+
end
|
|
282
|
+
before = repos.to_h { |repo| [repo, markers[repo] || @since] }
|
|
270
283
|
starts = before.dup
|
|
271
284
|
values = {}
|
|
272
285
|
loop do # rubocop:disable Metrics/BlockLength
|
|
@@ -342,7 +355,7 @@ class Fbe::Iterate
|
|
|
342
355
|
defined?(before) && !before.nil? &&
|
|
343
356
|
defined?(starts) && !starts.nil?
|
|
344
357
|
repos.each do |repo|
|
|
345
|
-
next if before[repo] == starts[repo]
|
|
358
|
+
next if before[repo] == starts[repo]
|
|
346
359
|
f =
|
|
347
360
|
Fbe.if_absent(fb: @fb, always: true) do |n|
|
|
348
361
|
n.what = 'iterate'
|
data/lib/fbe/just_one.rb
CHANGED
|
@@ -38,13 +38,16 @@ def Fbe.just_one(fb: Fbe.fb)
|
|
|
38
38
|
others(map: attrs) do |*args|
|
|
39
39
|
k = args[0]
|
|
40
40
|
if k.end_with?('=')
|
|
41
|
-
|
|
41
|
+
v = args[1]
|
|
42
|
+
raise(Fbe::Error, "Can't set #{k[0..-2]} to nil") if v.nil?
|
|
43
|
+
raise(Fbe::Error, "Can't set #{k[0..-2]} to empty string") if v.is_a?(String) && v.empty?
|
|
44
|
+
@map[k[0..-2].to_sym] = v
|
|
42
45
|
else
|
|
43
46
|
@map[k.to_sym]
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
yield(f)
|
|
47
|
-
q = attrs.except(
|
|
50
|
+
q = attrs.except(:_id, :_time, :_version).map do |k, v|
|
|
48
51
|
vv = v.to_s
|
|
49
52
|
if v.is_a?(String)
|
|
50
53
|
vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'"
|
data/lib/fbe/kill_if.rb
CHANGED
|
@@ -68,17 +68,18 @@ class Fbe::Middleware::Formatter < Faraday::Logging::Formatter
|
|
|
68
68
|
# @note Special handling for 403 JSON responses to show compact error message
|
|
69
69
|
def response(http) # rubocop:disable Metrics/AbcSize
|
|
70
70
|
return if http.status < 400
|
|
71
|
-
if http.status == 403 && http.response_headers['content-type']
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
if http.status == 403 && http.response_headers['content-type']&.start_with?('application/json')
|
|
72
|
+
msg =
|
|
73
|
+
begin
|
|
74
|
+
parsed = JSON.parse(http.response_body)
|
|
75
|
+
parsed['message'] if parsed.is_a?(Hash)
|
|
76
|
+
rescue JSON::ParserError, TypeError
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
unless msg.nil?
|
|
80
|
+
warn(["#{@req.method.upcase} #{apply_filters(@req.url.to_s)}", '->', http.status, '/', msg].join(' '))
|
|
81
|
+
return
|
|
82
|
+
end
|
|
82
83
|
end
|
|
83
84
|
if http.status >= 500 && http.response_headers['content-type']&.start_with?('text')
|
|
84
85
|
error(
|
|
@@ -27,11 +27,14 @@ class Fbe::Middleware::RateLimit < Faraday::Middleware
|
|
|
27
27
|
# Initializes the rate limit middleware.
|
|
28
28
|
#
|
|
29
29
|
# @param [Object] app The next middleware in the stack
|
|
30
|
-
def initialize(app)
|
|
31
|
-
super
|
|
30
|
+
def initialize(app, tracker = nil)
|
|
31
|
+
super(app)
|
|
32
32
|
@cached = nil
|
|
33
33
|
@remaining = nil
|
|
34
|
+
@searchleft = nil
|
|
34
35
|
@counter = 0
|
|
36
|
+
@lock = Mutex.new
|
|
37
|
+
tracker[:rate_limit] = self unless tracker.nil?
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
# Processes the HTTP request and handles rate limit caching.
|
|
@@ -40,10 +43,22 @@ class Fbe::Middleware::RateLimit < Faraday::Middleware
|
|
|
40
43
|
# @return [Faraday::Response] The response from cache or the next middleware
|
|
41
44
|
def call(env)
|
|
42
45
|
if env.url.path == '/rate_limit'
|
|
43
|
-
handle_rate_limit_request(env)
|
|
46
|
+
@lock.synchronize { handle_rate_limit_request(env) }
|
|
44
47
|
else
|
|
45
|
-
track_request
|
|
46
|
-
@app.call(env)
|
|
48
|
+
@lock.synchronize { track_request(env.url.path) }
|
|
49
|
+
@app.call(env).on_complete do |response_env|
|
|
50
|
+
@lock.synchronize { sync(response_env, env.url.path) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns the remaining requests count tracked by this middleware.
|
|
56
|
+
#
|
|
57
|
+
# @param [Symbol] resource The GitHub API resource (:core or :search)
|
|
58
|
+
# @return [Integer, nil] The remaining count, or nil when the resource is absent
|
|
59
|
+
def remaining(resource = :core)
|
|
60
|
+
@lock.synchronize do
|
|
61
|
+
resource == :search ? @searchleft : @remaining
|
|
47
62
|
end
|
|
48
63
|
end
|
|
49
64
|
|
|
@@ -56,22 +71,48 @@ class Fbe::Middleware::RateLimit < Faraday::Middleware
|
|
|
56
71
|
def handle_rate_limit_request(env)
|
|
57
72
|
if @cached.nil? || @counter >= 100
|
|
58
73
|
response = @app.call(env)
|
|
59
|
-
@cached = response
|
|
74
|
+
@cached = response
|
|
60
75
|
@remaining = extract_remaining_count(response)
|
|
76
|
+
@searchleft = extract_search_remaining_count(response)
|
|
61
77
|
@counter = 0
|
|
62
78
|
response
|
|
63
79
|
else
|
|
64
|
-
|
|
65
|
-
update_remaining_count(response)
|
|
66
|
-
Faraday::Response.new(response_env(env, response))
|
|
80
|
+
Faraday::Response.new(response_env(env, @cached))
|
|
67
81
|
end
|
|
68
82
|
end
|
|
69
83
|
|
|
70
84
|
# Tracks non-rate_limit requests and decrements counter.
|
|
71
|
-
def track_request
|
|
72
|
-
return if @remaining.nil?
|
|
73
|
-
@remaining -= 1 if @remaining.positive?
|
|
85
|
+
def track_request(path = nil)
|
|
74
86
|
@counter += 1
|
|
87
|
+
if path&.start_with?('/search/')
|
|
88
|
+
@searchleft -= 1 if @searchleft&.positive?
|
|
89
|
+
elsif @remaining&.positive?
|
|
90
|
+
@remaining -= 1
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Syncs the internal remaining count from a real API response header.
|
|
95
|
+
#
|
|
96
|
+
# When the response was served by Faraday::HttpCache from cache
|
|
97
|
+
# (indicated by +http_cache_trace+ containing +:fresh+), the
|
|
98
|
+
# +x-ratelimit-remaining+ header is stale, so we keep our
|
|
99
|
+
# decremented count. When the API was actually contacted,
|
|
100
|
+
# we seed unknown counters from headers, but avoid raising
|
|
101
|
+
# a counter already decremented by this middleware.
|
|
102
|
+
#
|
|
103
|
+
# @param [Faraday::Env] response_env The response environment
|
|
104
|
+
def sync(response_env, path = nil)
|
|
105
|
+
return if response_env[:http_cache_trace]&.include?(:fresh)
|
|
106
|
+
headers = response_env.response_headers
|
|
107
|
+
return unless headers
|
|
108
|
+
remaining = headers['x-ratelimit-remaining']
|
|
109
|
+
return unless remaining
|
|
110
|
+
count = Integer(remaining)
|
|
111
|
+
if path&.start_with?('/search/')
|
|
112
|
+
@searchleft = @searchleft.nil? ? count : [@searchleft, count].min
|
|
113
|
+
else
|
|
114
|
+
@remaining = @remaining.nil? ? count : [@remaining, count].min
|
|
115
|
+
end
|
|
75
116
|
end
|
|
76
117
|
|
|
77
118
|
# Extracts the remaining count from the response body.
|
|
@@ -80,52 +121,59 @@ class Fbe::Middleware::RateLimit < Faraday::Middleware
|
|
|
80
121
|
# @return [Integer] The remaining requests count
|
|
81
122
|
def extract_remaining_count(response)
|
|
82
123
|
body = response.body
|
|
83
|
-
if body.is_a?(String)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return 0
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
return 0 unless body.is_a?(Hash)
|
|
91
|
-
body.dig('rate', 'remaining') || 0
|
|
124
|
+
body = JSON.parse(body) if body.is_a?(String)
|
|
125
|
+
value = body.dig('rate', 'remaining') if body.is_a?(Hash)
|
|
126
|
+
value ||= response.headers['x-ratelimit-remaining']
|
|
127
|
+
Integer(value || 0)
|
|
92
128
|
end
|
|
93
129
|
|
|
94
|
-
#
|
|
130
|
+
# Extracts the search-resource remaining count from the response body.
|
|
95
131
|
#
|
|
96
|
-
# @param [Faraday::Response] response The
|
|
97
|
-
|
|
132
|
+
# @param [Faraday::Response] response The API response
|
|
133
|
+
# @return [Integer, nil] The remaining search-API requests count
|
|
134
|
+
def extract_search_remaining_count(response)
|
|
98
135
|
body = response.body
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
body = JSON.parse(body) if body.is_a?(String)
|
|
137
|
+
return nil unless body.is_a?(Hash)
|
|
138
|
+
value = body.dig('resources', 'search', 'remaining')
|
|
139
|
+
value.nil? ? nil : Integer(value)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Builds a fresh body with the current remaining counts written in,
|
|
143
|
+
# without mutating the cached response. Uses a JSON round-trip for
|
|
144
|
+
# the deep copy so we only handle JSON-shaped data.
|
|
145
|
+
#
|
|
146
|
+
# @param [Object] original The cached response body (Hash or JSON String)
|
|
147
|
+
# @return [Object] A new body of the same type with remaining counts updated
|
|
148
|
+
def patched_body(original)
|
|
149
|
+
stringed = original.is_a?(String)
|
|
150
|
+
body =
|
|
151
|
+
if stringed
|
|
152
|
+
JSON.parse(original)
|
|
153
|
+
elsif original.is_a?(Hash)
|
|
154
|
+
JSON.parse(original.to_json)
|
|
155
|
+
else
|
|
156
|
+
return original
|
|
105
157
|
end
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
body
|
|
109
|
-
|
|
110
|
-
response.instance_variable_set(:@body, body.to_json)
|
|
158
|
+
body['rate']['remaining'] = @remaining if body['rate'] && !@remaining.nil?
|
|
159
|
+
body.dig('resources', 'core')&.[]=('remaining', @remaining) unless @remaining.nil?
|
|
160
|
+
body.dig('resources', 'search')&.[]=('remaining', @searchleft) unless @searchleft.nil?
|
|
161
|
+
stringed ? body.to_json : body
|
|
111
162
|
end
|
|
112
163
|
|
|
113
|
-
#
|
|
164
|
+
# Builds a response environment that mirrors the cached response,
|
|
165
|
+
# preserving Faraday::Env invariants by dup-ing the original env
|
|
166
|
+
# and only overriding body and rate-limit headers.
|
|
114
167
|
#
|
|
115
168
|
# @param [Faraday::Env] env The original request environment
|
|
116
169
|
# @param [Faraday::Response] response The cached response
|
|
117
|
-
# @return [
|
|
170
|
+
# @return [Faraday::Env] Response env ready to wrap in Faraday::Response
|
|
118
171
|
def response_env(env, response)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
request_body: env.request_body,
|
|
126
|
-
status: response.status,
|
|
127
|
-
response_headers: headers,
|
|
128
|
-
body: response.body
|
|
129
|
-
}
|
|
172
|
+
served = response.env.dup
|
|
173
|
+
served.request_headers = env.request_headers
|
|
174
|
+
served.body = patched_body(response.body)
|
|
175
|
+
served.response_headers = response.headers.dup
|
|
176
|
+
served.response_headers['x-ratelimit-remaining'] = @remaining.to_s unless @remaining.nil?
|
|
177
|
+
served
|
|
130
178
|
end
|
|
131
179
|
end
|
|
@@ -86,8 +86,8 @@ class Fbe::Middleware::SqliteStore
|
|
|
86
86
|
return unless value
|
|
87
87
|
begin
|
|
88
88
|
JSON.parse(Zlib::Inflate.inflate(value))
|
|
89
|
-
rescue Zlib::Error => e
|
|
90
|
-
@loog.info("Failed to
|
|
89
|
+
rescue Zlib::Error, JSON::ParserError, TypeError => e
|
|
90
|
+
@loog.info("Failed to decode cached value for key: #{key}, error: #{e.message}, the key will be deleted")
|
|
91
91
|
delete(key)
|
|
92
92
|
end
|
|
93
93
|
end
|
|
@@ -106,7 +106,7 @@ class Fbe::Middleware::SqliteStore
|
|
|
106
106
|
# @return [nil]
|
|
107
107
|
# @note Values larger than 10KB are not cached
|
|
108
108
|
# @note Non-GET requests and URLs with query parameters are not cached
|
|
109
|
-
def write(key, value) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
109
|
+
def write(key, value) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
|
110
110
|
return if value.is_a?(Array) && value.any? do |vv|
|
|
111
111
|
req = JSON.parse(vv[0])
|
|
112
112
|
req['method'] != 'get'
|
|
@@ -129,6 +129,8 @@ class Fbe::Middleware::SqliteStore
|
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
resp['response_headers']['cache-control'] = control
|
|
132
|
+
value = value.dup
|
|
133
|
+
value[0] = value[0].dup
|
|
132
134
|
value[0][1] = JSON.dump(resp)
|
|
133
135
|
end
|
|
134
136
|
end
|
|
@@ -159,6 +161,13 @@ class Fbe::Middleware::SqliteStore
|
|
|
159
161
|
perform { _1.execute('SELECT key, value FROM cache') }
|
|
160
162
|
end
|
|
161
163
|
|
|
164
|
+
# Close the database connection explicitly.
|
|
165
|
+
# @return [nil]
|
|
166
|
+
def close
|
|
167
|
+
@db&.close
|
|
168
|
+
@db = nil
|
|
169
|
+
end
|
|
170
|
+
|
|
162
171
|
private
|
|
163
172
|
|
|
164
173
|
def perform(&) # rubocop:disable Metrics/AbcSize
|
|
@@ -248,7 +257,6 @@ class Fbe::Middleware::SqliteStore
|
|
|
248
257
|
"new file size: #{Filesize.from(File.size(@path).to_s).pretty} bytes"
|
|
249
258
|
)
|
|
250
259
|
end
|
|
251
|
-
at_exit { @db&.close }
|
|
252
260
|
end
|
|
253
261
|
@db.transaction(&)
|
|
254
262
|
end
|