defmodule WandererApp.Map.Server do @moduledoc """ Holds state for a map and exposes an interface to managing the map instance """ use GenServer, restart: :transient, significant: true require Logger alias WandererApp.Map.Server.Impl @logger Application.compile_env(:wanderer_app, :logger) @spec start_link(keyword()) :: GenServer.on_start() def start_link(args) when is_list(args) do GenServer.start_link(__MODULE__, args, name: _via(args[:map_id])) end @impl true def init(args), do: {:ok, Impl.init(args), {:continue, :load_state}} def map_pid(map_id), do: map_id |> _via() |> GenServer.whereis() def map_pid!(map_id) do map_id |> map_pid() |> case do map_id when is_pid(map_id) -> map_id nil -> WandererApp.Cache.insert("map_#{map_id}:started", false) throw("Map server not started") end end def get_map(pid) when is_pid(pid), do: pid |> GenServer.call({&Impl.get_map/1, []}, :timer.minutes(5)) def get_map(map_id) when is_binary(map_id), do: map_id |> map_pid! |> get_map() def get_export_settings(%{id: map_id, hubs: hubs} = _map) do with {:ok, all_systems} <- WandererApp.MapSystemRepo.get_all_by_map(map_id), {:ok, connections} <- WandererApp.MapConnectionRepo.get_by_map(map_id) do {:ok, %{ systems: all_systems, hubs: hubs, connections: connections }} else error -> @logger.error("Failed to get export settings: #{inspect(error, pretty: true)}") {:ok, %{ systems: [], hubs: [], connections: [] }} end end def get_characters(map_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.call({&Impl.get_characters/1, []}, :timer.minutes(1)) def add_character(map_id, character, track_character \\ false) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_character/3, [character, track_character]}) def remove_character(map_id, character_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.remove_character/2, [character_id]}) def untrack_characters(map_id, character_ids) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.untrack_characters/2, [character_ids]}) def add_system(map_id, system_info, user_id, character_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_system/4, [system_info, user_id, character_id]}) def add_system_comment(map_id, comment_info, user_id, character_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_system_comment/4, [comment_info, user_id, character_id]}) def remove_system_comment(map_id, comment_id, user_id, character_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.remove_system_comment/4, [comment_id, user_id, character_id]}) def update_system_position(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_position/2, [update]}) def update_system_linked_sig_eve_id(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_linked_sig_eve_id/2, [update]}) def update_system_name(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_name/2, [update]}) def update_system_description(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_description/2, [update]}) def update_system_status(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_status/2, [update]}) def update_system_tag(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_tag/2, [update]}) def update_system_temporary_name(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_temporary_name/2, [update]}) def update_system_locked(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_locked/2, [update]}) def update_system_labels(map_id, update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_system_labels/2, [update]}) def add_hub(map_id, hub_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_hub/2, [hub_info]}) def remove_hub(map_id, hub_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.remove_hub/2, [hub_info]}) def add_ping(map_id, ping_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_ping/2, [ping_info]}) def cancel_ping(map_id, ping_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.cancel_ping/2, [ping_info]}) def delete_systems(map_id, solar_system_ids, user_id, character_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.delete_systems/4, [solar_system_ids, user_id, character_id]}) def add_connection(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.add_connection/2, [connection_info]}) def import_settings(map_id, settings, user_id) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.call({&Impl.import_settings/3, [settings, user_id]}, :timer.minutes(30)) def update_subscription_settings(map_id, settings) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_subscription_settings/2, [settings]}) def delete_connection(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.delete_connection/2, [connection_info]}) def get_connection_info(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.call({&Impl.get_connection_info/2, [connection_info]}, :timer.minutes(1)) def update_connection_time_status(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_time_status/2, [connection_info]}) def update_connection_type(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_type/2, [connection_info]}) def update_connection_mass_status(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_mass_status/2, [connection_info]}) def update_connection_ship_size_type(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_ship_size_type/2, [connection_info]}) def update_connection_locked(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_locked/2, [connection_info]}) def update_connection_custom_info(map_id, connection_info) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_connection_custom_info/2, [connection_info]}) def update_signatures(map_id, signatures_update) when is_binary(map_id), do: map_id |> map_pid! |> GenServer.cast({&Impl.update_signatures/2, [signatures_update]}) @impl true def handle_continue(:load_state, state), do: {:noreply, state |> Impl.load_state(), {:continue, :start_map}} @impl true def handle_continue(:start_map, state), do: {:noreply, state |> Impl.start_map()} @impl true def handle_call( {impl_function, args}, _from, state ) when is_function(impl_function), do: WandererApp.GenImpl.apply_call(impl_function, state, args) @impl true def handle_cast(:stop, state), do: {:stop, :normal, state |> Impl.stop_map()} @impl true def handle_cast({impl_function, args}, state) when is_function(impl_function) do case WandererApp.GenImpl.apply_call(impl_function, state, args) do {:reply, _return, updated_state} -> {:noreply, updated_state} _ -> {:noreply, state} end end @impl true def handle_info(event, state), do: {:noreply, Impl.handle_event(event, state)} defp _via(map_id), do: {:via, Registry, {WandererApp.MapRegistry, map_id}} end