Files
bDS2/lib/bds/mcp/proposal_store.ex

100 lines
2.4 KiB
Elixir

defmodule BDS.MCP.ProposalStore do
@moduledoc false
import Ecto.Query
alias BDS.MCP.Proposal
alias BDS.Persistence
alias BDS.Repo
@default_ttl_ms 30 * 60 * 1000
def ensure_started, do: :ok
def create(kind, data, opts \\ []) when is_binary(kind) and is_map(data) do
:ok = ensure_started()
cleanup_expired(opts)
now = Persistence.now_ms()
entity_id = Keyword.get(opts, :entity_id) || derive_entity_id(data)
%Proposal{}
|> Proposal.changeset(%{
id: Ecto.UUID.generate(),
kind: kind,
status: :pending,
entity_id: entity_id,
data: data,
created_at: now,
expires_at: now + Keyword.get(opts, :ttl_ms, @default_ttl_ms)
})
|> Repo.insert!()
end
def get(id) when is_binary(id) do
:ok = ensure_started()
cleanup_expired([])
Repo.get(Proposal, id)
end
def remove(id) when is_binary(id) do
:ok = ensure_started()
Repo.delete_all(from proposal in Proposal, where: proposal.id == ^id)
:ok
end
def list do
:ok = ensure_started()
cleanup_expired([])
Repo.all(from proposal in Proposal, order_by: [asc: proposal.created_at])
end
def cleanup_expired(opts \\ []) do
:ok = ensure_started()
now = Persistence.now_ms()
on_expire = Keyword.get(opts, :on_expire)
expired =
Repo.all(
from proposal in Proposal,
where: proposal.status == :pending and proposal.expires_at <= ^now
)
Enum.each(expired, fn proposal ->
if is_function(on_expire, 1), do: on_expire.(proposal)
mark_status(proposal.id, :expired)
end)
Enum.map(expired, &Repo.get(Proposal, &1.id))
end
def mark_accepted(id) when is_binary(id), do: remove(id)
def mark_discarded(id) when is_binary(id), do: remove(id)
defp mark_status(id, status) do
case Repo.get(Proposal, id) do
nil ->
nil
proposal ->
Repo.delete_all(
from other in Proposal,
where:
other.id != ^id and other.kind == ^proposal.kind and
other.entity_id == ^proposal.entity_id and
other.status == ^status
)
proposal
|> Proposal.changeset(%{status: status})
|> Repo.update!()
end
end
defp derive_entity_id(data) do
data["post_id"] || data["script_id"] || data["template_id"] || data["media_id"] ||
Ecto.UUID.generate()
end
end