defmodule RedixClustered do
@moduledoc """
Redis connection (via Redix) with cluster support and more
"""
use Supervisor
@prefix_key "redis_prefix"
def start_link(opts) do
Supervisor.start_link(__MODULE__, opts, name: cluster_name(opts))
end
def init(opts) do
:ets.new(cluster_name(opts), [:set, :protected, :named_table])
:ets.insert(cluster_name(opts), {@prefix_key, Keyword.get(opts, :prefix)})
registry_opts =
opts
|> Keyword.put(:name, registry_name(opts))
|> Keyword.put(:pool_name, pool_name(opts))
children = [
{RedixClustered.Registry, registry_opts},
{RedixClustered.Slots, name: slots_name(opts)},
{DynamicSupervisor, name: pool_name(opts), strategy: :one_for_one}
]
Supervisor.init(children, strategy: :one_for_all)
end
def cluster_name(opts) when is_list(opts), do: cluster_name(Keyword.get(opts, :name))
def cluster_name(nil), do: :redix_clustered
def cluster_name(name), do: :"redix_clustered_#{name}"
def registry_name(opts), do: :"#{cluster_name(opts)}_registry"
def slots_name(opts), do: :"#{cluster_name(opts)}_slots"
def pool_name(opts), do: :"#{cluster_name(opts)}_pool"
def prefix(name) do
case :ets.lookup(cluster_name(name), @prefix_key) do
[{@prefix_key, "" <> pre}] -> "#{pre}:"
_ -> ""
end
end
def prefix(name, key), do: "#{prefix(name)}#{key}"
def unprefix(name, keys) when is_list(keys), do: Enum.map(keys, &unprefix(name, &1))
def unprefix(name, key) do
case prefix(name) do
"" -> key
pre -> String.trim_leading(key, pre)
end
end
# singleton/unnamed cluster
def command(cmd), do: command(nil, cmd)
def pipeline(cmds), do: pipeline(nil, cmds)
def get(key), do: get(nil, key)
def get_ttl(key), do: get_ttl(nil, key)
def ttl(key), do: ttl(nil, key)
def pttl(key), do: pttl(nil, key)
def expire(key, ttl), do: expire(nil, key, ttl)
def pexpire(key, ttl), do: pexpire(nil, key, ttl)
def set(key, val), do: set(nil, key, val)
def setex(key, ttl, val), do: setex(nil, key, ttl, val)
def psetex(key, ttl, val), do: psetex(nil, key, ttl, val)
def setnx_expire_get(key, ttl, val), do: setnx_expire_get(nil, key, ttl, val)
def del(key), do: del(nil, key)
def hgetall(key), do: hgetall(nil, key)
def hincrby(key, flds) when is_map(flds), do: hincrby(nil, key, flds)
def hincrby(key, flds, ttl) when is_map(flds), do: hincrby(nil, key, flds, ttl)
def hincrby(key, "" <> fld, num), do: hincrby(nil, key, fld, num)
def scan(pattern), do: scan(nil, pattern)
def nuke(pattern), do: nuke(nil, pattern)
# public interface
defdelegate command(name, cmd), to: RedixClustered.Conn
defdelegate pipeline(name, cmds), to: RedixClustered.Conn
defdelegate get(name, key), to: RedixClustered.Commands
defdelegate get_ttl(name, key), to: RedixClustered.Commands
defdelegate ttl(name, key), to: RedixClustered.Commands
defdelegate pttl(name, key), to: RedixClustered.Commands
defdelegate expire(name, key, ttl), to: RedixClustered.Commands
defdelegate pexpire(name, key, ttl), to: RedixClustered.Commands
defdelegate set(name, key, val), to: RedixClustered.Commands
defdelegate setex(name, key, ttl, val), to: RedixClustered.Commands
defdelegate psetex(name, key, ttl, val), to: RedixClustered.Commands
defdelegate setnx_expire_get(name, key, ttl, val), to: RedixClustered.Commands
defdelegate del(name, key), to: RedixClustered.Commands
defdelegate hgetall(name, key), to: RedixClustered.Commands
defdelegate hincrby(name, key, flds), to: RedixClustered.Commands
defdelegate hincrby(name, key, flds, ttl), to: RedixClustered.Commands
defdelegate scan(name, pattern), to: RedixClustered.Commands
defdelegate nuke(name, pattern), to: RedixClustered.Commands
end