fix(Core): Fixed issues with main character & tracking
Build / 🚀 Deploy to test env (fly.io) (push) Has been cancelled
Build / Manual Approval (push) Has been cancelled
Build / 🛠 Build (1.17, 18.x, 27) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/amd64) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/arm64) (push) Has been cancelled
Build / merge (push) Has been cancelled
Build / 🏷 Create Release (push) Has been cancelled

This commit is contained in:
Dmitry Popov
2025-04-15 12:15:08 +02:00
parent 8412e3867d
commit ecb3ca2b4e
16 changed files with 105 additions and 74 deletions
@@ -17,6 +17,7 @@ defmodule WandererApp.Api.MapCharacterSettings do
define(:read_by_map, action: :read_by_map)
define(:by_map_filtered, action: :by_map_filtered)
define(:tracked_by_map_filtered, action: :tracked_by_map_filtered)
define(:tracked_by_character, action: :tracked_by_character)
define(:tracked_by_map_all, action: :tracked_by_map_all)
define(:track, action: :track)
@@ -61,6 +62,11 @@ defmodule WandererApp.Api.MapCharacterSettings do
filter(expr(map_id == ^arg(:map_id) and tracked == true))
end
read :tracked_by_character do
argument(:character_id, :uuid, allow_nil?: false)
filter(expr(character_id == ^arg(:character_id) and tracked == true))
end
update :track do
accept [:map_id, :character_id]
argument :map_id, :string, allow_nil?: false
+2 -2
View File
@@ -33,7 +33,7 @@ defmodule WandererApp.Esi.ApiClient do
@cache_opts [cache: true]
@retry_opts [max_retries: 1, retry_log_level: :warning]
@timeout_opts [receive_timeout: :timer.seconds(30)]
@timeout_opts [pool_timeout: 15_000, receive_timeout: :timer.seconds(30)]
@api_retry_count 1
@logger Application.compile_env(:wanderer_app, :logger)
@@ -490,7 +490,7 @@ defmodule WandererApp.Esi.ApiClient do
try do
case Req.get(
"#{@base_url}#{path}",
api_opts |> with_user_agent_opts() |> with_cache_opts() |> Keyword.merge(@retry_opts)
api_opts |> with_user_agent_opts() |> with_cache_opts() |> Keyword.merge(@retry_opts) |> Keyword.merge(@timeout_opts)
) do
{:ok, %{status: 200, body: body}} ->
{:ok, body}
+2 -2
View File
@@ -70,7 +70,7 @@ defmodule WandererApp.Map.Audit do
def track_acl_event(
event_type,
%{user_id: user_id, acl_id: acl_id} = metadata
),
) when not is_nil(user_id) and not is_nil(acl_id),
do:
WandererApp.Api.UserActivity.new(%{
user_id: user_id,
@@ -85,7 +85,7 @@ defmodule WandererApp.Map.Audit do
def track_map_event(
event_type,
%{character_id: character_id, user_id: user_id, map_id: map_id} = metadata
),
) when not is_nil(character_id) and not is_nil(user_id) and not is_nil(map_id),
do:
WandererApp.Api.UserActivity.new(%{
character_id: character_id,
+1
View File
@@ -32,6 +32,7 @@ defmodule WandererApp.Map.Server do
map_id
nil ->
WandererApp.Cache.insert("map_#{map_id}:started", false)
throw("Map server not started")
end
end
@@ -86,6 +86,25 @@ defmodule WandererApp.Map.Server.AclsImpl do
end
end
def handle_acl_deleted(map_id, acl_id) do
{:ok, map} =
WandererApp.MapRepo.get(map_id,
acls: [
:owner_id,
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
]
)
WandererApp.Map.update_map(map_id, %{acls: map.acls})
character_ids =
map_id
|> WandererApp.Map.get_map!()
|> Map.get(:characters, [])
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", character_ids)
end
def track_acls([]), do: :ok
def track_acls([acl_id | rest]) do
@@ -64,6 +64,16 @@ defmodule WandererApp.Map.Server.CharactersImpl do
map_tracked_character_ids
|> Enum.filter(fn character -> character in tracked_characters end)
{:ok, old_map_tracked_characters} = WandererApp.Cache.lookup("maps:#{map_id}:tracked_characters", [])
characters_to_remove = old_map_tracked_characters -- map_active_tracked_characters
{:ok, invalidate_character_ids} =
WandererApp.Cache.lookup(
"map_#{map_id}:invalidate_character_ids",
[]
)
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", (invalidate_character_ids ++ characters_to_remove) |> Enum.uniq())
WandererApp.Cache.insert("maps:#{map_id}:tracked_characters", map_active_tracked_characters)
:ok
@@ -98,6 +108,9 @@ defmodule WandererApp.Map.Server.CharactersImpl do
character_id
|> WandererApp.Character.get_character()
|> case do
{:ok, %{user_id: nil}} ->
{:remove_character, character_id}
{:ok, character} ->
[character_permissions] =
WandererApp.Permissions.check_characters_access([character], acls)
@@ -377,12 +377,11 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
Impl.broadcast!(map_id, :add_connection, connection)
{:ok, character} = WandererApp.Character.get_character(character_id)
{:ok, character_with_user} = character |> Ash.load(:user)
{:ok, _} =
WandererApp.User.ActivityTracker.track_map_event(:map_connection_added, %{
character_id: character_id,
user_id: character_with_user.user_id,
user_id: character.user_id,
map_id: map_id,
solar_system_source_id: old_location.solar_system_id,
solar_system_target_id: location.solar_system_id
@@ -261,6 +261,12 @@ defmodule WandererApp.Map.Server.Impl do
state
end
def handle_event({:acl_deleted, %{acl_id: acl_id}}, %{map_id: map_id} = state) do
AclsImpl.handle_acl_updated(map_id, acl_id)
state
end
def handle_event(:cleanup_connections, state) do
Process.send_after(self(), :cleanup_connections, @connections_cleanup_timeout)
@@ -299,7 +305,7 @@ defmodule WandererApp.Map.Server.Impl do
%{state | map_opts: map_options(options)}
end
def handle_event({ref, _result}, %{map_id: _map_id} = state) do
def handle_event({ref, _result}, %{map_id: _map_id} = state) when is_reference(ref) do
Process.demonitor(ref, [:flush])
state
@@ -175,10 +175,6 @@ defmodule WandererApp.Zkb.KillsPreloader do
reduce_task_result(pass_type, task_result, acc_state, acc_map)
end)
if map_size(kills_map) > 0 do
broadcast_all_kills(kills_map, pass_type)
end
final_state
end
@@ -276,22 +272,6 @@ defmodule WandererApp.Zkb.KillsPreloader do
defp log_failed_task(:expanded, reason),
do: Logger.error("[KillsPreloader] Expanded fetch task failed => #{inspect(reason)}")
defp broadcast_all_kills(kills_map, pass_type) do
Logger.info(
"[KillsPreloader] Broadcasting kills => #{map_size(kills_map)} systems (#{pass_type})"
)
Phoenix.PubSub.broadcast!(
WandererApp.PubSub,
"zkb_preload",
%{
event: :detailed_kills_updated,
payload: kills_map,
fetch_type: pass_type
}
)
end
defp merge_calls_count(%{calls_count: c1} = st1, %{calls_count: c2}),
do: %{st1 | calls_count: c1 + c2}
@@ -64,9 +64,22 @@ defmodule WandererAppWeb.CharactersLive do
@impl true
def handle_event("delete", %{"character_id" => character_id}, socket) do
socket.assigns.characters
|> Enum.find(&(&1.id == character_id))
|> WandererApp.Api.Character.mark_as_deleted!()
WandererApp.Character.TrackerManager.stop_tracking(character_id)
{:ok, map_user_settings} = WandererApp.Api.MapCharacterSettings.tracked_by_character(%{character_id: character_id})
map_user_settings
|> Enum.each(fn settings ->
settings
|> WandererApp.Api.MapCharacterSettings.untrack()
end)
{:ok, updated_character} =
socket.assigns.characters
|> Enum.find(&(&1.id == character_id))
|> WandererApp.Api.Character.mark_as_deleted()
WandererApp.Character.update_character(character_id, updated_character)
{:ok, characters} =
WandererApp.Api.Character.active_by_user(%{user_id: socket.assigns.user_id})
@@ -79,7 +79,7 @@
</div>
</.link>
<div
:for={character <- @characters}
:for={character <- @characters |> Enum.sort_by(& &1.name, :asc)}
class="card rounded-none bg-gradient-to-l from-stone-950 to-stone-900 hover:text-white transform transition duration-500"
>
<figure class="avatar">
@@ -74,12 +74,12 @@ defmodule WandererAppWeb.MapActivityEventHandler do
}
end)
{:activity_data, summarized_result}
{:character_activity_data, summarized_result}
rescue
e ->
Logger.error("Error processing character activity: #{inspect(e)}")
Logger.error("#{Exception.format_stacktrace()}")
{:activity_data, []}
{:character_activity_data, []}
end
end)
@@ -240,12 +240,19 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
{:ok, tracking_data} =
WandererApp.Character.TrackingUtils.build_tracking_data(map_id, current_user_id)
{:ok, main_character_id} =
{main_character_id, main_character_eve_id} =
WandererApp.Character.TrackingUtils.get_main_character(
map_user_settings,
current_user_characters,
current_user_characters
)
|> case do
{:ok, main_character} when not is_nil(main_character) ->
{main_character.id, main_character.eve_id}
_ ->
{nil, nil}
end
Process.send_after(self(), %{event: :refresh_user_characters}, 50)
@@ -254,7 +261,7 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
|> assign(
map_user_settings: map_user_settings,
main_character_id: main_character_id,
main_character_eve_id: character_eve_id
main_character_eve_id: main_character_eve_id
)}
end
@@ -335,12 +335,20 @@ defmodule WandererAppWeb.MapCoreEventHandler do
only_tracked_characters
)
{:ok, main_character} =
{main_character_id, main_character_eve_id} =
WandererApp.Character.TrackingUtils.get_main_character(
map_user_settings,
current_user_characters,
available_map_characters
)
|> case do
{:ok, main_character} when not is_nil(main_character) ->
{main_character.id, main_character.eve_id}
_ ->
{nil, nil}
end
following_character_eve_id = case map_user_settings do
nil -> nil
@@ -351,8 +359,8 @@ defmodule WandererAppWeb.MapCoreEventHandler do
%{
user_permissions: user_permissions,
map_user_settings: map_user_settings,
main_character_id: main_character.id,
main_character_eve_id: main_character.eve_id,
main_character_id: main_character_id,
main_character_eve_id: main_character_eve_id,
following_character_eve_id: following_character_eve_id,
tracked_characters: tracked_data.tracked_characters,
all_character_tracked?: tracked_data.all_tracked?,
@@ -45,12 +45,20 @@ defmodule WandererAppWeb.MapKillsEventHandler do
)
end
def handle_server_event(%{event: :detailed_kills_updated, payload: payload}, socket) do
socket
|> MapEventHandler.push_map_event(
"detailed_kills_updated",
payload
)
def handle_server_event(%{event: :detailed_kills_updated, payload: payload}, %{
assigns: %{
map_id: map_id
}
} = socket) do
case WandererApp.Map.is_subscription_active?(map_id) do
{:ok, true} ->
socket
|> MapEventHandler.push_map_event(
"detailed_kills_updated",
payload
)
_ -> socket
end
end
def handle_server_event(
@@ -173,28 +173,10 @@ defmodule WandererAppWeb.MapEventHandler do
when event_name in @map_signatures_events,
do: MapSignaturesEventHandler.handle_server_event(event, socket)
def handle_event(
%{
assigns: %{
is_subscription_active?: true
}
} = socket,
%{event: event_name} = event
)
def handle_event(socket, %{event: event_name} = event)
when event_name in @map_kills_events,
do: MapKillsEventHandler.handle_server_event(event, socket)
def handle_event(
%{
assigns: %{
is_subscription_active?: false
}
} = socket,
%{event: event_name} = _event
)
when event_name in @map_kills_events,
do: socket
def handle_event(socket, {ref, result}) when is_reference(ref) do
Process.demonitor(ref, [:flush])
@@ -203,12 +185,6 @@ defmodule WandererAppWeb.MapEventHandler do
Process.send_after(self(), map_error, 100)
socket
{:activity_data, activity_data} ->
MapActivityEventHandler.handle_server_event(
%{event: :character_activity_data, payload: activity_data},
socket
)
{event, payload} ->
Process.send_after(
self(),
@@ -227,11 +203,6 @@ defmodule WandererAppWeb.MapEventHandler do
def handle_event(socket, {:DOWN, ref, :process, _pid, reason}) when is_reference(ref) do
# Task failed, log the error and update the client
Logger.error("Task failed: #{inspect(reason)}")
MapActivityEventHandler.handle_server_event(
%{event: :character_activity_data, payload: []},
socket
)
end
def handle_event(socket, event),