fix(Core): Invalidate character copr and ally data on map server start

This commit is contained in:
Dmitry Popov
2025-06-15 19:21:44 +02:00
parent fbcfae0200
commit ad5b2d2eb3
12 changed files with 220 additions and 120 deletions
+2
View File
@@ -120,6 +120,8 @@ config :wanderer_app,
corp_wallet_eve_id: System.get_env("WANDERER_CORP_WALLET_EVE_ID", "-1"),
public_api_disabled: public_api_disabled,
active_tracking_pool: System.get_env("WANDERER_ACTIVE_TRACKING_POOL", "default"),
tracking_pool_max_size:
System.get_env("WANDERER_TRACKING_POOL_MAX_SIZE", "300") |> String.to_integer(),
character_tracking_pause_disabled:
System.get_env("WANDERER_CHARACTER_TRACKING_PAUSE_DISABLED", "true")
|> String.to_existing_atom(),
+15 -12
View File
@@ -166,7 +166,7 @@ defmodule WandererApp.Character.Tracker do
def update_online(%{track_online: true, character_id: character_id} = character_state) do
case WandererApp.Character.get_character(character_id) do
{:ok, %{eve_id: eve_id, access_token: access_token}}
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
when not is_nil(access_token) ->
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
@@ -233,7 +233,7 @@ defmodule WandererApp.Character.Tracker do
{:error, :error_limited, headers} ->
reset_timeout = get_reset_timeout(headers)
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
WandererApp.Cache.put(
"character:#{character_id}:online_forbidden",
@@ -287,15 +287,15 @@ defmodule WandererApp.Character.Tracker do
defp get_reset_timeout(_headers, default_timeout), do: default_timeout
def update_info(character_id) do
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:info_forbidden") ||
(WandererApp.Cache.has_key?("character:#{character_id}:info_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|> case do
true ->
{:error, :skipped}
false ->
{:ok, %{eve_id: eve_id}} = WandererApp.Character.get_character(character_id)
{:ok, %{eve_id: eve_id, tracking_pool: tracking_pool}} =
WandererApp.Character.get_character(character_id)
case WandererApp.Esi.get_character_info(eve_id) do
{:ok, _info} ->
@@ -320,7 +320,7 @@ defmodule WandererApp.Character.Tracker do
{:error, :error_limited, headers} ->
reset_timeout = get_reset_timeout(headers)
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
WandererApp.Cache.put(
"character:#{character_id}:info_forbidden",
@@ -358,7 +358,8 @@ defmodule WandererApp.Character.Tracker do
character_id
|> WandererApp.Character.get_character()
|> case do
{:ok, %{eve_id: eve_id, access_token: access_token}} when not is_nil(access_token) ->
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
when not is_nil(access_token) ->
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:ship_forbidden") ||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
@@ -397,7 +398,7 @@ defmodule WandererApp.Character.Tracker do
{:error, :error_limited, headers} ->
reset_timeout = get_reset_timeout(headers)
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
WandererApp.Cache.put(
"character:#{character_id}:ship_forbidden",
@@ -462,7 +463,8 @@ defmodule WandererApp.Character.Tracker do
%{track_location: true, is_online: true, character_id: character_id} = character_state
) do
case WandererApp.Character.get_character(character_id) do
{:ok, %{eve_id: eve_id, access_token: access_token}} when not is_nil(access_token) ->
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
when not is_nil(access_token) ->
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused")
|> case do
true ->
@@ -494,7 +496,7 @@ defmodule WandererApp.Character.Tracker do
{:error, :skipped}
{:error, :error_limited, headers} ->
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
reset_timeout = get_reset_timeout(headers, @location_limit_ttl)
@@ -550,7 +552,8 @@ defmodule WandererApp.Character.Tracker do
character_id
|> WandererApp.Character.get_character()
|> case do
{:ok, %{eve_id: eve_id, access_token: access_token} = character}
{:ok,
%{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool} = character}
when not is_nil(access_token) ->
character
|> WandererApp.Character.can_track_wallet?()
@@ -589,7 +592,7 @@ defmodule WandererApp.Character.Tracker do
{:error, :error_limited, headers} ->
reset_timeout = get_reset_timeout(headers)
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
WandererApp.Cache.put(
"character:#{character_id}:wallet_forbidden",
@@ -0,0 +1,142 @@
defmodule WandererApp.Character.TrackingConfigUtils do
use Nebulex.Caching
@moduledoc false
@ttl :timer.minutes(5)
@last_active_character_minutes -1 * 60 * 24 * 7
@decorate cacheable(
cache: WandererApp.Cache,
key: "tracker-stats",
opts: [ttl: @ttl]
)
def load_tracker_stats() do
{:ok, characters} = get_active_characters()
admins_count =
characters |> Enum.filter(&WandererApp.Character.can_track_corp_wallet?/1) |> Enum.count()
with_wallets_count =
characters
|> Enum.filter(
&(WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
default_count =
characters
|> Enum.filter(
&(is_nil(&1.tracking_pool) and not WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
result = [
%{id: "admins", title: "Admins", value: admins_count},
%{id: "wallet", title: "With Wallet", value: with_wallets_count},
%{id: "default", title: "Default", value: default_count}
]
{:ok, pools_count} =
Cachex.get(
:esi_auth_cache,
"configs_total_count"
)
{:ok, pools} = get_pools_info(characters)
{:ok, result ++ pools}
end
def update_active_tracking_pool() do
{:ok, pools_count} =
Cachex.get(
:esi_auth_cache,
"configs_total_count"
)
active_pool =
if not is_nil(pools_count) && pools_count != 0 do
tracking_pool_max_size = WandererApp.Env.tracking_pool_max_size()
{:ok, characters} = get_active_characters()
{:ok, pools} = get_pools_info(characters)
pool =
pools
|> Enum.find(fn pool ->
pool.value < tracking_pool_max_size
end)
if not is_nil(pool) do
pool.id
else
"default"
end
else
"default"
end
Cachex.put(
:esi_auth_cache,
"active_pool",
active_pool
)
end
def get_active_pool!() do
Cachex.get(
:esi_auth_cache,
"active_pool"
)
|> case do
{:ok, active_pool} when not is_nil(active_pool) ->
active_pool
_ ->
"default"
end
end
defp get_active_characters() do
WandererApp.Api.Character.last_active(%{
from:
DateTime.utc_now()
|> DateTime.add(@last_active_character_minutes, :minute)
})
end
@decorate cacheable(
cache: WandererApp.Cache,
key: "character-pools-info",
opts: [ttl: @ttl]
)
defp get_pools_info(characters) do
{:ok, pools_count} =
Cachex.get(
:esi_auth_cache,
"configs_total_count"
)
if not is_nil(pools_count) && pools_count != 0 do
pools =
1..pools_count
|> Enum.map(fn pool_id ->
pools_character_count =
characters
|> Enum.filter(
&(&1.tracking_pool == "#{pool_id}" and
not WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
%{id: "#{pool_id}", title: "Pool #{pool_id}", value: pools_character_count}
end)
{:ok, pools}
else
{:ok, []}
end
end
end
@@ -146,7 +146,12 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
end
defp get_wallet_journal(
%{id: character_id, corporation_id: corporation_id, access_token: access_token} =
%{
id: character_id,
corporation_id: corporation_id,
access_token: access_token,
tracking_pool: tracking_pool
} =
_character,
division
)
@@ -164,7 +169,7 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
{:error, :forbidden}
{:error, :error_limited, _headers} ->
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
{:error, :error_limited}
{:error, error} ->
@@ -176,7 +181,12 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
defp get_wallet_journal(_character, _division), do: {:error, :skipped}
defp update_corp_wallets(
%{id: character_id, corporation_id: corporation_id, access_token: access_token} =
%{
id: character_id,
corporation_id: corporation_id,
access_token: access_token,
tracking_pool: tracking_pool
} =
_character
)
when not is_nil(access_token) do
@@ -193,7 +203,7 @@ defmodule WandererApp.Character.TransactionsTracker.Impl do
{:error, :forbidden}
{:error, :error_limited, _headers} ->
Logger.warning(".")
Logger.warning("#{inspect(tracking_pool)} ..")
{:error, :error_limited}
{:error, error} ->
+6
View File
@@ -22,6 +22,12 @@ defmodule WandererApp.Env do
key: "active_tracking_pool"
)
def active_tracking_pool, do: get_key(:active_tracking_pool, "default")
@decorate cacheable(
cache: WandererApp.Cache,
key: "tracking_pool_max_size"
)
def tracking_pool_max_size, do: get_key(:tracking_pool_max_size, 300)
def character_tracking_pause_disabled?, do: get_key(:character_tracking_pause_disabled, true)
def character_api_disabled?, do: get_key(:character_api_disabled, false)
def zkill_preload_disabled?, do: get_key(:zkill_preload_disabled, false)
+10 -15
View File
@@ -138,13 +138,8 @@ defmodule WandererApp.Map do
def add_characters!(map, []), do: map
def add_characters!(%{map_id: map_id} = map, [character | rest]) do
case add_character(map_id, character) do
:ok ->
add_characters!(map, rest)
{:error, :already_exists} ->
add_characters!(map, rest)
end
add_character(map_id, character)
add_characters!(map, rest)
end
def add_character(
@@ -172,15 +167,15 @@ defmodule WandererApp.Map do
map_id
|> update_map(%{characters: [character_id | characters]})
WandererApp.Cache.insert(
"map:#{map_id}:character:#{character_id}:alliance_id",
alliance_id
)
# WandererApp.Cache.insert(
# "map:#{map_id}:character:#{character_id}:alliance_id",
# alliance_id
# )
WandererApp.Cache.insert(
"map:#{map_id}:character:#{character_id}:corporation_id",
corporation_id
)
# WandererApp.Cache.insert(
# "map:#{map_id}:character:#{character_id}:corporation_id",
# corporation_id
# )
# WandererApp.Cache.insert(
# "map:#{map_id}:character:#{character_id}:solar_system_id",
+1 -1
View File
@@ -192,7 +192,7 @@ defmodule WandererApp.Ueberauth.Strategy.Eve do
end
defp oauth_client_options_from_conn(conn, with_wallet, is_admin?) do
tracking_pool = WandererApp.Env.active_tracking_pool()
tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
base_options = [
redirect_uri: callback_url(conn),
@@ -10,13 +10,8 @@ defmodule WandererApp.Esi.InitClientsTask do
def run(_arg) do
Logger.info("starting")
Cachex.put(
:esi_auth_cache,
:active_config,
"config_#{WandererApp.Env.active_tracking_pool()}"
)
cache_clients()
WandererApp.Character.TrackingConfigUtils.update_active_tracking_pool()
end
defp cache_clients() do
@@ -8,6 +8,8 @@ defmodule WandererAppWeb.AuthController do
require Logger
def callback(%{assigns: %{ueberauth_auth: auth, current_user: user} = _assigns} = conn, _params) do
active_tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
character_data = %{
eve_id: "#{auth.info.email}",
name: auth.info.name,
@@ -15,7 +17,7 @@ defmodule WandererAppWeb.AuthController do
refresh_token: auth.credentials.refresh_token,
expires_at: auth.credentials.expires_at,
scopes: auth.credentials.scopes,
tracking_pool: WandererApp.Env.active_tracking_pool()
tracking_pool: active_tracking_pool
}
%{
@@ -31,7 +33,7 @@ defmodule WandererAppWeb.AuthController do
refresh_token: auth.credentials.refresh_token,
expires_at: auth.credentials.expires_at,
scopes: auth.credentials.scopes,
tracking_pool: WandererApp.Env.active_tracking_pool()
tracking_pool: active_tracking_pool
}
{:ok, character} =
@@ -80,6 +82,8 @@ defmodule WandererAppWeb.AuthController do
maybe_update_character_user_id(character, user_id)
WandererApp.Character.TrackingConfigUtils.update_active_tracking_pool()
conn
|> put_session(:user_id, user_id)
|> redirect(to: "/characters")
+4 -65
View File
@@ -63,6 +63,7 @@ defmodule WandererAppWeb.AdminLive do
user_id: user_id,
invite_link: nil,
tracker_stats: [],
active_tracking_pool: "default",
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?(),
restrict_maps_creation?: WandererApp.Env.restrict_maps_creation?()
)}
@@ -295,7 +296,8 @@ defmodule WandererAppWeb.AdminLive do
defp apply_action(socket, :index, _params, uri) do
{:ok, invites} = WandererApp.Api.MapInvite.read()
{:ok, tracker_stats} = load_tracker_stats()
{:ok, tracker_stats} = WandererApp.Character.TrackingConfigUtils.load_tracker_stats()
active_tracking_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
socket
|> assign(:active_page, :admin)
@@ -312,6 +314,7 @@ defmodule WandererAppWeb.AdminLive do
|> assign(:unlink_character_form, to_form(%{}))
|> assign(:invites, invites)
|> assign(:tracker_stats, tracker_stats)
|> assign(:active_tracking_pool, active_tracking_pool)
end
defp apply_action(socket, :add_invite_link, _params, uri) do
@@ -348,70 +351,6 @@ defmodule WandererAppWeb.AdminLive do
|> assign(:invites, [])
end
defp load_tracker_stats() do
{:ok, characters} =
WandererApp.Api.Character.last_active(%{
from:
DateTime.utc_now()
|> DateTime.add(-1 * 60 * 24 * 7, :minute)
})
admins_count =
characters |> Enum.filter(&WandererApp.Character.can_track_corp_wallet?/1) |> Enum.count()
with_wallets_count =
characters
|> Enum.filter(
&(WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
default_count =
characters
|> Enum.filter(
&(is_nil(&1.tracking_pool) and not WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
result = [
%{title: "Admins", value: admins_count},
%{title: "With Wallet", value: with_wallets_count},
%{title: "Default", value: default_count}
]
{:ok, pools_count} =
Cachex.get(
:esi_auth_cache,
"configs_total_count"
)
result =
if not is_nil(pools_count) && pools_count != 0 do
pools =
1..pools_count
|> Enum.map(fn pool_id ->
pools_character_count =
characters
|> Enum.filter(
&(&1.tracking_pool == "#{pool_id}" and
not WandererApp.Character.can_track_wallet?(&1) and
not WandererApp.Character.can_track_corp_wallet?(&1))
)
|> Enum.count()
%{title: "Pool #{pool_id}", value: pools_character_count}
end)
result ++ pools
else
result
end
{:ok, result}
end
defp get_invite_link(uri, token) do
uri
|> Map.put(:path, "/auth/eve")
@@ -129,18 +129,18 @@
>
<:col :let={invite} label="Link">
<div class="flex items-center">
<div class="w-[200px] no-wrap truncate"><%= get_invite_link(@uri, invite.token) %></div>
<.button
phx-hook="CopyToClipboard"
id="copy-to-clipboard"
class="copy-link btn btn-neutral rounded-none"
data-url={get_invite_link(@uri, invite.token)}
>
Copy
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
Link copied
</div>
</.button>
<div class="w-[200px] no-wrap truncate"><%= get_invite_link(@uri, invite.token) %></div>
<.button
phx-hook="CopyToClipboard"
id="copy-to-clipboard"
class="copy-link btn btn-neutral rounded-none"
data-url={get_invite_link(@uri, invite.token)}
>
Copy
<div class="absolute w-[100px] !mr-[-170px] link-copied hidden">
Link copied
</div>
</.button>
</div>
</:col>
<:col :let={invite} label="Type">
@@ -171,6 +171,7 @@
<div class="card dark:bg-zinc-800 dark:border-zinc-600">
<div class="card-body">
<div class="col-span-6">
<span class="text-gray-400 dark:text-gray-400">Tracking Pools</span>
<.table
id="tracking_pools"
@@ -180,6 +181,9 @@
<:col :let={stat} label="Pool">
<div class="w-[200px] no-wrap truncate">{stat.title}</div>
</:col>
<:col :let={stat} label="Active">
<div :if={stat.id == @active_tracking_pool}>true</div>
</:col>
<:col :let={stat} label="Count">
{stat.value}
</:col>
@@ -5,8 +5,6 @@ defmodule WandererAppWeb.CharactersLive do
alias BetterNumber, as: Number
@active_tracking_pool 1
def mount(_params, %{"user_id" => user_id} = _session, socket)
when not is_nil(user_id) do
{:ok, characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id})
@@ -59,10 +57,12 @@ defmodule WandererAppWeb.CharactersLive do
def handle_event("authorize", form, socket) do
track_wallet = form |> Map.get("track_wallet", false)
active_pool = WandererApp.Character.TrackingConfigUtils.get_active_pool!()
{:ok, esi_config} =
Cachex.get(
:esi_auth_cache,
"config_#{WandererApp.Env.active_tracking_pool()}"
"config_#{active_pool}"
)
WandererApp.Cache.put("invite_#{esi_config.uuid}", true, ttl: :timer.minutes(30))