Start stubbing an S3 blob cache
This commit is contained in:
parent
899f8c6fbc
commit
b5f2c2df1a
4 changed files with 98 additions and 10 deletions
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
begin
|
begin
|
||||||
require 'cbor'
|
require 'cbor'
|
||||||
rescue LoadError
|
rescue LoadError # Load CBOR if possible
|
||||||
require 'json'
|
|
||||||
end
|
end
|
||||||
|
require 'json'
|
||||||
|
|
||||||
module FicTracker::Util
|
module FicTracker::Util
|
||||||
class Cache
|
class Cache
|
||||||
|
|
@ -26,6 +26,9 @@ module FicTracker::Util
|
||||||
when :redis, 'redis'
|
when :redis, 'redis'
|
||||||
require_relative 'cache/redis'
|
require_relative 'cache/redis'
|
||||||
cache = CacheImpl::Redis.new(**options)
|
cache = CacheImpl::Redis.new(**options)
|
||||||
|
when :s3, 'S3'
|
||||||
|
require_relative 'cache/s3'
|
||||||
|
cache = CacheImpl::Redis.new(**options)
|
||||||
when :none, 'none', nil
|
when :none, 'none', nil
|
||||||
require_relative 'cache/dummy'
|
require_relative 'cache/dummy'
|
||||||
cache = CacheImpl::Dummy.new
|
cache = CacheImpl::Dummy.new
|
||||||
|
|
@ -127,8 +130,8 @@ module FicTracker::Util
|
||||||
|
|
||||||
def best_encoder?(data)
|
def best_encoder?(data)
|
||||||
pod_encoder = :none if data.is_a?(String)
|
pod_encoder = :none if data.is_a?(String)
|
||||||
pod_encoder ||= :cbor if Object.const_defined?(:CBOR)
|
pod_encoder ||= :cbor if Object.const_defined?(:CBOR) && data.respond_to?(:to_cbor)
|
||||||
pod_encoder ||= :json if Object.const_defined?(:JSON)
|
pod_encoder ||= :json if Object.const_defined?(:JSON) && data.respond_to?(:to_json)
|
||||||
pod_encoder ||= :marshal
|
pod_encoder ||= :marshal
|
||||||
return pod_encoder if is_pod?(data)
|
return pod_encoder if is_pod?(data)
|
||||||
|
|
||||||
|
|
@ -139,11 +142,9 @@ module FicTracker::Util
|
||||||
encode ||= @encoder
|
encode ||= @encoder
|
||||||
encode ||= best_encoder?(data)
|
encode ||= best_encoder?(data)
|
||||||
|
|
||||||
flags = 0
|
flags = ENCODING_NONE
|
||||||
case encode
|
case encode
|
||||||
when :none
|
when :none
|
||||||
data = data
|
|
||||||
flags |= ENCODING_NONE
|
|
||||||
when :marshal
|
when :marshal
|
||||||
data = Marshal.dump(data)
|
data = Marshal.dump(data)
|
||||||
flags |= ENCODING_MARSHAL
|
flags |= ENCODING_MARSHAL
|
||||||
|
|
|
||||||
2
lib/fic_tracker/util/cache/database.rb
vendored
2
lib/fic_tracker/util/cache/database.rb
vendored
|
|
@ -12,8 +12,8 @@ module FicTracker::Util::CacheImpl
|
||||||
end
|
end
|
||||||
|
|
||||||
def expire
|
def expire
|
||||||
@dataset.where { Sequel::CURRENT_DATE >= expire_at }.update(expired: true)
|
|
||||||
dataset_expired.delete
|
dataset_expired.delete
|
||||||
|
@dataset.where { Sequel::CURRENT_DATE >= expire_at }.update(expired: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def has?(key)
|
def has?(key)
|
||||||
|
|
|
||||||
2
lib/fic_tracker/util/cache/file.rb
vendored
2
lib/fic_tracker/util/cache/file.rb
vendored
|
|
@ -7,7 +7,7 @@ module FicTracker::Util::CacheImpl
|
||||||
# A filesystem-backed in-memory cache
|
# A filesystem-backed in-memory cache
|
||||||
class File < Base
|
class File < Base
|
||||||
def initialize(dir: nil)
|
def initialize(dir: nil)
|
||||||
@dir = dir || Dir.mktmpdir('ficagg')
|
@dir = dir || Dir.mktmpdir('fictrack')
|
||||||
|
|
||||||
@internal = Memory.new
|
@internal = Memory.new
|
||||||
end
|
end
|
||||||
|
|
|
||||||
87
lib/fic_tracker/util/cache/s3.rb
vendored
Normal file
87
lib/fic_tracker/util/cache/s3.rb
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 's3-light'
|
||||||
|
|
||||||
|
class S3Light::Object
|
||||||
|
def read
|
||||||
|
response = client.with_connection do |connection|
|
||||||
|
connection.make_request(:get, "/#{bucket.name}/#{key}")
|
||||||
|
end
|
||||||
|
|
||||||
|
response.body.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module FicTracker::Util::CacheImpl
|
||||||
|
# A cache using an S3 bucket
|
||||||
|
class S3 < Base
|
||||||
|
def initialize(access_key:, secret_key:, bucket:, **s3)
|
||||||
|
@connection = nil # ...
|
||||||
|
@bucket = nil # ...
|
||||||
|
@objects = @bucket.objects
|
||||||
|
|
||||||
|
load_bucket!
|
||||||
|
end
|
||||||
|
|
||||||
|
def expire
|
||||||
|
to_destroy = @objects.all.reject do |obj|
|
||||||
|
obj.key.end_with?('.meta') || check_meta(obj.key)
|
||||||
|
end
|
||||||
|
return if to_destroy.empty?
|
||||||
|
|
||||||
|
@objects.destroy_batch keys: to_destroy.map(&:key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has?(key)
|
||||||
|
return check_meta key
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(key)
|
||||||
|
return nil unless check_meta key
|
||||||
|
|
||||||
|
@objects.find_by(key:).read
|
||||||
|
end
|
||||||
|
|
||||||
|
def set(key, value, expiry = nil)
|
||||||
|
expiry = expiry >= 0 ? Time.now + expiry : nil if expiry.is_a?(Numeric)
|
||||||
|
expiry = nil if expiry.is_a?(Numeric)
|
||||||
|
meta = {
|
||||||
|
key: key,
|
||||||
|
ttl: expiry&.to_i
|
||||||
|
}.compact.to_json
|
||||||
|
|
||||||
|
@objects.new(key:, input: value).save!
|
||||||
|
@objects.new(key: "#{key}.meta", input: meta.to_json).save!
|
||||||
|
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(key)
|
||||||
|
@objects.destroy_batch keys: [
|
||||||
|
key,
|
||||||
|
"#{key}.meta"
|
||||||
|
]
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear
|
||||||
|
to_destroy = @objects.all.map(&:key)
|
||||||
|
return if to_destroy.empty?
|
||||||
|
|
||||||
|
@objects.destroy_batch keys: to_destroy
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_meta(key)
|
||||||
|
meta_key = "#{key}.meta"
|
||||||
|
return true unless @objects.exists? meta_key
|
||||||
|
|
||||||
|
meta = JSON.parse(@objects.find_by(key: meta_key))
|
||||||
|
return true unless meta[:ttl]
|
||||||
|
|
||||||
|
Time.now < Time.at(meta[:ttl])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Reference in a new issue