diff --git a/.gitignore b/.gitignore index cb8d4d3..258f85a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ fly.toml /publish.rb /publish_bookmark.rb /publish_photo.rb +/publish_code.rb +/terminal_render.rb instagram_import.rb node_modules/* .DS_Store @@ -14,6 +16,8 @@ node_modules/* .env.* .vimrc.local *.dump +*.rdb +*.onnx Capfile config/deploy.rb config/deploy/production.rb diff --git a/.tool-versions b/.tool-versions index 2260bb7..b2554e6 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,5 @@ ruby 3.3.0 postgres 16.1 rust 1.74.1 -node 20.10.0 +nodejs 20.10.0 +redis 7.2.4 diff --git a/Gemfile b/Gemfile index 7695e51..7b1afb7 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ gem "georuby" gem "gpx" gem "gnuplot" gem "matrix" +gem "redis" gem "rack-session" gem "rack-rewrite" diff --git a/Gemfile.lock b/Gemfile.lock index 0976dc0..f4585c2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -364,6 +364,10 @@ GEM rdoc (6.6.2) psych (>= 4.0.0) redcarpet (3.6.0) + redis (5.1.0) + redis-client (>= 0.17.0) + redis-client (0.21.0) + connection_pool regexp_parser (2.9.0) reline (0.4.3) io-console (~> 0.5) @@ -562,6 +566,7 @@ DEPENDENCIES rack-test rake redcarpet + redis reverse_markdown rexml rom-factory diff --git a/Procfile.dev b/Procfile.dev index 7c59ea3..6d9e85a 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,3 +1,4 @@ web: bundle exec hanami server tailwind: bundle exec rake tailwind:watch assets: bundle exec hanami assets watch +redis: redis-server diff --git a/app/action.rb b/app/action.rb index 7329de1..35c2e59 100644 --- a/app/action.rb +++ b/app/action.rb @@ -22,8 +22,8 @@ module Adamantium handle_exception ROM::TupleCountMismatchError => :not_found handle_exception StandardError => :handle_error - def cache(key:, content_proc:, expiry: TimeMath.min.advance(Time.now, +10)) - cacher.call(key: key, content_proc: content_proc, expiry: expiry) + def cache(key:, params: [], content_proc:, expiry: TimeMath.min.advance(Time.now, +10)) + cacher.call(key: key, params: params, content_proc: content_proc, expiry: expiry) end def not_found(_req, res, _exception) diff --git a/config/providers/clients.rb b/config/providers/clients.rb index 4490a0b..434c5b2 100644 --- a/config/providers/clients.rb +++ b/config/providers/clients.rb @@ -4,5 +4,8 @@ Hanami.app.register_provider :clients, namespace: true do register "blue_sky", Adamantium::Client::BlueSky.new register "omdb", Adamantium::Client::Omdb.new(api_key: target["settings"].omdb_api_key) register "gist", Adamantium::Client::Gist.new(token: target["settings"].gist_client_token) + + require "redis" + register "redis", Redis.new end end diff --git a/config/settings.rb b/config/settings.rb index 51cf3b5..d105dfc 100644 --- a/config/settings.rb +++ b/config/settings.rb @@ -4,6 +4,9 @@ require "adamantium/types" module Adamantium class Settings < Hanami::Settings + # App Settings + setting :cache_store, default: :redis_cache_store + # Infrastructure setting :database_url diff --git a/lib/adamantium/view_cache/cacher.rb b/lib/adamantium/view_cache/cacher.rb index 7cda1a3..87c9136 100644 --- a/lib/adamantium/view_cache/cacher.rb +++ b/lib/adamantium/view_cache/cacher.rb @@ -3,42 +3,30 @@ require "json" module Adamantium module ViewCache class Cacher - def call(key:, content_proc:, expiry:) - cached_content = read(key: key) + include Deps["settings"] + + def call(key:, params:, content_proc:, expiry:) + calculated_key = "adamantium:#{key}_#{params.join("_")}" + cached_content = cache_store.read(key: calculated_key) return cached_content if cached_content - rendered_content = content_proc.call + rendered_content = content_proc.call(*params) data = JSON.generate(expire: expiry.to_i, content: rendered_content) - write(key: key, content: data) + cache_store.write(key: calculated_key, content: data, expiry: expiry) rendered_content end private - def write(key:, content:) - filename = "#{key}.json" - path = File.join(Hanami.app.root, "tmp", filename) - - File.write(path, content) - end - - def read(key:) - filename = "#{key}.json" - path = File.join(Hanami.app.root, "tmp", filename) - - return nil unless File.exist?(path) - - cached_data = JSON.parse(File.read(path)) - - if Time.strptime(cached_data["expire"].to_s, "%s") < Time.now - File.delete(path) - nil + def cache_store + if settings.cache_store == :redis_cache_store + RedisCacheStore.new else - cached_data["content"] + FileStore.new end end end diff --git a/lib/adamantium/view_cache/file_store.rb b/lib/adamantium/view_cache/file_store.rb new file mode 100644 index 0000000..a434439 --- /dev/null +++ b/lib/adamantium/view_cache/file_store.rb @@ -0,0 +1,28 @@ +module Adamantium + module ViewCache + class FileStore + def write(key:, content:, expiry:) + filename = "#{key}.json" + path = File.join(Hanami.app.root, "tmp", filename) + + File.write(path, content) + end + + def read(key:) + filename = "#{key}.json" + path = File.join(Hanami.app.root, "tmp", filename) + + return nil unless File.exist?(path) + + cached_data = JSON.parse(File.read(path)) + + if Time.strptime(cached_data["expire"].to_s, "%s") < Time.now + File.delete(path) + nil + else + cached_data["content"] + end + end + end + end +end diff --git a/lib/adamantium/view_cache/redis_cache_store.rb b/lib/adamantium/view_cache/redis_cache_store.rb new file mode 100644 index 0000000..e6308ed --- /dev/null +++ b/lib/adamantium/view_cache/redis_cache_store.rb @@ -0,0 +1,18 @@ +module Adamantium + module ViewCache + class RedisCacheStore + include Deps["clients.redis"] + + def read(key:) + cached_data = redis.get(key) + + JSON.parse(cached_data)["content"] if cached_data + end + + def write(key:, content:, expiry:) + redis.set(key, content, exat: expiry.to_i) + end + end + end +end + diff --git a/slices/main/actions/posts/index.rb b/slices/main/actions/posts/index.rb index 815b4d4..4682cf7 100644 --- a/slices/main/actions/posts/index.rb +++ b/slices/main/actions/posts/index.rb @@ -4,7 +4,10 @@ module Main class Index < Action include Deps["views.posts.index"] def handle(req, res) - res.render index, query: req.params[:q] + res.body = cache(key: "posts_index", + params: [req.params[:q]], + content_proc: ->(q) { res.render index, query: q }) + res.status = 200 end end end