mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-02 05:52:55 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e9fee2a0 | ||
|
|
c403a1cee5 | ||
|
|
02d25b370a | ||
|
|
e5a3eec8a1 | ||
|
|
910352d66c | ||
|
|
c4f02e7d55 | ||
|
|
6a1197ad83 | ||
|
|
84c31bbb88 | ||
|
|
33f6c32306 | ||
|
|
5c71304d41 | ||
|
|
bbaf04e977 | ||
|
|
ad5b2d2eb3 | ||
|
|
3c064baf8a | ||
|
|
9e11b10d74 | ||
|
|
2fc45e00b4 | ||
|
|
45eb08fc3a | ||
|
|
fbcfae0200 | ||
|
|
9c4ce013ec |
54
CHANGELOG.md
54
CHANGELOG.md
@@ -2,6 +2,60 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.70.5](https://github.com/wanderer-industries/wanderer/compare/v1.70.4...v1.70.5) (2025-06-17)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Fixed character caching issues
|
||||
|
||||
## [v1.70.4](https://github.com/wanderer-industries/wanderer/compare/v1.70.3...v1.70.4) (2025-06-16)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Distribute tracking to minimal pool first
|
||||
|
||||
## [v1.70.3](https://github.com/wanderer-industries/wanderer/compare/v1.70.2...v1.70.3) (2025-06-16)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Don't pause tracking for new pools
|
||||
|
||||
## [v1.70.2](https://github.com/wanderer-industries/wanderer/compare/v1.70.1...v1.70.2) (2025-06-15)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Core: Invalidate character copr and ally data on map server start
|
||||
|
||||
## [v1.70.1](https://github.com/wanderer-industries/wanderer/compare/v1.70.0...v1.70.1) (2025-06-14)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* resolve api issue with custom name
|
||||
|
||||
## [v1.70.0](https://github.com/wanderer-industries/wanderer/compare/v1.69.1...v1.70.0) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
|
||||
### Features:
|
||||
|
||||
* Core: Fix admin page error
|
||||
|
||||
## [v1.69.1](https://github.com/wanderer-industries/wanderer/compare/v1.69.0...v1.69.1) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -16,10 +16,6 @@ defmodule WandererApp.Character do
|
||||
ship_item_id: nil
|
||||
}
|
||||
|
||||
@decorate cacheable(
|
||||
cache: WandererApp.Cache,
|
||||
key: "characters-#{character_eve_id}"
|
||||
)
|
||||
def get_by_eve_id(character_eve_id) when is_binary(character_eve_id) do
|
||||
WandererApp.Api.Character.by_eve_id(character_eve_id)
|
||||
end
|
||||
@@ -201,9 +197,9 @@ defmodule WandererApp.Character do
|
||||
end
|
||||
end
|
||||
|
||||
def can_track_wallet?(%{scopes: scopes} = _character) when not is_nil(scopes) do
|
||||
scopes |> String.split(" ") |> Enum.member?(@read_character_wallet_scope)
|
||||
end
|
||||
def can_track_wallet?(%{scopes: scopes, id: character_id} = _character)
|
||||
when is_binary(scopes) and is_binary(character_id),
|
||||
do: scopes |> String.split(" ") |> Enum.member?(@read_character_wallet_scope)
|
||||
|
||||
def can_track_wallet?(_), do: false
|
||||
|
||||
@@ -213,15 +209,12 @@ defmodule WandererApp.Character do
|
||||
|
||||
def can_track_corp_wallet?(_), do: false
|
||||
|
||||
@decorate cacheable(
|
||||
cache: WandererApp.Cache,
|
||||
key: "can_pause_tracking-#{character_id}"
|
||||
)
|
||||
def can_pause_tracking?(character_id) do
|
||||
case get_character(character_id) do
|
||||
{:ok, character} when not is_nil(character) ->
|
||||
{:ok, %{tracking_pool: tracking_pool} = character} when not is_nil(character) ->
|
||||
not WandererApp.Env.character_tracking_pause_disabled?() &&
|
||||
not can_track_corp_wallet?(character)
|
||||
not can_track_wallet?(character) &&
|
||||
(is_nil(tracking_pool) || tracking_pool == "default")
|
||||
|
||||
_ ->
|
||||
true
|
||||
|
||||
@@ -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",
|
||||
|
||||
142
lib/wanderer_app/character/tracking_config_utils.ex
Normal file
142
lib/wanderer_app/character/tracking_config_utils.ex
Normal file
@@ -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)
|
||||
|
||||
minimal_pool_id =
|
||||
pools
|
||||
|> Enum.filter(&(&1.value < tracking_pool_max_size))
|
||||
|> Enum.min_by(& &1.value)
|
||||
|> Map.get(:id)
|
||||
|
||||
if not is_nil(minimal_pool_id) do
|
||||
minimal_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} ->
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -76,6 +76,11 @@ defmodule WandererApp.Map.Operations do
|
||||
{:ok, map()} | {:skip, :exists} | {:error, String.t()}
|
||||
defdelegate create_connection(map_id, attrs, char_id), to: Connections
|
||||
|
||||
@doc "Create a connection from a Plug.Conn"
|
||||
@spec create_connection(Plug.Conn.t(), map()) ::
|
||||
{:ok, :created} | {:skip, :exists} | {:error, atom()}
|
||||
defdelegate create_connection(conn, attrs), to: Connections
|
||||
|
||||
@doc "Update a connection"
|
||||
@spec update_connection(String.t(), String.t(), map()) ::
|
||||
{:ok, map()} | {:error, String.t()}
|
||||
|
||||
@@ -5,9 +5,10 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
"""
|
||||
|
||||
require Logger
|
||||
alias WandererApp.Map.Server.{ConnectionsImpl, Server}
|
||||
alias WandererApp.Map.Server
|
||||
alias Ash.Error.Invalid
|
||||
alias WandererApp.MapConnectionRepo
|
||||
alias WandererApp.CachedInfo
|
||||
|
||||
# Connection type constants
|
||||
@connection_type_wormhole 0
|
||||
@@ -20,7 +21,7 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
@xlarge_ship_size 3
|
||||
|
||||
# System class constants
|
||||
@c1_system_class "C1"
|
||||
@c1_system_class 1
|
||||
|
||||
@doc """
|
||||
Creates a connection between two systems, applying special rules for C1 wormholes.
|
||||
@@ -34,8 +35,8 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
defp do_create(attrs, map_id, char_id) do
|
||||
with {:ok, source} <- parse_int(attrs["solar_system_source"], "solar_system_source"),
|
||||
{:ok, target} <- parse_int(attrs["solar_system_target"], "solar_system_target"),
|
||||
{:ok, src_info} <- ConnectionsImpl.get_system_static_info(source),
|
||||
{:ok, tgt_info} <- ConnectionsImpl.get_system_static_info(target) do
|
||||
{:ok, src_info} <- CachedInfo.get_system_static_info(source),
|
||||
{:ok, tgt_info} <- CachedInfo.get_system_static_info(target) do
|
||||
build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info)
|
||||
else
|
||||
{:error, reason} -> handle_precondition_error(reason, attrs)
|
||||
@@ -45,21 +46,28 @@ defmodule WandererApp.Map.Operations.Connections do
|
||||
end
|
||||
|
||||
defp build_and_add_connection(attrs, map_id, char_id, src_info, tgt_info) do
|
||||
info = %{
|
||||
solar_system_source_id: src_info.solar_system_id,
|
||||
solar_system_target_id: tgt_info.solar_system_id,
|
||||
character_id: char_id,
|
||||
type: parse_type(attrs["type"]),
|
||||
ship_size_type: resolve_ship_size(attrs, src_info, tgt_info)
|
||||
}
|
||||
Logger.debug("[Connections] build_and_add_connection called with src_info: #{inspect(src_info)}, tgt_info: #{inspect(tgt_info)}")
|
||||
|
||||
case Server.add_connection(map_id, info) do
|
||||
:ok -> {:ok, :created}
|
||||
{:ok, []} -> log_warn_and(:inconsistent_state, info)
|
||||
{:error, %Invalid{errors: errs}} = err ->
|
||||
if Enum.any?(errs, &is_unique_constraint_error?/1), do: {:skip, :exists}, else: err
|
||||
{:error, _} = err -> Logger.error("[add_connection] #{inspect(err)}"); {:error, :server_error}
|
||||
other -> Logger.error("[add_connection] unexpected: #{inspect(other)}"); {:error, :unexpected_error}
|
||||
# Guard against nil info
|
||||
if is_nil(src_info) or is_nil(tgt_info) do
|
||||
{:error, :invalid_system_info}
|
||||
else
|
||||
info = %{
|
||||
solar_system_source_id: src_info.solar_system_id,
|
||||
solar_system_target_id: tgt_info.solar_system_id,
|
||||
character_id: char_id,
|
||||
type: parse_type(attrs["type"]),
|
||||
ship_size_type: resolve_ship_size(attrs, src_info, tgt_info)
|
||||
}
|
||||
|
||||
case Server.add_connection(map_id, info) do
|
||||
:ok -> {:ok, :created}
|
||||
{:ok, []} -> log_warn_and(:inconsistent_state, info)
|
||||
{:error, %Invalid{errors: errs}} = err ->
|
||||
if Enum.any?(errs, &is_unique_constraint_error?/1), do: {:skip, :exists}, else: err
|
||||
{:error, _} = err -> Logger.error("[add_connection] #{inspect(err)}"); {:error, :server_error}
|
||||
other -> Logger.error("[add_connection] unexpected: #{inspect(other)}"); {:error, :unexpected_error}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -68,10 +63,17 @@ defmodule WandererApp.Esi.InitClientsTask do
|
||||
# config_uuid
|
||||
# )
|
||||
|
||||
configs_total_count =
|
||||
if id == "default" do
|
||||
0
|
||||
else
|
||||
id
|
||||
end
|
||||
|
||||
Cachex.put(
|
||||
:esi_auth_cache,
|
||||
"configs_total_count",
|
||||
id
|
||||
configs_total_count
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -266,6 +266,10 @@ defmodule WandererAppWeb.MapConnectionAPIController do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json(%{error: reason})
|
||||
{:error, :precondition_failed, _reason} ->
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json(%{error: "Invalid request parameters"})
|
||||
_other ->
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|
||||
@@ -24,6 +24,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
solar_system_id: %Schema{type: :integer, description: "EVE solar system ID"},
|
||||
solar_system_name: %Schema{type: :string, description: "EVE solar system name"},
|
||||
region_name: %Schema{type: :string, description: "EVE region name"},
|
||||
custom_name: %Schema{type: :string, nullable: true, description: "Custom name for the system"},
|
||||
position_x: %Schema{type: :integer, description: "X coordinate"},
|
||||
position_y: %Schema{type: :integer, description: "Y coordinate"},
|
||||
status: %Schema{
|
||||
@@ -137,6 +138,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
solar_system_id: 30_000_142,
|
||||
solar_system_name: "Jita",
|
||||
region_name: "The Forge",
|
||||
custom_name: "Trade Hub Central",
|
||||
position_x: 100.5,
|
||||
position_y: 200.3,
|
||||
status: "active",
|
||||
@@ -179,6 +181,7 @@ defmodule WandererAppWeb.MapSystemAPIController do
|
||||
solar_system_id: 30_000_142,
|
||||
solar_system_name: "Jita",
|
||||
region_name: "The Forge",
|
||||
custom_name: "Trade Hub Central",
|
||||
position_x: 100.5,
|
||||
position_y: 200.3,
|
||||
status: "active",
|
||||
|
||||
@@ -262,13 +262,18 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
||||
|
||||
@spec map_system_to_json(struct()) :: map()
|
||||
def map_system_to_json(system) do
|
||||
original = get_original_name(system.solar_system_id)
|
||||
|
||||
# Determine the actual custom_name: if name differs from original, use it as custom_name
|
||||
actual_custom_name = if system.name != original and system.name not in [nil, ""], do: system.name, else: system.custom_name
|
||||
|
||||
base =
|
||||
Map.take(system, ~w(
|
||||
id map_id solar_system_id custom_name temporary_name description tag labels
|
||||
id map_id solar_system_id temporary_name description tag labels
|
||||
locked visible status position_x position_y inserted_at updated_at
|
||||
)a)
|
||||
|> Map.put(:custom_name, actual_custom_name)
|
||||
|
||||
original = get_original_name(system.solar_system_id)
|
||||
name = pick_name(system)
|
||||
|
||||
base
|
||||
@@ -283,11 +288,15 @@ defmodule WandererAppWeb.Helpers.APIUtils do
|
||||
end
|
||||
end
|
||||
|
||||
defp pick_name(%{temporary_name: t, custom_name: c, solar_system_id: id}) do
|
||||
defp pick_name(%{temporary_name: t, custom_name: c, name: n, solar_system_id: id} = system) do
|
||||
original = get_original_name(id)
|
||||
|
||||
cond do
|
||||
t not in [nil, ""] -> t
|
||||
c not in [nil, ""] -> c
|
||||
true -> get_original_name(id)
|
||||
# If name differs from original, it's a custom name
|
||||
n not in [nil, ""] and n != original -> n
|
||||
true -> original
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -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,64 +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"
|
||||
)
|
||||
|
||||
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 = result ++ pools
|
||||
|
||||
{: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))
|
||||
|
||||
Reference in New Issue
Block a user