From 7b91ca224515357953ef221c4e8c9884fb5a4c04 Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Thu, 6 Jun 2024 10:56:23 -0400 Subject: [PATCH] Re-activate clients if they are restarted --- lib/chronoscope/nts.ex | 8 ++++-- lib/chronoscope/nts/client.ex | 9 ++++-- lib/chronoscope_web/client_activator.ex | 38 +++++++++++++++---------- lib/chronoscope_web/live/index_live.ex | 13 +++++++-- priv/nts.txt | 2 ++ 5 files changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/chronoscope/nts.ex b/lib/chronoscope/nts.ex index 4e4995d..e9a1686 100644 --- a/lib/chronoscope/nts.ex +++ b/lib/chronoscope/nts.ex @@ -25,12 +25,16 @@ defmodule Chronoscope.NTS do |> Enum.map(fn {_, pid, _, _} -> @genserver.call(pid, :list) end) end - def list_clients(clients) do - clients + def list_clients(servers) do + servers |> Enum.map(&client_pid/1) |> Enum.map(fn pid -> @genserver.call(pid, :list, @timeout_in_milliseconds) end) end + def start_client(server) do + client_pid(server) + end + def auto_refresh(server) do server |> client_pid() diff --git a/lib/chronoscope/nts/client.ex b/lib/chronoscope/nts/client.ex index 0acb101..bd4ba3a 100644 --- a/lib/chronoscope/nts/client.ex +++ b/lib/chronoscope/nts/client.ex @@ -3,6 +3,7 @@ defmodule Chronoscope.NTS.Client do alias Chronoscope.NTS alias Chronoscope.NTS.KeyEstablishmentClient + alias ChronoscopeWeb.Endpoint @interval_in_seconds 30 @timeout_in_milliseconds 10_000 @@ -17,13 +18,13 @@ defmodule Chronoscope.NTS.Client do @impl true def init(server) do - now = utc_now() + Endpoint.broadcast(@topic, "initializing", server) {:ok, %{ server: server, key_establishment_response: {:error, "initializing"}, - last_key_establishment: DateTime.add(now, -@interval_in_seconds, :second) + last_key_establishment: DateTime.add(utc_now(), -@interval_in_seconds, :second) }} end @@ -53,6 +54,8 @@ defmodule Chronoscope.NTS.Client do @impl true def handle_call(:cancel_auto_refresh, _from, %{timer: timer} = state) do :timer.cancel(timer) + Endpoint.broadcast(@topic, "cancel-auto-refresh", state.server) + {:reply, :ok, Map.delete(state, :timer)} end @@ -79,7 +82,7 @@ defmodule Chronoscope.NTS.Client do if interval_surpassed?(now, state.last_key_establishment) do state |> Map.merge(current_data(state, now)) - |> tap(&ChronoscopeWeb.Endpoint.broadcast(@topic, "key-exchange", Map.delete(&1, :timer))) + |> tap(&Endpoint.broadcast(@topic, "key-exchange", Map.delete(&1, :timer))) else state end diff --git a/lib/chronoscope_web/client_activator.ex b/lib/chronoscope_web/client_activator.ex index 381bee1..32ee207 100644 --- a/lib/chronoscope_web/client_activator.ex +++ b/lib/chronoscope_web/client_activator.ex @@ -5,9 +5,9 @@ defmodule ChronoscopeWeb.ClientActivator do alias Chronoscope.NTS alias Chronoscope.NTS.Parse + alias ChronoscopeWeb.Endpoint - @activate_interval_in_milliseconds 300_000 - + @topic Application.compile_env(:chronoscope, :nts_topic) @nts_file Application.compile_env(:chronoscope, :nts_file) def start_link(_) do @@ -16,29 +16,33 @@ defmodule ChronoscopeWeb.ClientActivator do @impl true def init(_) do - nts_servers = - nts_servers() - |> tap(fn servers -> Enum.each(servers, &NTS.auto_refresh/1) end) + Endpoint.subscribe(@topic) - :timer.send_interval(@activate_interval_in_milliseconds, :ensure_activated) - - {:ok, %{nts_servers: nts_servers}} + {:ok, %{nts_servers: nts_servers() |> tap(&start_clients/1)}} end @impl true - def handle_info(:ensure_activated, state) do - Enum.each(state.nts_servers, &NTS.auto_refresh/1) + def handle_info(%{topic: @topic, event: "initializing", payload: server}, state) do + if server in state.nts_servers do + Logger.info("activating #{inspect(server)}") + NTS.auto_refresh(server) + end {:noreply, state} end @impl true - def handle_info(:activate_clients, _state) do - nts_servers = - nts_servers() - |> tap(fn servers -> Enum.each(servers, &NTS.auto_refresh/1) end) + def handle_info(%{topic: @topic, event: "cancel-auto-refresh", payload: server}, state) do + if server in state.nts_servers do + Logger.info("#{inspect(server)} was deactivated") + end - {:noreply, %{nts_servers: nts_servers}} + {:noreply, state} + end + + @impl true + def handle_info(_, state) do + {:noreply, state} end @impl true @@ -46,6 +50,10 @@ defmodule ChronoscopeWeb.ClientActivator do {:reply, state.nts_servers, state} end + defp start_clients(servers) do + Enum.each(servers, &NTS.start_client/1) + end + defp nts_servers() do File.touch(Application.app_dir(:chronoscope, @nts_file)) diff --git a/lib/chronoscope_web/live/index_live.ex b/lib/chronoscope_web/live/index_live.ex index a6b43e5..74e4f7d 100644 --- a/lib/chronoscope_web/live/index_live.ex +++ b/lib/chronoscope_web/live/index_live.ex @@ -4,14 +4,17 @@ defmodule ChronoscopeWeb.IndexLive do alias Chronoscope.NTS alias Chronoscope.NTS.KeyEstablishmentResponse alias ChronoscopeWeb.ClientActivator + alias ChronoscopeWeb.Endpoint @topic Application.compile_env(:chronoscope, :nts_topic) + @impl true def mount(_params, _session, socket) do - ChronoscopeWeb.Endpoint.subscribe(@topic) + Endpoint.subscribe(@topic) {:ok, assign(socket, %{servers: server_list(), clients: client_list()})} end + @impl true def handle_info(%{topic: @topic, event: "key-exchange", payload: client}, socket) do if client.server in socket.assigns.servers do {:noreply, update(socket, :clients, &update_client(&1, client))} @@ -20,6 +23,11 @@ defmodule ChronoscopeWeb.IndexLive do end end + @impl true + def handle_info(_, socket) do + {:noreply, socket} + end + defp update_client(client_list, client) do Enum.map(client_list, &if(client.server == &1.server, do: client, else: &1)) end @@ -29,7 +37,6 @@ defmodule ChronoscopeWeb.IndexLive do end defp client_list() do - server_list() - |> NTS.list_clients() + server_list() |> NTS.list_clients() end end diff --git a/priv/nts.txt b/priv/nts.txt index 45016b4..562c952 100644 --- a/priv/nts.txt +++ b/priv/nts.txt @@ -5,3 +5,5 @@ paris.time.system76.com oregon.time.system76.com ohio.time.system76.com brazil.time.system76.com +time.cloudflare.com +nts.netnod.se