mirror of
https://github.com/TheRealOwenRees/plantid-discord-bot.git
synced 2026-07-23 04:26:57 +00:00
state machine with requests per guild
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
**0.1.3**
|
||||||
|
|
||||||
|
- Typo corrections in README.md
|
||||||
|
|
||||||
**0.1.2**
|
**0.1.2**
|
||||||
|
|
||||||
- bug fixes around `Threat Status`, choosing to not display when no IUCU data is available
|
- bug fixes around `Threat Status`, choosing to not display when no IUCU data is available
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ defmodule PlantIdDiscordBot.Application do
|
|||||||
@impl true
|
@impl true
|
||||||
def start(_type, _args) do
|
def start(_type, _args) do
|
||||||
children = [
|
children = [
|
||||||
|
PlantIdDiscordBot.ProcessRegistry,
|
||||||
PlantIdDiscordBot.Consumer,
|
PlantIdDiscordBot.Consumer,
|
||||||
PlantIdDiscordBot.RateLimiter,
|
PlantIdDiscordBot.RateLimiter,
|
||||||
|
{PlantIdDiscordBot.Metrics, []},
|
||||||
PlantIdDiscordBot.Scheduler,
|
PlantIdDiscordBot.Scheduler,
|
||||||
{Plug.Cowboy,
|
{Plug.Cowboy,
|
||||||
scheme: :http,
|
scheme: :http,
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
defmodule PlantIdDiscordBot.Metrics do
|
||||||
|
use Agent
|
||||||
|
alias PlantIdDiscordBot.Metrics
|
||||||
|
|
||||||
|
@file_path "priv/metrics"
|
||||||
|
|
||||||
|
defstruct [
|
||||||
|
:guild_id,
|
||||||
|
:guild_name,
|
||||||
|
:total_requests
|
||||||
|
]
|
||||||
|
|
||||||
|
def start_link(_opts) do
|
||||||
|
initial_state =
|
||||||
|
case File.exists?(Path.join(@file_path, "requests")) do
|
||||||
|
true -> read()
|
||||||
|
false -> %{}
|
||||||
|
end
|
||||||
|
|
||||||
|
Agent.start_link(fn -> initial_state end, name: via_tuple(:metrics))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp via_tuple(key) do
|
||||||
|
PlantIdDiscordBot.ProcessRegistry.via_tuple({__MODULE__, key})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_pid do
|
||||||
|
[{pid, _value}] = Registry.lookup(PlantIdDiscordBot.ProcessRegistry, {__MODULE__, :metrics})
|
||||||
|
pid
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(key) do
|
||||||
|
get_pid()
|
||||||
|
|> Agent.get(&Map.get(&1, key))
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_all() do
|
||||||
|
get_pid()
|
||||||
|
|> Agent.get(& &1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def put(guild_id, guild_name) do
|
||||||
|
get_pid()
|
||||||
|
|> Agent.update(fn state ->
|
||||||
|
case Map.get(state, guild_id) do
|
||||||
|
nil ->
|
||||||
|
Map.put(state, guild_id, %Metrics{
|
||||||
|
guild_id: guild_id,
|
||||||
|
guild_name: guild_name,
|
||||||
|
total_requests: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
existing ->
|
||||||
|
Map.put(state, guild_id, %Metrics{
|
||||||
|
existing
|
||||||
|
| total_requests: existing.total_requests + 1
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Reset metrics state and remove the saved file from disk.
|
||||||
|
"""
|
||||||
|
def reset() do
|
||||||
|
get_pid()
|
||||||
|
|> Agent.update(fn _ -> %{} end)
|
||||||
|
|
||||||
|
file = Path.join(@file_path, "requests")
|
||||||
|
|
||||||
|
if File.exists?(file) do
|
||||||
|
File.rm!(Path.join(@file_path, "requests"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Write the current state to disk. To be consumed by a CRON job.
|
||||||
|
"""
|
||||||
|
def write() do
|
||||||
|
File.mkdir_p!("priv/metrics")
|
||||||
|
|
||||||
|
data =
|
||||||
|
get_all()
|
||||||
|
|> :erlang.term_to_binary()
|
||||||
|
|
||||||
|
File.write!(Path.join(@file_path, "requests"), data)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Read the state from disk. To be loaded into state on process start.
|
||||||
|
"""
|
||||||
|
def read() do
|
||||||
|
File.read!(Path.join(@file_path, "requests"))
|
||||||
|
|> :erlang.binary_to_term()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
defmodule PlantIdDiscordBot.ProcessRegistry do
|
||||||
|
def start_link do
|
||||||
|
Registry.start_link(keys: :unique, name: __MODULE__)
|
||||||
|
end
|
||||||
|
|
||||||
|
def via_tuple(key) do
|
||||||
|
{:via, Registry, {__MODULE__, key}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def child_spec(_) do
|
||||||
|
Supervisor.child_spec(
|
||||||
|
Registry,
|
||||||
|
id: __MODULE__,
|
||||||
|
start: {__MODULE__, :start_link, []}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
defmodule PlantIdDiscordBot.MetricsTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest PlantIdDiscordBot.Metrics
|
||||||
|
|
||||||
|
test "put multiple entries into state" do
|
||||||
|
PlantIdDiscordBot.Metrics.reset()
|
||||||
|
PlantIdDiscordBot.Metrics.put(123, "Test Guild 1")
|
||||||
|
PlantIdDiscordBot.Metrics.put(321, "Test Guild 2")
|
||||||
|
|
||||||
|
keys =
|
||||||
|
PlantIdDiscordBot.Metrics.get_all()
|
||||||
|
|> Map.keys()
|
||||||
|
|
||||||
|
assert length(keys) == 2
|
||||||
|
|
||||||
|
assert %PlantIdDiscordBot.Metrics{
|
||||||
|
guild_id: 123,
|
||||||
|
guild_name: "Test Guild 1",
|
||||||
|
total_requests: 1
|
||||||
|
} ==
|
||||||
|
PlantIdDiscordBot.Metrics.get(123)
|
||||||
|
|
||||||
|
assert %PlantIdDiscordBot.Metrics{
|
||||||
|
guild_id: 321,
|
||||||
|
guild_name: "Test Guild 2",
|
||||||
|
total_requests: 1
|
||||||
|
} ==
|
||||||
|
PlantIdDiscordBot.Metrics.get(321)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update requests for a guild" do
|
||||||
|
PlantIdDiscordBot.Metrics.reset()
|
||||||
|
PlantIdDiscordBot.Metrics.put(123, "Test Guild 1")
|
||||||
|
PlantIdDiscordBot.Metrics.put(123, "Test Guild 1")
|
||||||
|
|
||||||
|
assert %PlantIdDiscordBot.Metrics{
|
||||||
|
guild_id: 123,
|
||||||
|
guild_name: "Test Guild 1",
|
||||||
|
total_requests: 2
|
||||||
|
} ==
|
||||||
|
PlantIdDiscordBot.Metrics.get(123)
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user