defmodule MishkaInstaller.Helper.Setting do
use GenServer
require Logger
@ets_table :setting_ets_state
@sync_with_database 100_000
@re_check_binding_db 10_000
alias MishkaInstaller.Setting, as: DBSetting
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
def push(config) do
ETS.Set.put!(table(), {String.to_atom(config.name), config.configs})
end
def get(config_name) do
case ETS.Set.get(table(), String.to_atom(config_name)) do
{:ok, {_name, config}} -> config
_ -> nil
end
end
def get_all() do
ETS.Set.to_list!(table())
end
def delete(config_name) do
ETS.Set.delete(table(), String.to_atom(config_name))
end
def child_spec(process_name) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [process_name]},
restart: :transient,
max_restarts: 4
}
end
@impl true
def init(_state) do
Logger.info("The ETS state of settings was staretd")
Process.send_after(self(), :sync_with_database, @sync_with_database)
table =
ETS.Set.new!(
name: @ets_table,
protection: :public,
read_concurrency: true,
write_concurrency: true
)
{:ok, %{set: table}, {:continue, :sync_with_database}}
end
@impl true
def handle_continue(:sync_with_database, state) do
check_custom_pubsub_loaded(state)
end
@impl true
def handle_info(:timeout, state) do
Logger.info("We are waiting for your custom pubsub is loaded")
check_custom_pubsub_loaded(state)
end
@impl true
def handle_info(:sync_with_database, state) do
Logger.info("Setting ETS state was synced with database")
sync_with_database()
Process.send_after(self(), :sync_with_database, @sync_with_database)
{:noreply, state}
end
@impl true
def handle_info({:setting, :ok, action, repo_data}, state) do
Logger.warn("Your ETS state of setting is going to be updated")
case action do
:delete -> delete(repo_data.name)
_ -> push(repo_data)
end
{:noreply, state}
end
@impl true
def terminate(_reason, _state) do
Logger.warn("Your ETS state of setting was restarted by a problem")
end
def sync_with_database() do
DBSetting.settings()
|> Enum.map(&push/1)
end
defp check_custom_pubsub_loaded(state) do
custom_pubsub = MishkaInstaller.get_config(:pubsub)
cond do
!is_nil(custom_pubsub) && is_nil(Process.whereis(custom_pubsub)) ->
{:noreply, state, 100}
true ->
Process.send_after(self(), :sync_with_database, @re_check_binding_db)
MishkaInstaller.Setting.subscribe()
{:noreply, state}
end
end
defp table() do
case ETS.Set.wrap_existing(@ets_table) do
{:ok, set} ->
set
_ ->
start_link([])
table()
end
end
end