-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cache: Create the base of the caching subsystem
- Loading branch information
1 parent
9a75429
commit fe8ed6b
Showing
10 changed files
with
233 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require "./cache/*" | ||
|
||
module Invidious::Cache | ||
extend self | ||
|
||
INSTANCE = self.init(CONFIG.cache) | ||
|
||
def init(cfg : Config::CacheConfig) : ItemStore | ||
# Environment variable takes precedence over local config | ||
url = ENV.get?("INVIDIOUS__CACHE__URL").try { |u| URI.parse(u) } | ||
url ||= CONFIG.cache.url | ||
|
||
# Determine cache type from URL scheme | ||
type = StoreType.parse?(url.scheme || "none") || StoreType::None | ||
|
||
case type | ||
when .none? | ||
return NullItemStore.new | ||
when .postgres? | ||
# Use the database URL as a compatibility fallback | ||
url ||= CONFIG.database_url | ||
return PostgresItemStore.new(url) | ||
when .redis? | ||
if url.nil? | ||
raise InvalidConfigException.new "Redis cache requires an URL." | ||
end | ||
return RedisItemStore.new(url) | ||
else | ||
raise InvalidConfigException.new "Invalid cache url. Supported values are redis://, postgres:// or nothing." | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require "json" | ||
|
||
module Invidious::Cache | ||
# Including this module allows the includer object to be cached. | ||
# The object will automatically inherit from JSON::Serializable. | ||
module CacheableItem | ||
include JSON::Serializable | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
require "./cacheable_item" | ||
|
||
module Invidious::Cache | ||
# Abstract class from which any cached element should inherit | ||
# Note: class is used here, instead of a module, in order to benefit | ||
# from various compiler checks (e.g methods must be implemented) | ||
abstract class ItemStore | ||
# Retrieves an item from the store | ||
# Returns nil if item wasn't found or is expired | ||
abstract def fetch(key : String, *, as : T.class) | ||
|
||
# Stores a given item into cache | ||
abstract def store(key : String, value : CacheableItem, expires : Time::Span) | ||
|
||
# Prematurely deletes item(s) from the cache | ||
abstract def delete(key : String) | ||
abstract def delete(keys : Array(String)) | ||
|
||
# Removes all the items stored in the cache | ||
abstract def clear | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
require "./item_store" | ||
|
||
module Invidious::Cache | ||
class NullItemStore < ItemStore | ||
def initialize | ||
end | ||
|
||
def fetch(key : String, *, as : T.class) : T? forall T | ||
return nil | ||
end | ||
|
||
def store(key : String, value : CacheableItem, expires : Time::Span) | ||
end | ||
|
||
def delete(key : String) | ||
end | ||
|
||
def delete(keys : Array(String)) | ||
end | ||
|
||
def clear | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
require "./item_store" | ||
require "json" | ||
require "pg" | ||
|
||
module Invidious::Cache | ||
class PostgresItemStore < ItemStore | ||
@db : DB::Database | ||
@node_name : String | ||
|
||
def initialize(url : URI, @node_name = "") | ||
@db = DB.open url | ||
end | ||
|
||
def fetch(key : String, *, as : T.class) : T? forall T | ||
request = <<-SQL | ||
SELECT info,updated | ||
FROM videos | ||
WHERE id = $1 | ||
SQL | ||
|
||
value, expires = @db.query_one?(request, key, as: {String?, Time?}) | ||
|
||
if expires < Time.utc | ||
self.delete(key) | ||
return nil | ||
else | ||
return T.from_json(JSON::PullParser.new(value)) | ||
end | ||
end | ||
|
||
def store(key : String, value : CacheableItem, expires : Time::Span) | ||
request = <<-SQL | ||
INSERT INTO videos | ||
VALUES ($1, $2, $3) | ||
ON CONFLICT (id) DO | ||
UPDATE | ||
SET info = $2, updated = $3 | ||
SQL | ||
|
||
@db.exec(request, key, value.to_json, Time.utc + expires) | ||
end | ||
|
||
def delete(key : String) | ||
request = <<-SQL | ||
DELETE FROM videos * | ||
WHERE id = $1 | ||
SQL | ||
|
||
@db.exec(request, key) | ||
end | ||
|
||
def delete(keys : Array(String)) | ||
request = <<-SQL | ||
DELETE FROM videos * | ||
WHERE id = ANY($1::TEXT[]) | ||
SQL | ||
|
||
@db.exec(request, keys) | ||
end | ||
|
||
def clear | ||
request = <<-SQL | ||
DELETE FROM videos * | ||
WHERE updated < now() | ||
SQL | ||
|
||
@db.exec(request) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
require "./item_store" | ||
require "json" | ||
require "redis" | ||
|
||
module Invidious::Cache | ||
class RedisItemStore < ItemStore | ||
@redis : Redis::PooledClient | ||
@node_name : String | ||
|
||
def initialize(url : URI, @node_name = "") | ||
@redis = Redis::PooledClient.new url | ||
end | ||
|
||
def fetch(key : String, *, as : T.class) : (T | Nil) forall T | ||
value = @redis.get(key) | ||
return nil if value.nil? | ||
return T.from_json(JSON::PullParser.new(value)) | ||
end | ||
|
||
def store(key : String, value : CacheableItem, expires : Time::Span) | ||
@redis.set(key, value, ex: expires.to_i) | ||
end | ||
|
||
def delete(key : String) | ||
@redis.del(key) | ||
end | ||
|
||
def delete(keys : Array(String)) | ||
@redis.del(keys) | ||
end | ||
|
||
def clear | ||
@redis.flushdb | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module Invidious::Cache | ||
enum StoreType | ||
None | ||
Postgres | ||
Redis | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
require "../cache/store_type" | ||
|
||
module Invidious::Config | ||
struct CacheConfig | ||
include YAML::Serializable | ||
|
||
@[YAML::Field(converter: IV::Config::URIConverter)] | ||
@url : URI? = URI.parse("") | ||
|
||
# Required because of YAML serialization | ||
def initialize | ||
end | ||
end | ||
end |