init
This commit is contained in:
61
lib/forum/log_store.ex
Normal file
61
lib/forum/log_store.ex
Normal file
@@ -0,0 +1,61 @@
|
||||
defmodule Forum.LogStore do
|
||||
@moduledoc """
|
||||
Persists request and hosting logs to a JSON file.
|
||||
"""
|
||||
use GenServer
|
||||
|
||||
@max_entries 1_000
|
||||
|
||||
def start_link(opts) do
|
||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||
end
|
||||
|
||||
def add(entry) when is_map(entry) do
|
||||
GenServer.cast(__MODULE__, {:add, entry})
|
||||
end
|
||||
|
||||
def list(limit \\ 200) do
|
||||
GenServer.call(__MODULE__, {:list, limit})
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_opts) do
|
||||
path = Path.expand("priv/logs/requests.json", File.cwd!())
|
||||
File.mkdir_p!(Path.dirname(path))
|
||||
|
||||
{:ok, %{path: path, entries: read_entries(path)}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:add, entry}, state) do
|
||||
entry =
|
||||
entry
|
||||
|> Map.put_new("id", System.unique_integer([:positive, :monotonic]))
|
||||
|> Map.put_new("time", DateTime.utc_now() |> DateTime.to_iso8601())
|
||||
|
||||
entries = [entry | state.entries] |> Enum.take(@max_entries)
|
||||
write_entries!(state.path, entries)
|
||||
|
||||
{:noreply, %{state | entries: entries}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:list, limit}, _from, state) do
|
||||
{:reply, Enum.take(state.entries, limit), state}
|
||||
end
|
||||
|
||||
defp read_entries(path) do
|
||||
with {:ok, raw} <- File.read(path),
|
||||
{:ok, entries} when is_list(entries) <- Jason.decode(raw) do
|
||||
entries
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
end
|
||||
|
||||
defp write_entries!(path, entries) do
|
||||
tmp_path = path <> ".tmp"
|
||||
File.write!(tmp_path, Jason.encode!(entries, pretty: true))
|
||||
File.rename!(tmp_path, path)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user