app refactoring
This commit is contained in:
		
							parent
							
								
									f59cfee792
								
							
						
					
					
						commit
						b4cd5642ed
					
				
					 18 changed files with 121 additions and 348 deletions
				
			
		| 
						 | 
					@ -93,12 +93,7 @@ defmodule Prymn.Agents do
 | 
				
			||||||
  Get the system's information (CPU, Memory usage, etc.).
 | 
					  Get the system's information (CPU, Memory usage, etc.).
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  def get_sys_info(%Agent{} = agent) do
 | 
					  def get_sys_info(%Agent{} = agent) do
 | 
				
			||||||
    with {:ok, channel} <- get_channel(agent),
 | 
					    {:error, :unimplemented}
 | 
				
			||||||
         {:ok, result} <- Stub.get_sys_info(channel, %Google.Protobuf.Empty{}) do
 | 
					 | 
				
			||||||
      result
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      {:error, error} -> {:error, error}
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @doc """
 | 
					  @doc """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,7 @@
 | 
				
			||||||
defmodule Prymn.Agents.Connection do
 | 
					defmodule Prymn.Agents.Connection do
 | 
				
			||||||
  @moduledoc false
 | 
					  @moduledoc false
 | 
				
			||||||
 | 
					 | 
				
			||||||
  alias Prymn.Agents.Health
 | 
					 | 
				
			||||||
  alias PrymnProto.Prymn.Agent.Stub
 | 
					 | 
				
			||||||
  require Logger
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  use GenServer, restart: :transient
 | 
					  use GenServer, restart: :transient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @timeout :timer.minutes(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def start_link(host_address) do
 | 
					  def start_link(host_address) do
 | 
				
			||||||
    GenServer.start_link(__MODULE__, host_address, name: via(host_address))
 | 
					    GenServer.start_link(__MODULE__, host_address, name: via(host_address))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					@ -23,118 +16,10 @@ defmodule Prymn.Agents.Connection do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					  @impl true
 | 
				
			||||||
  def init(host) do
 | 
					  def init(host) do
 | 
				
			||||||
    # Process.flag(:trap_exit, true)
 | 
					 | 
				
			||||||
    pid = self()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Start a connection without blocking the GenServer
 | 
					 | 
				
			||||||
    Task.start_link(fn ->
 | 
					 | 
				
			||||||
      case GRPC.Stub.connect(host, 50_012, []) do
 | 
					 | 
				
			||||||
        {:ok, channel} -> send(pid, channel)
 | 
					 | 
				
			||||||
        {:error, error} -> send(pid, {:connect_error, error})
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Keep receiving and sending back any messages to the GenServer forever
 | 
					 | 
				
			||||||
      receive_loop(pid)
 | 
					 | 
				
			||||||
    end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:ok, {host, nil}}
 | 
					    {:ok, {host, nil}}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_continue(:health, {_, channel} = state) do
 | 
					 | 
				
			||||||
    pid = self()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Task.start_link(fn ->
 | 
					 | 
				
			||||||
      case Stub.health(channel, %Google.Protobuf.Empty{}) do
 | 
					 | 
				
			||||||
        {:ok, stream} ->
 | 
					 | 
				
			||||||
          # Read from the stream forever and send data back to parent
 | 
					 | 
				
			||||||
          stream
 | 
					 | 
				
			||||||
          |> Stream.each(fn {_, data} -> send(pid, data) end)
 | 
					 | 
				
			||||||
          |> Enum.take_while(fn _ -> true end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {:error, _rpcerror} ->
 | 
					 | 
				
			||||||
          send(pid, {:connect_error, :rpc_error})
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:noreply, state}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_call(:get_channel, _, {_, channel} = state) do
 | 
					 | 
				
			||||||
    {:reply, channel, state, @timeout}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def handle_info(%GRPC.Channel{} = channel, {host, _}) do
 | 
					 | 
				
			||||||
    {:noreply, {host, channel}, {:continue, :health}}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info({:connect_error, reason}, {host, _} = state) do
 | 
					 | 
				
			||||||
    health = Health.lookup(host, default: true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case reason do
 | 
					 | 
				
			||||||
      :timeout -> Health.make_timed_out(health)
 | 
					 | 
				
			||||||
      :rpc_error -> Health.make_disconnected(health)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
    |> Health.update_and_broadcast()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # NOTE: Here we terminate normally, which means we won't be retrying. Maybe we want to?
 | 
					 | 
				
			||||||
    {:stop, :normal, state}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info(%PrymnProto.Prymn.HealthResponse{} = response, {host, _} = state) do
 | 
					 | 
				
			||||||
    response
 | 
					 | 
				
			||||||
    |> Health.make_from_proto(host)
 | 
					 | 
				
			||||||
    |> Health.update_and_broadcast()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:noreply, state, @timeout}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info(%GRPC.RPCError{} = response, state) do
 | 
					 | 
				
			||||||
    Logger.debug("received a GRPC error: #{inspect(response)}")
 | 
					 | 
				
			||||||
    {:noreply, state}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info({:gun_up, _pid, _protocol}, state) do
 | 
					 | 
				
			||||||
    # NOTE: If it's possible for the GRPC connection to be down when we receive
 | 
					 | 
				
			||||||
    # this message, maybe we should restart the connection
 | 
					 | 
				
			||||||
    {:noreply, state, {:continue, :health}}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info({:gun_down, _pid, _proto, _reason, _}, {host, _} = state) do
 | 
					 | 
				
			||||||
    Health.lookup(host, default: true)
 | 
					 | 
				
			||||||
    |> Health.make_disconnected()
 | 
					 | 
				
			||||||
    |> Health.update_and_broadcast()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {:noreply, state, @timeout}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info(:timeout, state) do
 | 
					 | 
				
			||||||
    {:stop, {:shutdown, :timeout}, state}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def handle_info(msg, state) do
 | 
					 | 
				
			||||||
    Logger.debug("received unhandled message #{inspect(msg)}")
 | 
					 | 
				
			||||||
    {:noreply, state}
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def terminate(reason, {host, channel}) do
 | 
					 | 
				
			||||||
    Logger.debug("terminating Agent connection (host: #{host}, reason: #{inspect(reason)})")
 | 
					 | 
				
			||||||
    Health.delete(host)
 | 
					 | 
				
			||||||
    if channel, do: GRPC.Stub.disconnect(channel)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp via(name) do
 | 
					  defp via(name) do
 | 
				
			||||||
    {:via, Registry, {Prymn.Agents.Registry, name}}
 | 
					    {:via, Registry, {Prymn.Agents.Registry, name}}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp receive_loop(pid) do
 | 
					 | 
				
			||||||
    receive do
 | 
					 | 
				
			||||||
      msg -> send(pid, msg)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    receive_loop(pid)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,6 +51,25 @@ defmodule Prymn.Agents.Health do
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def new(agent_id, %{"cpu_status" => cpu, "memory_status" => memory, "disk_status" => disk}) do
 | 
				
			||||||
 | 
					    %__MODULE__{host: agent_id, version: "0.1.0"}
 | 
				
			||||||
 | 
					    |> do_cpu(cpu)
 | 
				
			||||||
 | 
					    |> do_memory(memory)
 | 
				
			||||||
 | 
					    |> do_disks(disk)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp do_cpu(health, cpu) do
 | 
				
			||||||
 | 
					    %__MODULE__{health | message: "Connected", status: :connected}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp do_memory(health, memory) do
 | 
				
			||||||
 | 
					    health
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp do_disks(health, disks) do
 | 
				
			||||||
 | 
					    health
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def make_timed_out(%__MODULE__{} = health) do
 | 
					  def make_timed_out(%__MODULE__{} = health) do
 | 
				
			||||||
    %__MODULE__{health | status: :unreachable, message: "Connect timed out"}
 | 
					    %__MODULE__{health | status: :unreachable, message: "Connect timed out"}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ defmodule Prymn.Application do
 | 
				
			||||||
      {Finch, name: Prymn.Finch},
 | 
					      {Finch, name: Prymn.Finch},
 | 
				
			||||||
      {Oban, Application.fetch_env!(:prymn, Oban)},
 | 
					      {Oban, Application.fetch_env!(:prymn, Oban)},
 | 
				
			||||||
      Prymn.Agents.Supervisor,
 | 
					      Prymn.Agents.Supervisor,
 | 
				
			||||||
 | 
					      Prymn.Messaging.ConnectionSupervisor,
 | 
				
			||||||
      {Task.Supervisor, name: Prymn.TaskSupervisor},
 | 
					      {Task.Supervisor, name: Prymn.TaskSupervisor},
 | 
				
			||||||
      PrymnWeb.Endpoint
 | 
					      PrymnWeb.Endpoint
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								app/lib/prymn/messaging.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/lib/prymn/messaging.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					defmodule Prymn.Messaging do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  The Prymn messaging system
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def agent_health_topic(agent_id), do: "health.#{agent_id}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def subscribe_to_agent_health(agent_id) do
 | 
				
			||||||
 | 
					    Phoenix.PubSub.subscribe(Prymn.PubSub, agent_health_topic(agent_id))
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										64
									
								
								app/lib/prymn/messaging/connection.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/lib/prymn/messaging/connection.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					defmodule Prymn.Messaging.Connection do
 | 
				
			||||||
 | 
					  alias Prymn.Agents.Health
 | 
				
			||||||
 | 
					  use GenServer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defstruct [:conn_pid]
 | 
				
			||||||
 | 
					  require Logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @dialyzer {:nowarn_function, init: 1}
 | 
				
			||||||
 | 
					  @v1_prefix "agents.v1."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def start_link(name) do
 | 
				
			||||||
 | 
					    GenServer.start_link(__MODULE__, nil, name: name)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def init(_init_arg) do
 | 
				
			||||||
 | 
					    connection_properties = %{
 | 
				
			||||||
 | 
					      host: "localhost",
 | 
				
			||||||
 | 
					      username: "prymn_admin",
 | 
				
			||||||
 | 
					      password: "prymn_admin",
 | 
				
			||||||
 | 
					      name: "Prymn Control",
 | 
				
			||||||
 | 
					      auth_required: true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Process.flag(:trap_exit, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case Gnat.start_link(connection_properties) do
 | 
				
			||||||
 | 
					      {:ok, pid} ->
 | 
				
			||||||
 | 
					        Logger.info("Connected to NATS")
 | 
				
			||||||
 | 
					        {:ok, %__MODULE__{conn_pid: pid}, {:continue, :subscribe_to_health}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {:error, reason} ->
 | 
				
			||||||
 | 
					        Logger.info("Connection to NATS failed (#{reason}). Attempting reconnect.")
 | 
				
			||||||
 | 
					        {:ok, nil, {:continue, :attempt_reconnect}}
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_continue(:attempt_reconnect, state) do
 | 
				
			||||||
 | 
					    Process.sleep(3000)
 | 
				
			||||||
 | 
					    {:stop, {:shutdown, :connection_failure}, state}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_continue(:subscribe_to_health, %__MODULE__{} = state) do
 | 
				
			||||||
 | 
					    {:ok, _subscription} = Gnat.sub(state.conn_pid, self(), @v1_prefix <> "*.health")
 | 
				
			||||||
 | 
					    {:noreply, state}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def handle_info({:EXIT, _pid, _reason}, state) do
 | 
				
			||||||
 | 
					    Logger.info("Lost connection to NATS. Attempting reconnect.")
 | 
				
			||||||
 | 
					    {:noreply, state, {:continue, :attempt_reconnect}}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def handle_info({:msg, %{body: body, topic: @v1_prefix <> topic}}, state) do
 | 
				
			||||||
 | 
					    [agent_id, "health"] = String.split(topic, ".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    agent_id
 | 
				
			||||||
 | 
					    |> Health.new(Jason.decode!(body))
 | 
				
			||||||
 | 
					    |> Health.update_and_broadcast()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {:noreply, state}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										16
									
								
								app/lib/prymn/messaging/connection_supervisor.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/lib/prymn/messaging/connection_supervisor.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					defmodule Prymn.Messaging.ConnectionSupervisor do
 | 
				
			||||||
 | 
					  use Supervisor, restart: :permanent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def start_link([]) do
 | 
				
			||||||
 | 
					    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @impl true
 | 
				
			||||||
 | 
					  def init(_init_arg) do
 | 
				
			||||||
 | 
					    children = [
 | 
				
			||||||
 | 
					      {Prymn.Messaging.Connection, :nats1}
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Supervisor.init(children, strategy: :one_for_one)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -10,15 +10,11 @@ defmodule PrymnWeb.ServerLive.Index do
 | 
				
			||||||
    servers = Servers.list_servers()
 | 
					    servers = Servers.list_servers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    healths =
 | 
					    healths =
 | 
				
			||||||
      if connected?(socket) do
 | 
					      for %Servers.Server{status: :registered, id: id} = server <- servers, into: %{} do
 | 
				
			||||||
        for %Servers.Server{status: :registered, public_ip: ip} = server <- servers, into: %{} do
 | 
					        # Agents.from_server(server)
 | 
				
			||||||
          Agents.from_server(server)
 | 
					        # |> Agents.subscribe_to_health()
 | 
				
			||||||
          |> Agents.subscribe_to_health()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {ip, Agents.get_health(ip)}
 | 
					        {id, Agents.get_health(id)}
 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        %{}
 | 
					 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {:ok,
 | 
					    {:ok,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,8 +31,6 @@
 | 
				
			||||||
            elixir
 | 
					            elixir
 | 
				
			||||||
            elixir-ls
 | 
					            elixir-ls
 | 
				
			||||||
            rustToolchain
 | 
					            rustToolchain
 | 
				
			||||||
            protobuf
 | 
					 | 
				
			||||||
            protoc-gen-elixir
 | 
					 | 
				
			||||||
            scripts.prymn_db
 | 
					            scripts.prymn_db
 | 
				
			||||||
          ] ++ lib.optionals stdenv.isLinux [ inotify-tools ];
 | 
					          ] ++ lib.optionals stdenv.isLinux [ inotify-tools ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								mix.exs
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								mix.exs
									
									
									
									
									
								
							| 
						 | 
					@ -6,7 +6,6 @@ defmodule Prymn.MixProject do
 | 
				
			||||||
      app: :prymn,
 | 
					      app: :prymn,
 | 
				
			||||||
      version: "0.1.0",
 | 
					      version: "0.1.0",
 | 
				
			||||||
      elixir: "~> 1.15",
 | 
					      elixir: "~> 1.15",
 | 
				
			||||||
      compilers: [:proto | Mix.compilers()],
 | 
					 | 
				
			||||||
      elixirc_paths: elixirc_paths(Mix.env()),
 | 
					      elixirc_paths: elixirc_paths(Mix.env()),
 | 
				
			||||||
      config_path: Path.expand("app/config/config.exs", __DIR__),
 | 
					      config_path: Path.expand("app/config/config.exs", __DIR__),
 | 
				
			||||||
      test_paths: ["app/test"],
 | 
					      test_paths: ["app/test"],
 | 
				
			||||||
| 
						 | 
					@ -51,10 +50,8 @@ defmodule Prymn.MixProject do
 | 
				
			||||||
      {:jason, "~> 1.2"},
 | 
					      {:jason, "~> 1.2"},
 | 
				
			||||||
      {:dns_cluster, "~> 0.1.1"},
 | 
					      {:dns_cluster, "~> 0.1.1"},
 | 
				
			||||||
      {:plug_cowboy, "~> 2.5"},
 | 
					      {:plug_cowboy, "~> 2.5"},
 | 
				
			||||||
      {:grpc, "~> 0.7"},
 | 
					 | 
				
			||||||
      {:protobuf, "~> 0.12.0"},
 | 
					 | 
				
			||||||
      {:google_protos, "~> 0.3.0"},
 | 
					 | 
				
			||||||
      {:oban, "~> 2.17"},
 | 
					      {:oban, "~> 2.17"},
 | 
				
			||||||
 | 
					      {:gnat, "~> 1.7"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Test
 | 
					      # Test
 | 
				
			||||||
      {:floki, ">= 0.30.0", only: :test},
 | 
					      {:floki, ">= 0.30.0", only: :test},
 | 
				
			||||||
| 
						 | 
					@ -66,7 +63,6 @@ defmodule Prymn.MixProject do
 | 
				
			||||||
      {:tailwind_formatter, "~> 0.3.6", runtime: Mix.env() == :dev},
 | 
					      {:tailwind_formatter, "~> 0.3.6", runtime: Mix.env() == :dev},
 | 
				
			||||||
      {:phoenix_live_reload, "~> 1.2", only: :dev},
 | 
					      {:phoenix_live_reload, "~> 1.2", only: :dev},
 | 
				
			||||||
      {:dialyxir, "~> 1.4", only: [:dev], runtime: false},
 | 
					      {:dialyxir, "~> 1.4", only: [:dev], runtime: false},
 | 
				
			||||||
      {:prymn_proto_compiler, path: "proto_compiler", runtime: false}
 | 
					 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								mix.lock
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								mix.lock
									
									
									
									
									
								
							| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
  "dns_cluster": {:hex, :dns_cluster, "0.1.1", "73b4b2c3ec692f8a64276c43f8c929733a9ab9ac48c34e4c0b3d9d1b5cd69155", [:mix], [], "hexpm", "03a3f6ff16dcbb53e219b99c7af6aab29eb6b88acf80164b4bd76ac18dc890b3"},
 | 
					  "dns_cluster": {:hex, :dns_cluster, "0.1.1", "73b4b2c3ec692f8a64276c43f8c929733a9ab9ac48c34e4c0b3d9d1b5cd69155", [:mix], [], "hexpm", "03a3f6ff16dcbb53e219b99c7af6aab29eb6b88acf80164b4bd76ac18dc890b3"},
 | 
				
			||||||
  "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"},
 | 
					  "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"},
 | 
				
			||||||
  "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
 | 
					  "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
 | 
				
			||||||
 | 
					  "ed25519": {:hex, :ed25519, "1.4.1", "479fb83c3e31987c9cad780e6aeb8f2015fb5a482618cdf2a825c9aff809afc4", [:mix], [], "hexpm", "0dacb84f3faa3d8148e81019ca35f9d8dcee13232c32c9db5c2fb8ff48c80ec7"},
 | 
				
			||||||
  "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
 | 
					  "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
 | 
				
			||||||
  "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
 | 
					  "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
 | 
				
			||||||
  "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
 | 
					  "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
 | 
				
			||||||
| 
						 | 
					@ -21,15 +22,15 @@
 | 
				
			||||||
  "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"},
 | 
					  "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"},
 | 
				
			||||||
  "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
 | 
					  "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
 | 
				
			||||||
  "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
 | 
					  "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
 | 
				
			||||||
  "google_protos": {:hex, :google_protos, "0.3.0", "15faf44dce678ac028c289668ff56548806e313e4959a3aaf4f6e1ebe8db83f4", [:mix], [{:protobuf, "~> 0.10", [hex: :protobuf, repo: "hexpm", optional: false]}], "hexpm", "1f6b7fb20371f72f418b98e5e48dae3e022a9a6de1858d4b254ac5a5d0b4035f"},
 | 
					  "gnat": {:hex, :gnat, "1.7.1", "491144f9c3aec00e9941d69538e2fd2836271e220315c8d2d87907c20ca7abc8", [:mix], [{:cowlib, "~> 2.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:nkeys, "~> 0.2", [hex: :nkeys, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5629088d9bdb16d982eb48fd431cf6c5a71e9b026281781983501237ab5b911"},
 | 
				
			||||||
  "grpc": {:hex, :grpc, "0.7.0", "a86eab356b0b84406b526786a947ca50e9b9eae87108c873b51e321f8a71e8ed", [:mix], [{:cowboy, "~> 2.10", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowlib, "~> 2.12", [hex: :cowlib, repo: "hexpm", optional: false]}, {:gun, "~> 2.0", [hex: :gun, repo: "hexpm", optional: false]}, {:mint, "~> 1.5", [hex: :mint, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "632a9507da8d3c12b112b197db4d60da3c95bad02594d37711eeb622d032f254"},
 | 
					 | 
				
			||||||
  "gun": {:hex, :gun, "2.0.1", "160a9a5394800fcba41bc7e6d421295cf9a7894c2252c0678244948e3336ad73", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "a10bc8d6096b9502205022334f719cc9a08d9adcfbfc0dbee9ef31b56274a20b"},
 | 
					 | 
				
			||||||
  "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
 | 
					  "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
 | 
				
			||||||
  "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
 | 
					  "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
 | 
				
			||||||
  "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
 | 
					  "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
 | 
				
			||||||
  "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
 | 
					  "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
 | 
				
			||||||
  "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
 | 
					  "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
 | 
				
			||||||
 | 
					  "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
 | 
				
			||||||
  "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
 | 
					  "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
 | 
				
			||||||
 | 
					  "nkeys": {:hex, :nkeys, "0.2.2", "b1ab3324ed4f3a2c9658d7e80feeef86b4d15fbfd12ca5c8cf068289f582fcfa", [:mix], [{:ed25519, "~> 1.3", [hex: :ed25519, repo: "hexpm", optional: false]}], "hexpm", "3578802427b8d1d11ea6dd785c2ab774f527e2c3e449e67bd34612ab71ca471d"},
 | 
				
			||||||
  "oban": {:hex, :oban, "2.17.1", "42d6221a1c17b63d81c19e3bad9ea82b59e39c47c1f9b7670ee33628569a449b", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c02686ada7979b00e259c0efbafeae2749f8209747b3460001fe695c5bdbeee6"},
 | 
					  "oban": {:hex, :oban, "2.17.1", "42d6221a1c17b63d81c19e3bad9ea82b59e39c47c1f9b7670ee33628569a449b", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c02686ada7979b00e259c0efbafeae2749f8209747b3460001fe695c5bdbeee6"},
 | 
				
			||||||
  "phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"},
 | 
					  "phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"},
 | 
				
			||||||
  "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
 | 
					  "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
 | 
				
			||||||
| 
						 | 
					@ -43,7 +44,6 @@
 | 
				
			||||||
  "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
 | 
					  "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
 | 
				
			||||||
  "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
 | 
					  "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
 | 
				
			||||||
  "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
 | 
					  "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
 | 
				
			||||||
  "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"},
 | 
					 | 
				
			||||||
  "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
 | 
					  "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
 | 
				
			||||||
  "swoosh": {:hex, :swoosh, "1.14.3", "949e6bf6dd469449238a94ec6f19ec10b63fc8753de7f3ebe3d3aeaf772f4c6b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6c565103fc8f086bdd96e5c948660af8e20922b7a90a75db261f06a34f805c8b"},
 | 
					  "swoosh": {:hex, :swoosh, "1.14.3", "949e6bf6dd469449238a94ec6f19ec10b63fc8753de7f3ebe3d3aeaf772f4c6b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6c565103fc8f086bdd96e5c948660af8e20922b7a90a75db261f06a34f805c8b"},
 | 
				
			||||||
  "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
 | 
					  "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,4 @@ final: prev: {
 | 
				
			||||||
  elixir = prev.beam.packages.erlang_26.elixir_1_15;
 | 
					  elixir = prev.beam.packages.erlang_26.elixir_1_15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  elixir-ls = prev.beam.packages.erlang_26.elixir-ls.override { elixir = final.elixir; };
 | 
					  elixir-ls = prev.beam.packages.erlang_26.elixir-ls.override { elixir = final.elixir; };
 | 
				
			||||||
 | 
					 | 
				
			||||||
  protoc-gen-elixir = prev.callPackage ./protoc-gen-elixir.nix { elixir = final.elixir; };
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,28 +0,0 @@
 | 
				
			||||||
{ elixir, beamPackages, fetchFromGitHub }:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
beamPackages.mixRelease rec {
 | 
					 | 
				
			||||||
  pname = "protoc-gen-elixir";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  version = "v0.12.0";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  inherit elixir;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  src = fetchFromGitHub {
 | 
					 | 
				
			||||||
    owner = "elixir-protobuf";
 | 
					 | 
				
			||||||
    repo = "protobuf";
 | 
					 | 
				
			||||||
    rev = "ce9a031a5cae97336d4674670d313d54f1f80bf6";
 | 
					 | 
				
			||||||
    sha256 = "wLU3iM9jI/Zc96/HfPUjNvjteGryWos6IobIb/4zqpw=";
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mixFodDeps = beamPackages.fetchMixDeps {
 | 
					 | 
				
			||||||
    pname = "mix-deps-${pname}";
 | 
					 | 
				
			||||||
    inherit src version;
 | 
					 | 
				
			||||||
    sha256 = "H7yiBHoxuiqWcNbWwPU5X0Nnv8f6nM8z/ZAfZAGPZjE=";
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  installPhase = ''
 | 
					 | 
				
			||||||
    mix escript.build
 | 
					 | 
				
			||||||
    mkdir -p $out/bin
 | 
					 | 
				
			||||||
    mv ./protoc-gen-elixir $out/bin
 | 
					 | 
				
			||||||
  '';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,92 +0,0 @@
 | 
				
			||||||
syntax = "proto3";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "google/protobuf/empty.proto";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package prymn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message SystemHealth {
 | 
					 | 
				
			||||||
    // Comma-separated statuses
 | 
					 | 
				
			||||||
    string status = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message TaskHealth {
 | 
					 | 
				
			||||||
    string started_on = 1;
 | 
					 | 
				
			||||||
    float progress = 2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message HealthResponse {
 | 
					 | 
				
			||||||
    string version = 1;
 | 
					 | 
				
			||||||
    SystemHealth system = 2;
 | 
					 | 
				
			||||||
    map<string, TaskHealth> tasks = 3;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message SysInfoResponse {
 | 
					 | 
				
			||||||
    message Cpu {
 | 
					 | 
				
			||||||
        uint64 freq_mhz = 1;
 | 
					 | 
				
			||||||
        float  usage = 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    message Disk {
 | 
					 | 
				
			||||||
        string name = 1;
 | 
					 | 
				
			||||||
        uint64 total_bytes = 2;
 | 
					 | 
				
			||||||
        uint64 avail_bytes = 3;
 | 
					 | 
				
			||||||
        string mount_point = 4;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint64 uptime = 1;
 | 
					 | 
				
			||||||
    string hostname = 2;
 | 
					 | 
				
			||||||
    string os = 3;
 | 
					 | 
				
			||||||
    uint64 mem_total_bytes = 4;
 | 
					 | 
				
			||||||
    uint64 mem_avail_bytes = 5;
 | 
					 | 
				
			||||||
    uint64 swap_total_bytes = 6;
 | 
					 | 
				
			||||||
    uint64 swap_free_bytes = 7;
 | 
					 | 
				
			||||||
    repeated Cpu  cpus = 8;
 | 
					 | 
				
			||||||
    repeated Disk disks = 9;
 | 
					 | 
				
			||||||
    uint32 updates_available = 10;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message ExecRequest {
 | 
					 | 
				
			||||||
    string user = 1;
 | 
					 | 
				
			||||||
    string program = 2;
 | 
					 | 
				
			||||||
    repeated string args = 3;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message ExecResponse {
 | 
					 | 
				
			||||||
    oneof out {
 | 
					 | 
				
			||||||
        string stdout = 1;
 | 
					 | 
				
			||||||
        string stderr = 2;
 | 
					 | 
				
			||||||
        string error = 3;
 | 
					 | 
				
			||||||
        int32 exit_code = 4;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message SysUpdateRequest {
 | 
					 | 
				
			||||||
    bool dry_run = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message SysUpdateResponse {
 | 
					 | 
				
			||||||
    string output = 1;
 | 
					 | 
				
			||||||
    int32 progress = 2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message TerminalRequest {
 | 
					 | 
				
			||||||
    message Resize {
 | 
					 | 
				
			||||||
        uint32 rows = 1;
 | 
					 | 
				
			||||||
        uint32 cols = 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bytes input = 1;
 | 
					 | 
				
			||||||
    optional Resize resize = 2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
message TerminalResponse {
 | 
					 | 
				
			||||||
    bytes output = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
service Agent {
 | 
					 | 
				
			||||||
    rpc Health(google.protobuf.Empty) returns (stream HealthResponse);
 | 
					 | 
				
			||||||
    rpc Exec(ExecRequest) returns (stream ExecResponse);
 | 
					 | 
				
			||||||
    rpc Terminal(stream TerminalRequest) returns (stream TerminalResponse);
 | 
					 | 
				
			||||||
    rpc GetSysInfo(google.protobuf.Empty) returns (SysInfoResponse);
 | 
					 | 
				
			||||||
    rpc SysUpdate(SysUpdateRequest) returns (stream SysUpdateResponse);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,4 +0,0 @@
 | 
				
			||||||
# Used by "mix format"
 | 
					 | 
				
			||||||
[
 | 
					 | 
				
			||||||
  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
							
								
								
									
										26
									
								
								proto_compiler/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								proto_compiler/.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
# The directory Mix will write compiled artifacts to.
 | 
					 | 
				
			||||||
/_build/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# If you run "mix test --cover", coverage assets end up here.
 | 
					 | 
				
			||||||
/cover/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# The directory Mix downloads your dependencies sources to.
 | 
					 | 
				
			||||||
/deps/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Where third-party dependencies like ExDoc output generated docs.
 | 
					 | 
				
			||||||
/doc/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Ignore .fetch files in case you like to edit your project deps locally.
 | 
					 | 
				
			||||||
/.fetch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# If the VM crashes, it generates a dump, let's ignore it too.
 | 
					 | 
				
			||||||
erl_crash.dump
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Also ignore archive artifacts (built via "mix archive.build").
 | 
					 | 
				
			||||||
*.ez
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Ignore package tarball (built via "mix hex.build").
 | 
					 | 
				
			||||||
proto-*.tar
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Temporary files, for example, from tests.
 | 
					 | 
				
			||||||
/tmp/
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
defmodule Mix.Tasks.Compile.Proto do
 | 
					 | 
				
			||||||
  use Mix.Task.Compiler
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @manifest "compile.proto"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def run(_args) do
 | 
					 | 
				
			||||||
    output = "./app/lib/prymn_proto"
 | 
					 | 
				
			||||||
    sources = Path.wildcard("proto/*.proto")
 | 
					 | 
				
			||||||
    targets = Path.wildcard(output <> "/*.pb.ex")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if Mix.Utils.stale?(sources, targets) do
 | 
					 | 
				
			||||||
      {_, 0} = do_protoc(sources, output)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    :ok
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @impl true
 | 
					 | 
				
			||||||
  def manifests(), do: [manifest()]
 | 
					 | 
				
			||||||
  defp manifest(), do: Path.join(Mix.Project.manifest_path(), @manifest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  defp do_protoc(sources, output) do
 | 
					 | 
				
			||||||
    System.cmd(
 | 
					 | 
				
			||||||
      "protoc",
 | 
					 | 
				
			||||||
      [
 | 
					 | 
				
			||||||
        "--elixir_out=plugins=grpc:" <> output,
 | 
					 | 
				
			||||||
        "--elixir_opt=package_prefix=prymn_proto",
 | 
					 | 
				
			||||||
        "-I",
 | 
					 | 
				
			||||||
        "proto"
 | 
					 | 
				
			||||||
      ] ++ sources
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,22 +0,0 @@
 | 
				
			||||||
defmodule PrymnProtoCompiler.MixProject do
 | 
					 | 
				
			||||||
  use Mix.Project
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def project do
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
      app: :prymn_proto_compiler,
 | 
					 | 
				
			||||||
      version: "0.1.0",
 | 
					 | 
				
			||||||
      elixir: "~> 1.15",
 | 
					 | 
				
			||||||
      deps: deps()
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Run "mix help compile.app" to learn about applications.
 | 
					 | 
				
			||||||
  def application do
 | 
					 | 
				
			||||||
    []
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Run "mix help deps" to learn about dependencies.
 | 
					 | 
				
			||||||
  defp deps do
 | 
					 | 
				
			||||||
    []
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in a new issue