mirror of
https://github.com/wanderer-industries/wanderer
synced 2026-05-01 15:00:31 +00:00
269 lines
8.0 KiB
Elixir
269 lines
8.0 KiB
Elixir
defmodule WandererApp.RouteBuilderClient do
|
|
@moduledoc """
|
|
HTTP client for the local route builder service.
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@timeout_opts [pool_timeout: 5_000, receive_timeout: :timer.seconds(30)]
|
|
@loot_dir Path.join(["repo", "data", "route_by_systems"])
|
|
@available_routes_by ["blueLoot", "redLoot", "thera", "turnur", "so_cleaning", "trade_hubs"]
|
|
|
|
def available_routes_by(), do: @available_routes_by
|
|
|
|
def find_closest(
|
|
%{
|
|
origin: origin,
|
|
flag: flag,
|
|
connections: connections,
|
|
avoid: avoid,
|
|
count: count,
|
|
type: type,
|
|
security_type: security_type
|
|
} = payload
|
|
) do
|
|
url = "#{WandererApp.Env.custom_route_base_url()}/route/findClosest"
|
|
|
|
routes_settings = Map.get(payload, :routes_settings, %{})
|
|
destinations = destinations_for(type, security_type, routes_settings)
|
|
|
|
payload = %{
|
|
origin: origin,
|
|
flag: flag,
|
|
connections: connections || [],
|
|
avoid: avoid || [],
|
|
destinations: destinations,
|
|
count: count || 1
|
|
}
|
|
|
|
case Req.post(url, Keyword.merge([json: payload], @timeout_opts)) do
|
|
{:ok, %{status: status, body: body}} when status in [200, 201] ->
|
|
{:ok, body}
|
|
|
|
{:ok, %{status: status, body: body}} ->
|
|
Logger.warning("[RouteBuilderClient] Unexpected status: #{status}")
|
|
{:error, {:unexpected_status, status, body}}
|
|
|
|
{:error, reason} ->
|
|
Logger.error("[RouteBuilderClient] Request failed: #{inspect(reason)}")
|
|
{:error, reason}
|
|
end
|
|
end
|
|
|
|
defp destinations_for(type, security_type, routes_settings) do
|
|
case normalize_type(type) do
|
|
:thera ->
|
|
thera_destinations(routes_settings, security_type)
|
|
|
|
:turnur ->
|
|
turnur_destinations(routes_settings, security_type)
|
|
|
|
_ ->
|
|
case load_loot_data(type) do
|
|
{:ok, %{"system_ids_by_band" => by_band}} ->
|
|
high = Map.get(by_band, "high", [])
|
|
low = Map.get(by_band, "low", [])
|
|
pick_by_band(high, low, security_type)
|
|
|
|
{:ok, %{"system_ids" => system_ids}} when is_list(system_ids) ->
|
|
filter_by_security(system_ids, security_type)
|
|
|
|
{:error, reason} ->
|
|
Logger.error("[RouteBuilderClient] Failed to load loot data: #{inspect(reason)}")
|
|
[]
|
|
|
|
_ ->
|
|
[]
|
|
end
|
|
end
|
|
end
|
|
|
|
defp thera_destinations(routes_settings, security_type) do
|
|
{:ok, thera_chains} = WandererApp.Server.TheraDataFetcher.get_chain_pairs(routes_settings)
|
|
|
|
system_ids =
|
|
thera_chains
|
|
|> Enum.map(fn %{first: first, second: second} ->
|
|
pick_thera_destination(first, second)
|
|
end)
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.uniq()
|
|
|
|
filter_by_security(system_ids, security_type)
|
|
end
|
|
|
|
defp turnur_destinations(routes_settings, security_type) do
|
|
{:ok, turnur_chains} = WandererApp.Server.TurnurDataFetcher.get_chain_pairs(routes_settings)
|
|
|
|
system_ids =
|
|
turnur_chains
|
|
|> Enum.map(fn %{first: first, second: second} ->
|
|
pick_turnur_destination(first, second)
|
|
end)
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.uniq()
|
|
|
|
filter_by_security(system_ids, security_type)
|
|
end
|
|
|
|
defp filter_by_security(system_ids, security_type) do
|
|
case normalize_security_type(security_type) do
|
|
"high" ->
|
|
Enum.filter(system_ids, fn system_id ->
|
|
case system_security(system_id) do
|
|
{:ok, security} -> security >= 0.5
|
|
_ -> false
|
|
end
|
|
end)
|
|
|
|
"low" ->
|
|
Enum.filter(system_ids, fn system_id ->
|
|
case system_security(system_id) do
|
|
{:ok, security} -> security > 0.0 and security < 0.5
|
|
_ -> false
|
|
end
|
|
end)
|
|
|
|
_ ->
|
|
system_ids
|
|
end
|
|
end
|
|
|
|
defp system_security(system_id) do
|
|
case WandererApp.CachedInfo.get_system_static_info(system_id) do
|
|
{:ok, %{security: security}} -> parse_security(security)
|
|
_ -> {:error, :missing_security}
|
|
end
|
|
end
|
|
|
|
defp pick_thera_destination(first, second) do
|
|
first_is_thera = is_thera_system?(first)
|
|
second_is_thera = is_thera_system?(second)
|
|
|
|
cond do
|
|
first_is_thera and not second_is_thera -> second
|
|
second_is_thera and not first_is_thera -> first
|
|
true -> second
|
|
end
|
|
end
|
|
|
|
defp is_thera_system?(system_id) do
|
|
case WandererApp.CachedInfo.get_system_static_info(system_id) do
|
|
{:ok, %{system_class: 12}} -> true
|
|
_ -> false
|
|
end
|
|
end
|
|
|
|
defp pick_turnur_destination(first, second) do
|
|
first_is_turnur = is_turnur_system?(first)
|
|
second_is_turnur = is_turnur_system?(second)
|
|
|
|
cond do
|
|
first_is_turnur and not second_is_turnur -> second
|
|
second_is_turnur and not first_is_turnur -> first
|
|
true -> second
|
|
end
|
|
end
|
|
|
|
defp is_turnur_system?(system_id) do
|
|
case WandererApp.CachedInfo.get_system_static_info(system_id) do
|
|
{:ok, %{solar_system_name: name}} when is_binary(name) ->
|
|
String.downcase(name) == "turnur"
|
|
|
|
_ ->
|
|
false
|
|
end
|
|
end
|
|
|
|
defp parse_security(security) when is_float(security), do: {:ok, security}
|
|
defp parse_security(security) when is_integer(security), do: {:ok, security * 1.0}
|
|
|
|
defp parse_security(security) when is_binary(security) do
|
|
case Float.parse(security) do
|
|
{value, _} -> {:ok, value}
|
|
_ -> {:error, :invalid_security}
|
|
end
|
|
end
|
|
|
|
defp parse_security(_), do: {:error, :invalid_security}
|
|
|
|
defp normalize_security_type("high"), do: "high"
|
|
defp normalize_security_type(:high), do: "high"
|
|
defp normalize_security_type("hight"), do: "high"
|
|
defp normalize_security_type(:hight), do: "high"
|
|
defp normalize_security_type("low"), do: "low"
|
|
defp normalize_security_type(:low), do: "low"
|
|
defp normalize_security_type(_), do: "both"
|
|
|
|
def stations_for(type) do
|
|
case normalize_type(type) do
|
|
:thera ->
|
|
%{}
|
|
|
|
:turnur ->
|
|
%{}
|
|
|
|
_ ->
|
|
case load_loot_data(type) do
|
|
{:ok, %{"system_stations" => system_stations}} when is_map(system_stations) ->
|
|
system_stations
|
|
|
|
{:ok, _} ->
|
|
%{}
|
|
|
|
{:error, reason} ->
|
|
Logger.error("[RouteBuilderClient] Failed to load loot stations: #{inspect(reason)}")
|
|
%{}
|
|
end
|
|
end
|
|
end
|
|
|
|
defp pick_by_band(high, _low, "high"), do: high
|
|
defp pick_by_band(high, _low, :high), do: high
|
|
defp pick_by_band(high, _low, "hight"), do: high
|
|
defp pick_by_band(high, _low, :hight), do: high
|
|
defp pick_by_band(_high, low, "low"), do: low
|
|
defp pick_by_band(_high, low, :low), do: low
|
|
defp pick_by_band(high, low, _), do: high ++ low
|
|
|
|
defp load_loot_data("blueLoot"), do: load_loot_file("blueloot.json")
|
|
defp load_loot_data(:blueLoot), do: load_loot_file("blueloot.json")
|
|
defp load_loot_data("redLoot"), do: load_loot_file("redloot.json")
|
|
defp load_loot_data(:redLoot), do: load_loot_file("redloot.json")
|
|
defp load_loot_data("so_cleaning"), do: load_loot_file("ss_cleaning.json")
|
|
defp load_loot_data(:so_cleaning), do: load_loot_file("ss_cleaning.json")
|
|
defp load_loot_data("trade_hubs"), do: load_loot_file("trade_hubs.json")
|
|
defp load_loot_data(:trade_hubs), do: load_loot_file("trade_hubs.json")
|
|
defp load_loot_data(_), do: load_loot_file("blueloot.json")
|
|
|
|
defp normalize_type("thera"), do: :thera
|
|
defp normalize_type(:thera), do: :thera
|
|
defp normalize_type("turnur"), do: :turnur
|
|
defp normalize_type(:turnur), do: :turnur
|
|
defp normalize_type("so_cleaning"), do: :so_cleaning
|
|
defp normalize_type(:so_cleaning), do: :so_cleaning
|
|
defp normalize_type("trade_hubs"), do: :trade_hubs
|
|
defp normalize_type(:trade_hubs), do: :trade_hubs
|
|
defp normalize_type(type), do: type
|
|
|
|
defp load_loot_file(filename) do
|
|
key = {__MODULE__, :loot_data, filename}
|
|
|
|
case :persistent_term.get(key, :missing) do
|
|
:missing ->
|
|
path = Path.join([:code.priv_dir(:wanderer_app), @loot_dir, filename])
|
|
|
|
with {:ok, body} <- File.read(path),
|
|
{:ok, json} <- Jason.decode(body) do
|
|
:persistent_term.put(key, json)
|
|
{:ok, json}
|
|
else
|
|
error -> error
|
|
end
|
|
|
|
cached ->
|
|
{:ok, cached}
|
|
end
|
|
end
|
|
end
|