Compare commits

..

20 Commits

Author SHA1 Message Date
CI
802e81b1cd chore: release version v1.65.7 2025-05-26 14:05:57 +00:00
Dmitry Popov
41f0834c51 chore: release version v1.65.6 2025-05-26 16:05:12 +02:00
Dmitry Popov
880de0b047 chore: release version v1.65.6 2025-05-26 15:57:34 +02:00
Dmitry Popov
bbe7fda4e0 fix(Core): Fixed map character tracking issues 2025-05-26 15:56:46 +02:00
CI
92a9274dce chore: release version v1.65.6 2025-05-26 10:19:27 +00:00
Dmitry Popov
8765d83083 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-05-26 12:09:13 +02:00
Dmitry Popov
a298152bc8 fix(Core): Fixed map character tracking issues 2025-05-26 12:09:09 +02:00
CI
2b7abe5774 chore: release version v1.65.5
Some checks failed
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
2025-05-26 00:11:32 +00:00
Dmitry Popov
3e9241892e fix(Core): Fixed map character tracking issues 2025-05-26 01:41:21 +02:00
Dmitry Popov
6ea79a7960 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-05-25 09:41:39 +02:00
Dmitry Popov
2af562e313 fix(Signature): Update restored signature character 2025-05-25 09:41:33 +02:00
CI
40672f6a47 chore: release version v1.65.4 2025-05-24 17:30:03 +00:00
Dmitry Popov
6d66ae3f50 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-05-24 19:18:57 +02:00
Dmitry Popov
94c89e0325 fix(Signature): Force signature update even if there are no any changes 2025-05-24 19:18:50 +02:00
CI
3670ef40a3 chore: release version v1.65.3 2025-05-23 18:29:03 +00:00
Dmitry Popov
16d464fba5 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-05-23 20:06:20 +02:00
Dmitry Popov
0b7e0b9cd0 fix(Signature): Fixed signature clenup 2025-05-23 20:06:17 +02:00
CI
dd5fd114d2 chore: release version v1.65.2 2025-05-23 15:33:00 +00:00
Dmitry Popov
6e53879344 Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-05-23 17:24:33 +02:00
Dmitry Popov
af2bfd4d59 fix(Signature): Fixed signature updates 2025-05-23 17:24:30 +02:00
24 changed files with 867 additions and 163 deletions

View File

@@ -18,49 +18,8 @@ permissions:
contents: write
jobs:
deploy-test:
name: 🚀 Deploy to test env (fly.io)
runs-on: ubuntu-latest
if: ${{ github.base_ref == 'main' || (github.ref == 'refs/heads/main' && github.event_name == 'push') }}
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
- uses: superfly/flyctl-actions/setup-flyctl@master
- name: 👀 Read app name
uses: SebRollen/toml-action@v1.0.0
id: app_name
with:
file: "fly.toml"
field: "app"
- name: 🚀 Deploy Test
run: flyctl deploy --remote-only --wait-timeout=300 --ha=false
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
manual-approval:
name: Manual Approval
runs-on: ubuntu-latest
needs: deploy-test
if: success()
permissions:
issues: write
steps:
- name: Await Manual Approval
uses: trstringer/manual-approval@v1
with:
secret: ${{ github.TOKEN }}
approvers: DmitryPopov
minimum-approvals: 1
issue-title: "Manual Approval Required for Release"
issue-body: "Please approve or deny the deployment."
build:
name: 🛠 Build
needs: manual-approval
runs-on: ubuntu-22.04
if: ${{ (github.ref == 'refs/heads/main') && github.event_name == 'push' }}
permissions:
@@ -157,7 +116,6 @@ jobs:
matrix:
platform:
- linux/amd64
- linux/arm64
steps:
- name: Prepare
run: |

View File

@@ -2,6 +2,62 @@
<!-- changelog -->
## [v1.65.7](https://github.com/wanderer-industries/wanderer/compare/v1.65.6...v1.65.7) (2025-05-26)
### Bug Fixes:
* Core: Fixed map character tracking issues
## [v1.65.6](https://github.com/wanderer-industries/wanderer/compare/v1.65.5...v1.65.6) (2025-05-26)
### Bug Fixes:
* Core: Fixed map character tracking issues
## [v1.65.5](https://github.com/wanderer-industries/wanderer/compare/v1.65.4...v1.65.5) (2025-05-26)
### Bug Fixes:
* Core: Fixed map character tracking issues
* Signature: Update restored signature character
## [v1.65.4](https://github.com/wanderer-industries/wanderer/compare/v1.65.3...v1.65.4) (2025-05-24)
### Bug Fixes:
* Signature: Force signature update even if there are no any changes
## [v1.65.3](https://github.com/wanderer-industries/wanderer/compare/v1.65.2...v1.65.3) (2025-05-23)
### Bug Fixes:
* Signature: Fixed signature clenup
## [v1.65.2](https://github.com/wanderer-industries/wanderer/compare/v1.65.1...v1.65.2) (2025-05-23)
### Bug Fixes:
* Signature: Fixed signature updates
## [v1.65.1](https://github.com/wanderer-industries/wanderer/compare/v1.65.0...v1.65.1) (2025-05-22)

View File

@@ -1,14 +1,15 @@
import { UNKNOWN_SIGNATURE_NAME } from '@/hooks/Mapper/helpers';
import { SystemSignature } from '@/hooks/Mapper/types';
import { SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
export const getState = (_: string[], newSig: SystemSignature) => {
let state = -1;
if (!newSig.group) {
if (!newSig.group || newSig.group === SignatureGroup.CosmicSignature) {
state = 0;
} else if (!newSig.name || newSig.name === '' || newSig.name === UNKNOWN_SIGNATURE_NAME) {
state = 1;
} else if (newSig.name !== '') {
state = 2;
}
return state;
};

View File

@@ -70,7 +70,7 @@ export const useSystemSignaturesData = ({
? signaturesRef.current.filter(sig => !sig.pendingDeletion)
: signaturesRef.current.filter(sig => !sig.pendingDeletion || !sig.pendingAddition);
const { added, updated, removed } = getActualSigs(currentNonPending, incomingSignatures, !lazyDeleteValue, true);
const { added, updated, removed } = getActualSigs(currentNonPending, incomingSignatures, !lazyDeleteValue, false);
if (removed.length > 0) {
await processRemovedSignatures(removed, added, updated);

View File

@@ -3,17 +3,19 @@ defmodule WandererApp.Api.MapCharacterSettings do
use Ash.Resource,
domain: WandererApp.Api,
data_layer: AshPostgres.DataLayer
data_layer: AshPostgres.DataLayer,
extensions: [AshCloak]
@derive {Jason.Encoder, only: [
:id,
:map_id,
:character_id,
:tracked,
:followed,
:inserted_at,
:updated_at
]}
@derive {Jason.Encoder,
only: [
:id,
:map_id,
:character_id,
:tracked,
:followed,
:inserted_at,
:updated_at
]}
postgres do
repo(WandererApp.Repo)
@@ -23,8 +25,10 @@ defmodule WandererApp.Api.MapCharacterSettings do
code_interface do
define(:create, action: :create)
define(:destroy, action: :destroy)
define(:update, action: :update)
define(:read_by_map, action: :read_by_map)
define(:read_by_map_and_character, action: :read_by_map_and_character)
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)
@@ -44,7 +48,31 @@ defmodule WandererApp.Api.MapCharacterSettings do
:tracked
]
defaults [:create, :read, :update, :destroy]
defaults [:read, :destroy]
create :create do
primary? true
upsert? true
upsert_identity :uniq_map_character
upsert_fields [
:map_id,
:character_id
]
accept [
:map_id,
:character_id,
:tracked,
:followed
]
argument :map_id, :uuid, allow_nil?: false
argument :character_id, :uuid, allow_nil?: false
change manage_relationship(:map_id, :map, on_lookup: :relate, on_no_match: nil)
change manage_relationship(:character_id, :character, on_lookup: :relate, on_no_match: nil)
end
read :by_map_filtered do
argument(:map_id, :string, allow_nil?: false)
@@ -67,6 +95,15 @@ defmodule WandererApp.Api.MapCharacterSettings do
filter(expr(map_id == ^arg(:map_id)))
end
read :read_by_map_and_character do
get? true
argument(:map_id, :string, allow_nil?: false)
argument(:character_id, :uuid, allow_nil?: false)
filter(expr(map_id == ^arg(:map_id) and character_id == ^arg(:character_id)))
end
read :tracked_by_map_all do
argument(:map_id, :string, allow_nil?: false)
filter(expr(map_id == ^arg(:map_id) and tracked == true))
@@ -77,6 +114,20 @@ defmodule WandererApp.Api.MapCharacterSettings do
filter(expr(character_id == ^arg(:character_id) and tracked == true))
end
update :update do
primary? true
require_atomic? false
accept([
:ship,
:ship_name,
:ship_item_id,
:solar_system_id,
:structure_id,
:station_id
])
end
update :track do
accept [:map_id, :character_id]
argument :map_id, :string, allow_nil?: false
@@ -134,6 +185,28 @@ defmodule WandererApp.Api.MapCharacterSettings do
end
end
cloak do
vault(WandererApp.Vault)
attributes([
:ship,
:ship_name,
:ship_item_id,
:solar_system_id,
:structure_id,
:station_id
])
decrypt_by_default([
:ship,
:ship_name,
:ship_item_id,
:solar_system_id,
:structure_id,
:station_id
])
end
attributes do
uuid_primary_key :id
@@ -147,6 +220,13 @@ defmodule WandererApp.Api.MapCharacterSettings do
allow_nil? true
end
attribute :solar_system_id, :integer
attribute :structure_id, :integer
attribute :station_id, :integer
attribute :ship, :integer
attribute :ship_name, :string
attribute :ship_item_id, :integer
create_timestamp(:inserted_at)
update_timestamp(:updated_at)
end

View File

@@ -25,9 +25,18 @@ defmodule WandererApp.Api.MapSystemSignature do
define(:by_system_id, action: :by_system_id, args: [:system_id])
define(:by_system_id_all, action: :by_system_id_all, args: [:system_id])
define(:by_system_id_and_eve_ids, action: :by_system_id_and_eve_ids, args: [:system_id, :eve_ids])
define(:by_system_id_and_eve_ids,
action: :by_system_id_and_eve_ids,
args: [:system_id, :eve_ids]
)
define(:by_linked_system_id, action: :by_linked_system_id, args: [:linked_system_id])
define(:by_deleted_and_updated_before!, action: :by_deleted_and_updated_before, args: [:deleted, :updated_before])
define(:by_deleted_and_updated_before!,
action: :by_deleted_and_updated_before,
args: [:deleted, :updated_before]
)
end
actions do
@@ -88,7 +97,8 @@ defmodule WandererApp.Api.MapSystemSignature do
:group,
:type,
:custom_info,
:deleted
:deleted,
:update_forced_at
]
primary? true
@@ -177,6 +187,10 @@ defmodule WandererApp.Api.MapSystemSignature do
default false
end
attribute :update_forced_at, :utc_datetime do
allow_nil? true
end
create_timestamp(:inserted_at)
update_timestamp(:updated_at)
end
@@ -192,21 +206,20 @@ defmodule WandererApp.Api.MapSystemSignature do
end
@derive {Jason.Encoder,
only: [
:id,
:system_id,
:eve_id,
:character_eve_id,
:name,
:description,
:type,
:linked_system_id,
:kind,
:group,
:custom_info,
:deleted,
:inserted_at,
:updated_at
]
}
only: [
:id,
:system_id,
:eve_id,
:character_eve_id,
:name,
:description,
:type,
:linked_system_id,
:kind,
:group,
:custom_info,
:deleted,
:inserted_at,
:updated_at
]}
end

View File

@@ -7,6 +7,15 @@ defmodule WandererApp.Character do
@read_character_wallet_scope "esi-wallet.read_character_wallet.v1"
@read_corp_wallet_scope "esi-wallet.read_corporation_wallets.v1"
@default_character_tracking_data %{
solar_system_id: nil,
structure_id: nil,
station_id: nil,
ship: nil,
ship_name: nil,
ship_item_id: nil
}
@decorate cacheable(
cache: WandererApp.Cache,
key: "characters-#{character_eve_id}"
@@ -45,6 +54,32 @@ defmodule WandererApp.Character do
end
end
def get_map_character(map_id, character_id) do
case get_character(character_id) do
{:ok, character} ->
{:ok,
character
|> maybe_merge_map_character_settings(
map_id,
WandererApp.Character.TrackerManager.Impl.character_is_present(map_id, character_id)
)}
_ ->
{:ok, nil}
end
end
def get_map_character!(map_id, character_id) do
case get_map_character(map_id, character_id) do
{:ok, character} ->
character
_ ->
Logger.error("Failed to get map character #{map_id} #{character_id}")
nil
end
end
def get_character_eve_ids!(character_ids),
do:
character_ids
@@ -146,7 +181,7 @@ defmodule WandererApp.Character do
params: opts[:params]
) do
{:ok, result} ->
{:ok, result |> _prepare_search_results()}
{:ok, result |> prepare_search_results()}
{:error, error} ->
Logger.warning("#{__MODULE__} failed search: #{inspect(error)}")
@@ -208,7 +243,28 @@ defmodule WandererApp.Character do
end
end
defp _prepare_search_results(result) do
defp maybe_merge_map_character_settings(character, map_id, true), do: character
defp maybe_merge_map_character_settings(
%{id: character_id} = character,
map_id,
_character_is_present
) do
WandererApp.MapCharacterSettingsRepo.get(map_id, character_id)
|> case do
{:ok, settings} when not is_nil(settings) ->
character
|> Map.put(:online, false)
|> Map.merge(settings)
_ ->
character
|> Map.put(:online, false)
|> Map.merge(@default_character_tracking_data)
end
end
defp prepare_search_results(result) do
{:ok, characters} =
_load_eve_info(Map.get(result, "character"), :get_character_info, &_map_character_info/1)

View File

@@ -13,7 +13,7 @@ defmodule WandererApp.Character.TrackerManager.Impl do
}
@garbage_collection_interval :timer.minutes(15)
@untrack_characters_interval :timer.minutes(5)
@untrack_characters_interval :timer.minutes(1)
@inactive_character_timeout :timer.minutes(5)
@logger Application.compile_env(:wanderer_app, :logger)
@@ -220,6 +220,18 @@ defmodule WandererApp.Character.TrackerManager.Impl do
track: false
})
{:ok, character} = WandererApp.Character.get_character(character_id)
{:ok, _updated} =
WandererApp.MapCharacterSettingsRepo.update(map_id, character_id, %{
ship: character.ship,
ship_name: character.ship_name,
ship_item_id: character.ship_item_id,
solar_system_id: character.solar_system_id,
structure_id: character.structure_id,
station_id: character.station_id
})
WandererApp.Character.update_character_state(character_id, character_state)
end
end,
@@ -246,7 +258,7 @@ defmodule WandererApp.Character.TrackerManager.Impl do
def handle_info(_event, state),
do: state
defp character_is_present(map_id, character_id) do
def character_is_present(map_id, character_id) do
{:ok, presence_character_ids} =
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", [])

View File

@@ -121,7 +121,6 @@ defmodule WandererApp.Character.TrackingUtils do
WandererApp.MapCharacterSettingsRepo.untrack(existing_settings)
:ok = untrack([character], map_id, caller_pid)
:ok = remove_characters([character], map_id)
{:ok, updated_settings}
else
{:ok, existing_settings}
@@ -132,7 +131,6 @@ defmodule WandererApp.Character.TrackingUtils do
if track do
{:ok, updated_settings} = WandererApp.MapCharacterSettingsRepo.track(existing_settings)
:ok = track([character], map_id, true, caller_pid)
:ok = add_characters([character], map_id, true)
{:ok, updated_settings}
else
{:ok, existing_settings}
@@ -149,7 +147,6 @@ defmodule WandererApp.Character.TrackingUtils do
})
:ok = track([character], map_id, true, caller_pid)
:ok = add_characters([character], map_id, true)
{:ok, settings}
else
{:error, "Character settings not found"}
@@ -231,15 +228,15 @@ defmodule WandererApp.Character.TrackingUtils do
with false <- is_nil(caller_pid) do
character_ids = characters |> Enum.map(& &1.id)
characters
|> Enum.each(fn character ->
WandererAppWeb.Presence.update(caller_pid, map_id, character.id, %{
character_ids
|> Enum.each(fn character_id ->
WandererAppWeb.Presence.update(caller_pid, map_id, character_id, %{
tracked: false,
from: DateTime.utc_now()
})
end)
WandererApp.Map.Server.untrack_characters(map_id, character_ids)
# WandererApp.Map.Server.untrack_characters(map_id, character_ids)
:ok
else
@@ -249,19 +246,19 @@ defmodule WandererApp.Character.TrackingUtils do
end
end
def add_characters([], _map_id, _track_character), do: :ok
# def add_characters([], _map_id, _track_character), do: :ok
def add_characters([character | characters], map_id, track_character) do
:ok = WandererApp.Map.Server.add_character(map_id, character, track_character)
add_characters(characters, map_id, track_character)
end
# def add_characters([character | characters], map_id, track_character) do
# :ok = WandererApp.Map.Server.add_character(map_id, character, track_character)
# add_characters(characters, map_id, track_character)
# end
def remove_characters([], _map_id), do: :ok
# def remove_characters([], _map_id), do: :ok
def remove_characters([character | characters], map_id) do
:ok = WandererApp.Map.Server.remove_character(map_id, character.id)
remove_characters(characters, map_id)
end
# def remove_characters([character | characters], map_id) do
# :ok = WandererApp.Map.Server.remove_character(map_id, character.id)
# remove_characters(characters, map_id)
# end
def get_main_character(
nil,

View File

@@ -96,7 +96,7 @@ defmodule WandererApp.Map do
map_id
|> get_map!()
|> Map.get(:characters, [])
|> Enum.map(&WandererApp.Character.get_character!(&1))
|> Enum.map(fn character_id -> WandererApp.Character.get_map_character!(map_id, character_id) end)
def list_systems(map_id),
do: {:ok, map_id |> get_map!() |> Map.get(:systems, Map.new()) |> Map.values()}

View File

@@ -5,25 +5,22 @@ defmodule WandererApp.Map.Server.CharactersImpl do
alias WandererApp.Map.Server.{Impl, ConnectionsImpl, SystemsImpl}
def get_characters(%{map_id: map_id} = _state),
do: {:ok, map_id |> WandererApp.Map.list_characters()}
def add_character(%{map_id: map_id} = state, %{id: character_id} = character, track_character) do
Task.start_link(fn ->
with :ok <- map_id |> WandererApp.Map.add_character(character),
{:ok, _} <-
{:ok, _settings} <-
WandererApp.MapCharacterSettingsRepo.create(%{
character_id: character_id,
map_id: map_id,
tracked: track_character
}),
{:ok, character} <- WandererApp.Character.get_character(character_id) do
{:ok, character} <- WandererApp.Character.get_map_character(map_id, character_id) do
Impl.broadcast!(map_id, :character_added, character)
:telemetry.execute([:wanderer_app, :map, :character, :added], %{count: 1})
:ok
else
_error ->
{:ok, character} = WandererApp.Character.get_character(character_id)
{:ok, character} = WandererApp.Character.get_map_character(map_id, character_id)
Impl.broadcast!(map_id, :character_added, character)
:ok
end
@@ -35,7 +32,7 @@ defmodule WandererApp.Map.Server.CharactersImpl do
def remove_character(map_id, character_id) do
Task.start_link(fn ->
with :ok <- WandererApp.Map.remove_character(map_id, character_id),
{:ok, character} <- WandererApp.Character.get_character(character_id) do
{:ok, character} <- WandererApp.Character.get_map_character(map_id, character_id) do
Impl.broadcast!(map_id, :character_removed, character)
:telemetry.execute([:wanderer_app, :map, :character, :removed], %{count: 1})
@@ -64,7 +61,9 @@ 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", [])
{: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} =
@@ -73,7 +72,11 @@ defmodule WandererApp.Map.Server.CharactersImpl do
[]
)
WandererApp.Cache.insert("map_#{map_id}:invalidate_character_ids", (invalidate_character_ids ++ characters_to_remove) |> Enum.uniq())
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
@@ -84,12 +87,26 @@ defmodule WandererApp.Map.Server.CharactersImpl do
do:
character_ids
|> Enum.each(fn character_id ->
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: false
})
if is_character_map_active?(map_id, character_id) do
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: false
})
Impl.broadcast!(map_id, :untrack_character, character_id)
end
end)
def is_character_map_active?(map_id, character_id) do
case WandererApp.Character.get_character_state(character_id) do
{:ok, %{active_maps: active_maps}} ->
map_id in active_maps
_ ->
false
end
end
def cleanup_characters(map_id, owner_id) do
{:ok, invalidate_character_ids} =
WandererApp.Cache.lookup(
@@ -265,7 +282,7 @@ defmodule WandererApp.Map.Server.CharactersImpl do
end
defp update_character(map_id, character_id) do
{:ok, character} = WandererApp.Character.get_character(character_id)
{:ok, character} = WandererApp.Character.get_map_character(map_id, character_id)
Impl.broadcast!(map_id, :character_updated, character)
end
@@ -315,15 +332,18 @@ defmodule WandererApp.Map.Server.CharactersImpl do
is_nil(structure_id) and is_nil(station_id)
end
defp track_character(map_id, character_id),
do:
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: true,
track_online: true,
track_location: true,
track_ship: true
})
defp track_character(map_id, character_id) do
{:ok, character} = WandererApp.Character.get_character(character_id)
add_character(%{map_id: map_id}, character, true)
WandererApp.Character.TrackerManager.update_track_settings(character_id, %{
map_id: map_id,
track: true,
track_online: true,
track_location: true,
track_ship: true
})
end
defp maybe_update_online(map_id, character_id) do
with {:ok, old_online} <-
@@ -394,8 +414,7 @@ defmodule WandererApp.Map.Server.CharactersImpl do
{:ok, old_structure_id} =
WandererApp.Cache.lookup("map:#{map_id}:character:#{character_id}:structure_id")
{:ok,
%{solar_system_id: solar_system_id, structure_id: structure_id, station_id: station_id}} =
{:ok, %{solar_system_id: solar_system_id, structure_id: structure_id, station_id: station_id}} =
WandererApp.Character.get_character(character_id)
WandererApp.Cache.insert(
@@ -413,14 +432,15 @@ defmodule WandererApp.Map.Server.CharactersImpl do
structure_id
)
if solar_system_id != old_solar_system_id || structure_id != old_structure_id || station_id != old_station_id do
if solar_system_id != old_solar_system_id || structure_id != old_structure_id ||
station_id != old_station_id do
[
{:character_location,
%{
solar_system_id: solar_system_id,
structure_id: structure_id,
station_id: station_id
}, %{solar_system_id: old_solar_system_id}}
%{
solar_system_id: solar_system_id,
structure_id: structure_id,
station_id: station_id
}, %{solar_system_id: old_solar_system_id}}
]
else
[:skip]

View File

@@ -93,7 +93,6 @@ defmodule WandererApp.Map.Server.Impl do
Process.send_after(self(), :cleanup_connections, 5_000)
Process.send_after(self(), :cleanup_systems, 10_000)
Process.send_after(self(), :cleanup_characters, :timer.minutes(5))
Process.send_after(self(), :cleanup_signatures, :timer.minutes(30))
Process.send_after(self(), :backup_state, @backup_state_timeout)
WandererApp.Cache.insert("map_#{map_id}:started", true)
@@ -312,11 +311,6 @@ defmodule WandererApp.Map.Server.Impl do
state
end
def handle_event(:cleanup_signatures, state) do
Process.send_after(self(), :cleanup_signatures, :timer.minutes(30))
state |> SignaturesImpl.cleanup_signatures()
end
def handle_event(msg, state) do
Logger.warning("Unhandled event: #{inspect(msg)}")

View File

@@ -25,7 +25,10 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
)
when not is_nil(char_id) do
with {:ok, system} <-
MapSystem.read_by_map_and_solar_system(%{map_id: map_id, solar_system_id: system_solar_id}),
MapSystem.read_by_map_and_solar_system(%{
map_id: map_id,
solar_system_id: system_solar_id
}),
{:ok, %{eve_id: char_eve_id}} <- Character.get_character(char_id) do
do_update_signatures(
state,
@@ -84,9 +87,11 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
# 3. Additions & restorations
added_eve_ids = Enum.map(added_sigs, & &1.eve_id)
existing_index = MapSystemSignature.by_system_id_all!(system.id)
|> Enum.filter(&(&1.eve_id in added_eve_ids))
|> Map.new(&{&1.eve_id, &1})
existing_index =
MapSystemSignature.by_system_id_all!(system.id)
|> Enum.filter(&(&1.eve_id in added_eve_ids))
|> Map.new(&{&1.eve_id, &1})
added_sigs
|> Enum.each(fn sig ->
@@ -97,7 +102,17 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
%MapSystemSignature{deleted: true} = deleted_sig ->
MapSystemSignature.update!(
deleted_sig,
Map.take(sig, [:name, :description, :kind, :group, :type, :custom_info, :deleted])
Map.take(sig, [
:name,
:description,
:kind,
:group,
:type,
:character_eve_id,
:custom_info,
:deleted,
:update_forced_at
])
)
_ ->
@@ -107,7 +122,12 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
# 4. Activity tracking
if added_ids != [] do
track_activity(:signatures_added, state.map_id, system.solar_system_id, user_id, character_eve_id,
track_activity(
:signatures_added,
state.map_id,
system.solar_system_id,
user_id,
character_eve_id,
added_ids
)
end
@@ -152,8 +172,13 @@ defmodule WandererApp.Map.Server.SignaturesImpl do
defp apply_update_signature(%MapSystemSignature{} = existing, update_params)
when not is_nil(update_params) do
case MapSystemSignature.update(existing, update_params) do
{:ok, _} -> :ok
case MapSystemSignature.update(
existing,
update_params |> Map.put(:update_forced_at, DateTime.utc_now())
) do
{:ok, _updated} ->
:ok
{:error, reason} ->
Logger.error("Failed to update signature #{existing.id}: #{inspect(reason)}")
end

View File

@@ -1,8 +1,37 @@
defmodule WandererApp.MapCharacterSettingsRepo do
use WandererApp, :repository
def create(settings),
do: WandererApp.Api.MapCharacterSettings.create(settings)
def get(map_id, character_id) do
case WandererApp.Api.MapCharacterSettings.read_by_map_and_character(%{
map_id: map_id,
character_id: character_id
}) do
{:ok, settings} when not is_nil(settings) ->
{:ok, settings}
_ ->
WandererApp.Api.MapCharacterSettings.create(%{
character_id: character_id,
map_id: map_id,
tracked: false
})
end
end
def create(settings) do
WandererApp.Api.MapCharacterSettings.create(settings)
end
def update(map_id, character_id, updated_settings) do
case get(map_id, character_id) do
{:ok, settings} when not is_nil(settings) ->
settings
|> WandererApp.Api.MapCharacterSettings.update(updated_settings)
_ ->
{:ok, nil}
end
end
def get_tracked_by_map_filtered(map_id, character_ids),
do:

View File

@@ -91,6 +91,8 @@ defmodule WandererAppWeb.CharactersTrackingLive do
character_setting
|> WandererApp.MapCharacterSettingsRepo.untrack!()
WandererApp.Map.Server.untrack_characters(selected_map.id, [character_setting.character_id])
_ ->
character_setting
|> WandererApp.MapCharacterSettingsRepo.track!()

View File

@@ -32,6 +32,16 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
)
end
def handle_server_event(%{event: :untrack_character, payload: character_id}, %{
assigns: %{
map_id: map_id
}
} = socket) do
:ok = WandererApp.Character.TrackingUtils.untrack([%{id: character_id}], map_id, self())
socket
end
def handle_server_event(
%{event: :characters_updated},
%{
@@ -342,9 +352,6 @@ defmodule WandererAppWeb.MapCharactersEventHandler do
self()
)
:ok =
WandererApp.Character.TrackingUtils.add_characters(map_characters, map_id, track_character)
socket
end

View File

@@ -57,7 +57,6 @@ defmodule WandererAppWeb.MapCoreEventHandler do
case track_character do
false ->
:ok = WandererApp.Character.TrackingUtils.untrack(map_characters, map_id, self())
:ok = WandererApp.Character.TrackingUtils.remove_characters(map_characters, map_id)
_ ->
:ok =
@@ -67,13 +66,6 @@ defmodule WandererAppWeb.MapCoreEventHandler do
true,
self()
)
:ok =
WandererApp.Character.TrackingUtils.add_characters(
map_characters,
map_id,
track_character
)
end
socket

View File

@@ -84,11 +84,7 @@ defmodule WandererAppWeb.MapCharactersLive do
character_setting ->
case character_setting.tracked do
true ->
{:ok, map_character_settings} =
character_setting
|> WandererApp.MapCharacterSettingsRepo.untrack()
WandererApp.Map.Server.remove_character(map_id, map_character_settings.character_id)
WandererApp.Map.Server.untrack_characters(map_id, [character_setting.character_id])
socket |> put_flash(:info, "Character untracked!") |> load_characters()

View File

@@ -23,7 +23,8 @@ defmodule WandererAppWeb.MapEventHandler do
:characters_updated,
:present_characters_updated,
:refresh_user_characters,
:show_tracking
:show_tracking,
:untrack_character
]
@map_characters_ui_events [

View File

@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
@source_url "https://github.com/wanderer-industries/wanderer"
@version "1.65.1"
@version "1.65.7"
def project do
[

View File

@@ -0,0 +1,21 @@
defmodule WandererApp.Repo.Migrations.AddSigUpdateForcedAt do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
alter table(:map_system_signatures_v1) do
add :update_forced_at, :utc_datetime
end
end
def down do
alter table(:map_system_signatures_v1) do
remove :update_forced_at
end
end
end

View File

@@ -0,0 +1,31 @@
defmodule WandererApp.Repo.Migrations.AddMapCharacterTrackingInfo do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
alter table(:map_character_settings_v1) do
add :encrypted_ship, :binary
add :encrypted_ship_name, :binary
add :encrypted_ship_item_id, :binary
add :encrypted_solar_system_id, :binary
add :encrypted_structure_id, :binary
add :encrypted_station_id, :binary
end
end
def down do
alter table(:map_character_settings_v1) do
remove :encrypted_station_id
remove :encrypted_structure_id
remove :encrypted_solar_system_id
remove :encrypted_ship_item_id
remove :encrypted_ship_name
remove :encrypted_ship
end
end
end

View File

@@ -0,0 +1,206 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "false",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "tracked",
"type": "boolean"
},
{
"allow_nil?": true,
"default": "false",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "followed",
"type": "boolean"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_character_settings_v1_map_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "maps_v1"
},
"size": null,
"source": "map_id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_character_settings_v1_character_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "character_v1"
},
"size": null,
"source": "character_id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_ship",
"type": "binary"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_ship_name",
"type": "binary"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_ship_item_id",
"type": "binary"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_solar_system_id",
"type": "binary"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_structure_id",
"type": "binary"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "encrypted_station_id",
"type": "binary"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "3F585D1C545A5264AEFA05502C0F625F9B27B15CA36699DCF37E4F834E6339AE",
"identities": [
{
"all_tenants?": false,
"base_filter": null,
"index_name": "map_character_settings_v1_uniq_map_character_index",
"keys": [
{
"type": "atom",
"value": "map_id"
},
{
"type": "atom",
"value": "character_id"
}
],
"name": "uniq_map_character",
"nils_distinct?": true,
"where": null
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_character_settings_v1"
}

View File

@@ -0,0 +1,207 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "eve_id",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "character_eve_id",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "name",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "description",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "type",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "linked_system_id",
"type": "bigint"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "kind",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "group",
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "custom_info",
"type": "text"
},
{
"allow_nil?": false,
"default": "false",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "deleted",
"type": "boolean"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "update_forced_at",
"type": "utc_datetime"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "map_system_signatures_v1_system_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "map_system_v1"
},
"size": null,
"source": "system_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "915C0896211ECCB6C38871664117E7D470C794825536E7F0887DC5B92681F17B",
"identities": [
{
"all_tenants?": false,
"base_filter": null,
"index_name": "map_system_signatures_v1_uniq_system_eve_id_index",
"keys": [
{
"type": "atom",
"value": "system_id"
},
{
"type": "atom",
"value": "eve_id"
}
],
"name": "uniq_system_eve_id",
"nils_distinct?": true,
"where": null
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.WandererApp.Repo",
"schema": null,
"table": "map_system_signatures_v1"
}