A set of utilities for working with the AT Protocol in Elixir.

refactor: update Atex.IdentityResolver.Cache.ETS to use ConCache

ovyerus.com 2ae52bab 47417790

verified
Changed files
+37 -22
lib
atex
identity_resolver
cache
+2
CHANGELOG.md
··· 38 39 - `mix atex.lexicons` now adds `@moduledoc false` to generated modules to stop 40 them from automatically cluttering documentation. 41 42 ## [0.6.0] - 2025-11-25 43
··· 38 39 - `mix atex.lexicons` now adds `@moduledoc false` to generated modules to stop 40 them from automatically cluttering documentation. 41 + - `Atex.IdentityResolver.Cache.ETS` now uses ConCache instead of ETS directly, 42 + with a 1-hour TTL for cached identity information. 43 44 ## [0.6.0] - 2025-11-25 45
+35 -22
lib/atex/identity_resolver/cache/ets.ex
··· 1 defmodule Atex.IdentityResolver.Cache.ETS do 2 alias Atex.IdentityResolver.Identity 3 @behaviour Atex.IdentityResolver.Cache 4 use Supervisor 5 6 - @table :atex_identities 7 8 def start_link(opts) do 9 - Supervisor.start_link(__MODULE__, opts) 10 end 11 12 @impl Supervisor 13 def init(_opts) do 14 - :ets.new(@table, [:set, :public, :named_table]) 15 - Supervisor.init([], strategy: :one_for_one) 16 end 17 18 @impl Atex.IdentityResolver.Cache 19 @spec insert(Identity.t()) :: Identity.t() 20 def insert(identity) do 21 - # TODO: benchmark lookups vs match performance, is it better to use a "composite" key or two inserts? 22 - :ets.insert(@table, {{identity.did, identity.handle}, identity}) 23 identity 24 end 25 26 @impl Atex.IdentityResolver.Cache 27 @spec get(String.t()) :: {:ok, Identity.t()} | {:error, atom()} 28 def get(identifier) do 29 - lookup(identifier) 30 end 31 32 @impl Atex.IdentityResolver.Cache 33 @spec delete(String.t()) :: :noop | Identity.t() 34 def delete(identifier) do 35 - case lookup(identifier) do 36 {:ok, identity} -> 37 - :ets.delete(@table, {identity.did, identity.handle}) 38 identity 39 40 _ -> 41 :noop 42 - end 43 - end 44 - 45 - defp lookup(identifier) do 46 - case :ets.match(@table, {{identifier, :_}, :"$1"}) do 47 - [] -> 48 - case :ets.match(@table, {{:_, identifier}, :"$1"}) do 49 - [] -> {:error, :not_found} 50 - [[identity]] -> {:ok, identity} 51 - end 52 - 53 - [[identity]] -> 54 - {:ok, identity} 55 end 56 end 57 end
··· 1 defmodule Atex.IdentityResolver.Cache.ETS do 2 + @moduledoc """ 3 + ConCache-based implementation for Identity Resolver caching. 4 + 5 + Stores identity information (DID and handle mappings) with a 1-hour TTL. 6 + Uses two separate cache entries per identity to allow lookups by either DID or handle. 7 + """ 8 + 9 alias Atex.IdentityResolver.Identity 10 @behaviour Atex.IdentityResolver.Cache 11 use Supervisor 12 13 + @cache :atex_identities_cache 14 + @ttl_ms :timer.hours(1) 15 16 def start_link(opts) do 17 + Supervisor.start_link(__MODULE__, opts, name: __MODULE__) 18 end 19 20 @impl Supervisor 21 def init(_opts) do 22 + children = [ 23 + {ConCache, 24 + [ 25 + name: @cache, 26 + ttl_check_interval: :timer.minutes(5), 27 + global_ttl: @ttl_ms 28 + ]} 29 + ] 30 + 31 + Supervisor.init(children, strategy: :one_for_one) 32 end 33 34 @impl Atex.IdentityResolver.Cache 35 @spec insert(Identity.t()) :: Identity.t() 36 def insert(identity) do 37 + ConCache.put(@cache, {:did, identity.did}, identity) 38 + ConCache.put(@cache, {:handle, identity.handle}, identity) 39 identity 40 end 41 42 @impl Atex.IdentityResolver.Cache 43 @spec get(String.t()) :: {:ok, Identity.t()} | {:error, atom()} 44 def get(identifier) do 45 + case ConCache.get(@cache, {:did, identifier}) do 46 + nil -> 47 + case ConCache.get(@cache, {:handle, identifier}) do 48 + nil -> {:error, :not_found} 49 + identity -> {:ok, identity} 50 + end 51 + 52 + identity -> 53 + {:ok, identity} 54 + end 55 end 56 57 @impl Atex.IdentityResolver.Cache 58 @spec delete(String.t()) :: :noop | Identity.t() 59 def delete(identifier) do 60 + case get(identifier) do 61 {:ok, identity} -> 62 + ConCache.delete(@cache, {:did, identity.did}) 63 + ConCache.delete(@cache, {:handle, identity.handle}) 64 identity 65 66 _ -> 67 :noop 68 end 69 end 70 end