Give a Plani somewhere to live

1830332 · Gabriel Morell · 2026-09-03 17:21

25 files +424 -15
Message
{commit_body(@commit)}

Files changed

modified ?
+0 −0

Binary file — not rendered.

modified ?
+0 −0

Binary file — not rendered.

modified apps/room_sanctum/lib/room_sanctum/configuration.ex
+28 −0
@@ -616,6 +616,34 @@ defmodule RoomSanctum.Configuration do
616 616 ** (Ecto.NoResultsError)
617 617
618 618 """
619 + alias RoomSanctum.Configuration.Plani
620 +
621 + @doc "Every Plani, for the supervisor that keeps a worker per one."
622 + def list_plani, do: Repo.all(Plani)
623 +
624 + def list_plani(uid), do: Repo.all(from p in Plani, where: p.user_id == ^uid)
625 +
626 + def get_plani!(id) when is_binary(id) do
627 + case Integer.parse(id) do
628 + {n, ""} -> get_plani!(n)
629 + _ -> raise Ecto.NoResultsError, queryable: Plani
630 + end
631 + end
632 +
633 + def get_plani!(id), do: Repo.get!(Plani, id)
634 +
635 + def create_plani(attrs \\ %{}) do
636 + %Plani{} |> Plani.changeset(attrs) |> Repo.insert() |> announce(:plani)
637 + end
638 +
639 + def update_plani(%Plani{} = plani, attrs) do
640 + plani |> Plani.changeset(attrs) |> Repo.update() |> announce(:plani)
641 + end
642 +
643 + def delete_plani(%Plani{} = plani), do: Repo.delete(plani)
644 +
645 + def change_plani(%Plani{} = plani, attrs \\ %{}), do: Plani.changeset(plani, attrs)
646 +
619 647 def get_pythiae!(id), do: Repo.get!(Pythiae, id)
620 648
621 649 @doc """
added apps/room_sanctum/lib/room_sanctum/configuration/plani.ex
+58 −0
@@ -0,0 +1,58 @@
1 +defmodule RoomSanctum.Configuration.Plani do
2 + @moduledoc """
3 + A vision whose anchor moves.
4 +
5 + Where a Vision is a list of queries asked in the places they name, a Plani is
6 + a list of *sources* asked around wherever its client currently is. It is a
7 + sibling of a vision, not a mode on one: a Pythiae shows one or the other.
8 +
9 + The position itself is never stored. It lives in the Plani's worker and
10 + expires there; `home_foci` is what answers when nothing has reported
11 + recently, which is also what a Plani that has never heard from anybody
12 + falls back to.
13 + """
14 + use Ecto.Schema
15 + import Ecto.Changeset
16 +
17 + schema "cfg_plani" do
18 + field :name, :string
19 + belongs_to :user, RoomSanctum.Accounts.User
20 +
21 + # Where it is when it does not know where it is.
22 + field :home_foci_id, :integer
23 +
24 + # Whose position to follow. An Ankyra may carry several clients and only
25 + # one of them is the one that travels.
26 + field :ankyra_id, :integer
27 + field :client_id, :string
28 +
29 + # What to look for around the anchor.
30 + field :sources, {:array, :integer}, default: []
31 + field :radius, :integer, default: 800
32 + field :limit, :integer, default: 5
33 +
34 + timestamps()
35 + end
36 +
37 + @doc false
38 + def changeset(plani, attrs) do
39 + plani
40 + |> cast(attrs, [
41 + :name,
42 + :user_id,
43 + :home_foci_id,
44 + :ankyra_id,
45 + :client_id,
46 + :sources,
47 + :radius,
48 + :limit
49 + ])
50 + |> validate_required([:name, :home_foci_id])
51 + # The same bounds an area query keeps, and for the same reason: past a
52 + # couple of kilometres this stops meaning "near me".
53 + |> validate_number(:radius, greater_than_or_equal_to: 50, less_than_or_equal_to: 3000)
54 + |> validate_number(:limit, greater_than_or_equal_to: 1, less_than_or_equal_to: 20)
55 + |> foreign_key_constraint(:user_id)
56 + |> foreign_key_constraint(:home_foci_id)
57 + end
58 +end
modified apps/room_sanctum/lib/room_sanctum/configuration/pythiae.ex
+6 −1
@@ -46,6 +46,10 @@ defmodule RoomSanctum.Configuration.Pythiae do
46 46 belongs_to :user, RoomSanctum.Accounts.User
47 47 field :curr_vision, :id
48 48 field :curr_foci, :id
49 + # Exclusive with curr_vision: a Pythiae shows a vision or a Plani, never
50 + # both. A Plani is a vision whose anchor moves, so the two answer the same
51 + # question from different places and merging them would show each twice.
52 + field :curr_plani, :id
49 53 embeds_many :consts, Const
50 54 embeds_one :tweaks, Tweaks
51 55
@@ -55,11 +59,12 @@ defmodule RoomSanctum.Configuration.Pythiae do
55 59 @doc false
56 60 def changeset(pythiae, attrs) do
57 61 pythiae
58 − |> cast(attrs, [:visions, :ankyra, :user_id, :curr_vision, :curr_foci, :name])
62 + |> cast(attrs, [:visions, :ankyra, :user_id, :curr_vision, :curr_foci, :curr_plani, :name])
59 63 |> cast_embed(:consts, with: &Const.changeset/2)
60 64 |> foreign_key_constraint(:user_id)
61 65 |> foreign_key_constraint(:curr_vision)
62 66 |> foreign_key_constraint(:curr_foci)
67 + |> foreign_key_constraint(:curr_plani)
63 68 |> validate_required([:visions, :ankyra, :name])
64 69 end
65 70 end
modified apps/room_sanctum/lib/room_sanctum/storage.ex
+20 −11

Click to load diff…

modified apps/room_sanctum/lib/room_sanctum/workers/ankyra_worker.ex
+27 −0

Click to load diff…

added apps/room_sanctum/lib/room_sanctum/workers/plani_worker.ex
+164 −0

Click to load diff…

modified apps/room_sanctum/lib/room_sanctum/workers/pythiae_worker.ex
+19 −3

Click to load diff…

added apps/room_sanctum/priv/repo/migrations/20260903140000_create_cfg_plani.exs
+47 −0

Click to load diff…

added apps/room_sanctum/priv/repo/migrations/20260903141000_add_curr_plani_to_pythiae.exs
+17 −0

Click to load diff…

modified apps/room_zeus/lib/application.ex
+1 −0

Click to load diff…

added apps/room_zeus/lib/supervision_plani.ex
+37 −0

Click to load diff…

Parents: 0eb79c0