Db: Fix various things around local persistence/net interactions
This commit is contained in:
parent
802e0c4cde
commit
d5dc55a0c4
@ -12,6 +12,7 @@ using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Logging;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Floors;
|
||||
@ -25,6 +26,7 @@ namespace Pal.Client.DependencyInjection
|
||||
internal sealed class FrameworkService : IDisposable
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<FrameworkService> _logger;
|
||||
private readonly Framework _framework;
|
||||
private readonly ConfigurationManager _configurationManager;
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
@ -42,6 +44,7 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
public FrameworkService(
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<FrameworkService> logger,
|
||||
Framework framework,
|
||||
ConfigurationManager configurationManager,
|
||||
IPalacePalConfiguration configuration,
|
||||
@ -54,6 +57,7 @@ namespace Pal.Client.DependencyInjection
|
||||
RemoteApi remoteApi)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_framework = framework;
|
||||
_configurationManager = configurationManager;
|
||||
_configuration = configuration;
|
||||
@ -92,8 +96,11 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
if (_territoryState.LastTerritory != _clientState.TerritoryType)
|
||||
{
|
||||
MemoryTerritory? oldTerritory = _floorService.GetTerritoryIfReady(_territoryState.LastTerritory);
|
||||
if (oldTerritory != null)
|
||||
oldTerritory.SyncState = ESyncState.NotAttempted;
|
||||
|
||||
_territoryState.LastTerritory = _clientState.TerritoryType;
|
||||
_territoryState.TerritorySyncState = ESyncState.NotAttempted;
|
||||
NextUpdateObjects.Clear();
|
||||
|
||||
_floorService.ChangeTerritory(_territoryState.LastTerritory);
|
||||
@ -106,11 +113,12 @@ namespace Pal.Client.DependencyInjection
|
||||
if (!_territoryState.IsInDeepDungeon() || !_floorService.IsReady(_territoryState.LastTerritory))
|
||||
return;
|
||||
|
||||
if (_configuration.Mode == EMode.Online &&
|
||||
_territoryState.TerritorySyncState == ESyncState.NotAttempted)
|
||||
ETerritoryType territoryType = (ETerritoryType)_territoryState.LastTerritory;
|
||||
MemoryTerritory memoryTerritory = _floorService.GetTerritoryIfReady(territoryType)!;
|
||||
if (_configuration.Mode == EMode.Online && memoryTerritory.SyncState == ESyncState.NotAttempted)
|
||||
{
|
||||
_territoryState.TerritorySyncState = ESyncState.Started;
|
||||
Task.Run(async () => await DownloadMarkersForTerritory(_territoryState.LastTerritory));
|
||||
memoryTerritory.SyncState = ESyncState.Started;
|
||||
Task.Run(async () => await DownloadLocationsForTerritory(_territoryState.LastTerritory));
|
||||
}
|
||||
|
||||
while (LateEventQueue.TryDequeue(out IQueueOnFrameworkThread? queued))
|
||||
@ -120,7 +128,6 @@ namespace Pal.Client.DependencyInjection
|
||||
IReadOnlyList<EphemeralLocation> visibleEphemeralMarkers) =
|
||||
GetRelevantGameObjects();
|
||||
|
||||
ETerritoryType territoryType = (ETerritoryType)_territoryState.LastTerritory;
|
||||
HandlePersistentLocations(territoryType, visiblePersistentMarkers, recreateLayout);
|
||||
|
||||
if (_floorService.MergeEphemeralLocations(visibleEphemeralMarkers, recreateLayout))
|
||||
@ -188,7 +195,7 @@ namespace Pal.Client.DependencyInjection
|
||||
private void UploadLocations()
|
||||
{
|
||||
MemoryTerritory? memoryTerritory = _floorService.GetTerritoryIfReady(_territoryState.LastTerritory);
|
||||
if (memoryTerritory == null)
|
||||
if (memoryTerritory == null || memoryTerritory.SyncState != ESyncState.Complete)
|
||||
return;
|
||||
|
||||
List<PersistentLocation> locationsToUpload = memoryTerritory.Locations
|
||||
@ -296,10 +303,11 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
#region Up-/Download
|
||||
|
||||
private async Task DownloadMarkersForTerritory(ushort territoryId)
|
||||
private async Task DownloadLocationsForTerritory(ushort territoryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Downloading territory {Territory} from server", (ETerritoryType)territoryId);
|
||||
var (success, downloadedMarkers) = await _remoteApi.DownloadRemoteMarkers(territoryId);
|
||||
LateEventQueue.Enqueue(new QueuedSyncResponse
|
||||
{
|
||||
@ -319,6 +327,8 @@ namespace Pal.Client.DependencyInjection
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Uploading {Count} locations for territory {Territory} to server",
|
||||
locationsToUpload.Count, (ETerritoryType)territoryId);
|
||||
var (success, uploadedLocations) = await _remoteApi.UploadLocations(territoryId, locationsToUpload);
|
||||
LateEventQueue.Enqueue(new QueuedSyncResponse
|
||||
{
|
||||
@ -339,6 +349,8 @@ namespace Pal.Client.DependencyInjection
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Syncing {Count} seen locations for territory {Territory} to server",
|
||||
locationsToUpdate.Count, (ETerritoryType)territoryId);
|
||||
var success = await _remoteApi.MarkAsSeen(territoryId, locationsToUpdate);
|
||||
LateEventQueue.Enqueue(new QueuedSyncResponse
|
||||
{
|
||||
|
@ -17,7 +17,6 @@ namespace Pal.Client.DependencyInjection
|
||||
}
|
||||
|
||||
public ushort LastTerritory { get; set; }
|
||||
public ESyncState TerritorySyncState { get; set; }
|
||||
public PomanderState PomanderOfSight { get; set; } = PomanderState.Inactive;
|
||||
public PomanderState PomanderOfIntuition { get; set; } = PomanderState.Inactive;
|
||||
|
||||
|
@ -20,5 +20,10 @@ namespace Pal.Client.Floors
|
||||
{
|
||||
return !Equals(a, b);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"EphemeralLocation(Position={Position}, Type={Type})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ namespace Pal.Client.Floors
|
||||
}
|
||||
|
||||
if (markAsSeen.Count > 0)
|
||||
new MarkAsSeen(_serviceScopeFactory, territory, markAsSeen).Start();
|
||||
new MarkLocalSeen(_serviceScopeFactory, territory, markAsSeen).Start();
|
||||
|
||||
if (newLocations.Count > 0)
|
||||
new SaveNewLocations(_serviceScopeFactory, territory, newLocations).Start();
|
||||
|
@ -22,8 +22,8 @@ namespace Pal.Client.Floors
|
||||
{
|
||||
Unknown,
|
||||
|
||||
Hoard,
|
||||
Trap,
|
||||
Hoard,
|
||||
|
||||
SilverCoffer,
|
||||
}
|
||||
@ -52,5 +52,15 @@ namespace Pal.Client.Floors
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(objectType), objectType, null)
|
||||
};
|
||||
}
|
||||
|
||||
public static ObjectType ToObjectType(this MemoryLocation.EType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
MemoryLocation.EType.Trap => ObjectType.Trap,
|
||||
MemoryLocation.EType.Hoard => ObjectType.Hoard,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.Scheduled;
|
||||
using Pal.Common;
|
||||
|
||||
namespace Pal.Client.Floors
|
||||
@ -18,7 +19,8 @@ namespace Pal.Client.Floors
|
||||
|
||||
public ETerritoryType TerritoryType { get; }
|
||||
public bool IsReady { get; set; }
|
||||
public bool IsLoading { get; set; }
|
||||
public bool IsLoading { get; set; } // probably merge this with IsReady as enum
|
||||
public ESyncState SyncState { get; set; } = ESyncState.NotAttempted;
|
||||
|
||||
public ConcurrentBag<PersistentLocation> Locations { get; } = new();
|
||||
public object LockObj { get; } = new();
|
||||
|
@ -44,5 +44,10 @@ namespace Pal.Client.Floors
|
||||
{
|
||||
return !Equals(a, b);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"PersistentLocation(Position={Position}, Type={Type})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Database;
|
||||
|
||||
namespace Pal.Client.Floors.Tasks
|
||||
{
|
||||
internal abstract class DbTask
|
||||
internal abstract class DbTask<T>
|
||||
where T : DbTask<T>
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
@ -18,12 +21,13 @@ namespace Pal.Client.Floors.Tasks
|
||||
Task.Run(() =>
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
ILogger<T> logger = scope.ServiceProvider.GetRequiredService<ILogger<T>>();
|
||||
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
|
||||
|
||||
Run(dbContext);
|
||||
Run(dbContext, logger);
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void Run(PalClientContext dbContext);
|
||||
protected abstract void Run(PalClientContext dbContext, ILogger<T> logger);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Database;
|
||||
|
||||
namespace Pal.Client.Floors.Tasks
|
||||
{
|
||||
internal sealed class LoadTerritory : DbTask
|
||||
internal sealed class LoadTerritory : DbTask<LoadTerritory>
|
||||
{
|
||||
private readonly MemoryTerritory _territory;
|
||||
|
||||
@ -18,19 +19,27 @@ namespace Pal.Client.Floors.Tasks
|
||||
_territory = territory;
|
||||
}
|
||||
|
||||
protected override void Run(PalClientContext dbContext)
|
||||
protected override void Run(PalClientContext dbContext, ILogger<LoadTerritory> logger)
|
||||
{
|
||||
lock (_territory.LockObj)
|
||||
{
|
||||
if (_territory.IsReady)
|
||||
{
|
||||
logger.LogInformation("Territory {Territory} is already loaded", _territory.TerritoryType);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInformation("Loading territory {Territory}", _territory.TerritoryType);
|
||||
List<ClientLocation> locations = dbContext.Locations
|
||||
.Where(o => o.TerritoryType == (ushort)_territory.TerritoryType)
|
||||
.Include(o => o.ImportedBy)
|
||||
.Include(o => o.RemoteEncounters)
|
||||
.AsSplitQuery()
|
||||
.ToList();
|
||||
_territory.Initialize(locations.Select(ToMemoryLocation));
|
||||
|
||||
logger.LogInformation("Loaded {Count} locations for territory {Territory}", locations.Count,
|
||||
_territory.TerritoryType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,16 +2,17 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Database;
|
||||
|
||||
namespace Pal.Client.Floors.Tasks
|
||||
{
|
||||
internal sealed class MarkAsSeen : DbTask
|
||||
internal sealed class MarkLocalSeen : DbTask<MarkLocalSeen>
|
||||
{
|
||||
private readonly MemoryTerritory _territory;
|
||||
private readonly IReadOnlyList<PersistentLocation> _locations;
|
||||
|
||||
public MarkAsSeen(IServiceScopeFactory serviceScopeFactory, MemoryTerritory territory,
|
||||
public MarkLocalSeen(IServiceScopeFactory serviceScopeFactory, MemoryTerritory territory,
|
||||
IReadOnlyList<PersistentLocation> locations)
|
||||
: base(serviceScopeFactory)
|
||||
{
|
||||
@ -19,10 +20,12 @@ namespace Pal.Client.Floors.Tasks
|
||||
_locations = locations;
|
||||
}
|
||||
|
||||
protected override void Run(PalClientContext dbContext)
|
||||
protected override void Run(PalClientContext dbContext, ILogger<MarkLocalSeen> logger)
|
||||
{
|
||||
lock (_territory.LockObj)
|
||||
{
|
||||
logger.LogInformation("Marking {Count} locations as seen locally in territory {Territory}", _locations.Count,
|
||||
_territory.TerritoryType);
|
||||
dbContext.Locations
|
||||
.Where(loc => _locations.Any(l => l.LocalId == loc.LocalId))
|
||||
.ExecuteUpdate(loc => loc.SetProperty(l => l.Seen, true));
|
@ -1,11 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Database;
|
||||
|
||||
namespace Pal.Client.Floors.Tasks
|
||||
{
|
||||
internal sealed class MarkRemoteSeen : DbTask
|
||||
internal sealed class MarkRemoteSeen : DbTask<MarkRemoteSeen>
|
||||
{
|
||||
private readonly MemoryTerritory _territory;
|
||||
private readonly IReadOnlyList<PersistentLocation> _locations;
|
||||
@ -22,16 +24,26 @@ namespace Pal.Client.Floors.Tasks
|
||||
_accountId = accountId;
|
||||
}
|
||||
|
||||
protected override void Run(PalClientContext dbContext)
|
||||
protected override void Run(PalClientContext dbContext, ILogger<MarkRemoteSeen> logger)
|
||||
{
|
||||
lock (_territory.LockObj)
|
||||
{
|
||||
List<ClientLocation> locationsToUpdate = dbContext.Locations
|
||||
.Where(loc => _locations.Any(l =>
|
||||
l.LocalId == loc.LocalId && loc.RemoteEncounters.All(r => r.AccountId != _accountId)))
|
||||
.ToList();
|
||||
logger.LogInformation("Marking {Count} locations as seen remotely on {Account} in territory {Territory}",
|
||||
_locations.Count, _accountId, _territory.TerritoryType);
|
||||
|
||||
List<int> locationIds = _locations.Select(x => x.LocalId).Where(x => x != null).Cast<int>().ToList();
|
||||
List<ClientLocation> locationsToUpdate =
|
||||
dbContext.Locations
|
||||
.Include(x => x.RemoteEncounters)
|
||||
.Where(x => locationIds.Contains(x.LocalId))
|
||||
.ToList()
|
||||
.Where(x => x.RemoteEncounters.All(encounter => encounter.AccountId != _accountId))
|
||||
.ToList();
|
||||
foreach (var clientLocation in locationsToUpdate)
|
||||
{
|
||||
clientLocation.RemoteEncounters.Add(new RemoteEncounter(clientLocation, _accountId));
|
||||
}
|
||||
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Database;
|
||||
using Pal.Common;
|
||||
|
||||
namespace Pal.Client.Floors.Tasks
|
||||
{
|
||||
internal sealed class SaveNewLocations : DbTask
|
||||
internal sealed class SaveNewLocations : DbTask<SaveNewLocations>
|
||||
{
|
||||
private readonly MemoryTerritory _territory;
|
||||
private readonly List<PersistentLocation> _newLocations;
|
||||
@ -20,16 +21,22 @@ namespace Pal.Client.Floors.Tasks
|
||||
_newLocations = newLocations;
|
||||
}
|
||||
|
||||
protected override void Run(PalClientContext dbContext)
|
||||
protected override void Run(PalClientContext dbContext, ILogger<SaveNewLocations> logger)
|
||||
{
|
||||
Run(_territory, dbContext, _newLocations);
|
||||
Run(_territory, dbContext, logger, _newLocations);
|
||||
}
|
||||
|
||||
public static void Run(MemoryTerritory territory, PalClientContext dbContext,
|
||||
public static void Run<T>(
|
||||
MemoryTerritory territory,
|
||||
PalClientContext dbContext,
|
||||
ILogger<T> logger,
|
||||
List<PersistentLocation> locations)
|
||||
{
|
||||
lock (territory.LockObj)
|
||||
{
|
||||
logger.LogInformation("Saving {Count} new locations for territory {Territory}", locations.Count,
|
||||
territory.TerritoryType);
|
||||
|
||||
Dictionary<PersistentLocation, ClientLocation> mapping =
|
||||
locations.ToDictionary(x => x, x => ToDatabaseLocation(x, territory.TerritoryType));
|
||||
dbContext.Locations.AddRange(mapping.Values);
|
||||
|
@ -11,13 +11,15 @@ using System.Threading.Tasks;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Properties;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
|
||||
namespace Pal.Client.Net
|
||||
{
|
||||
internal partial class RemoteApi
|
||||
{
|
||||
private async Task<(bool Success, string Error)> TryConnect(CancellationToken cancellationToken, ILoggerFactory? loggerFactory = null, bool retry = true)
|
||||
private readonly SemaphoreSlim connectLock = new(1, 1);
|
||||
|
||||
private async Task<(bool Success, string Error)> TryConnect(CancellationToken cancellationToken,
|
||||
ILoggerFactory? loggerFactory = null, bool retry = true)
|
||||
{
|
||||
using IDisposable? logScope = _logger.BeginScope("TryConnect");
|
||||
|
||||
@ -27,7 +29,8 @@ namespace Pal.Client.Net
|
||||
return (false, Localization.ConnectionError_NotOnline);
|
||||
}
|
||||
|
||||
if (_channel == null || !(_channel.State == ConnectivityState.Ready || _channel.State == ConnectivityState.Idle))
|
||||
if (_channel == null ||
|
||||
!(_channel.State == ConnectivityState.Ready || _channel.State == ConnectivityState.Idle))
|
||||
{
|
||||
Dispose();
|
||||
|
||||
@ -48,97 +51,122 @@ namespace Pal.Client.Net
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var accountClient = new AccountService.AccountServiceClient(_channel);
|
||||
IAccountConfiguration? configuredAccount = _configuration.FindAccount(RemoteUrl);
|
||||
if (configuredAccount == null)
|
||||
_logger.LogTrace("Acquiring connect lock");
|
||||
await connectLock.WaitAsync(cancellationToken);
|
||||
_logger.LogTrace("Obtained connect lock");
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("No account information saved for {Url}, creating new account", RemoteUrl);
|
||||
var createAccountReply = await accountClient.CreateAccountAsync(new CreateAccountRequest(), headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
||||
if (createAccountReply.Success)
|
||||
var accountClient = new AccountService.AccountServiceClient(_channel);
|
||||
IAccountConfiguration? configuredAccount = _configuration.FindAccount(RemoteUrl);
|
||||
if (configuredAccount == null)
|
||||
{
|
||||
if (!Guid.TryParse(createAccountReply.AccountId, out Guid accountId))
|
||||
throw new InvalidOperationException("invalid account id returned");
|
||||
|
||||
configuredAccount = _configuration.CreateAccount(RemoteUrl, accountId);
|
||||
_logger.LogInformation("Account created with id {AccountId}", accountId.ToPartialId());
|
||||
|
||||
_configurationManager.Save(_configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Account creation failed with error {Error}", createAccountReply.Error);
|
||||
if (createAccountReply.Error == CreateAccountError.UpgradeRequired && !_warnedAboutUpgrade)
|
||||
_logger.LogInformation("No account information saved for {Url}, creating new account", RemoteUrl);
|
||||
var createAccountReply = await accountClient.CreateAccountAsync(new CreateAccountRequest(),
|
||||
headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10),
|
||||
cancellationToken: cancellationToken);
|
||||
if (createAccountReply.Success)
|
||||
{
|
||||
_chat.Error(Localization.ConnectionError_OldVersion);
|
||||
_warnedAboutUpgrade = true;
|
||||
}
|
||||
return (false, string.Format(Localization.ConnectionError_CreateAccountFailed, createAccountReply.Error));
|
||||
}
|
||||
}
|
||||
if (!Guid.TryParse(createAccountReply.AccountId, out Guid accountId))
|
||||
throw new InvalidOperationException("invalid account id returned");
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
configuredAccount = _configuration.CreateAccount(RemoteUrl, accountId);
|
||||
_logger.LogInformation("Account created with id {AccountId}", accountId.ToPartialId());
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (configuredAccount == null)
|
||||
{
|
||||
_logger.LogWarning("No account to login with");
|
||||
return (false, Localization.ConnectionError_CreateAccountReturnedNoId);
|
||||
}
|
||||
|
||||
if (!_loginInfo.IsValid)
|
||||
{
|
||||
_logger.LogInformation("Logging in with account id {AccountId}", configuredAccount.AccountId.ToPartialId());
|
||||
LoginReply loginReply = await accountClient.LoginAsync(new LoginRequest { AccountId = configuredAccount.AccountId.ToString() }, headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
||||
if (loginReply.Success)
|
||||
{
|
||||
_logger.LogInformation("Login successful with account id: {AccountId}", configuredAccount.AccountId.ToPartialId());
|
||||
_loginInfo = new LoginInfo(loginReply.AuthToken);
|
||||
|
||||
bool save = configuredAccount.EncryptIfNeeded();
|
||||
|
||||
List<string> newRoles = _loginInfo.Claims?.Roles.ToList() ?? new();
|
||||
if (!newRoles.SequenceEqual(configuredAccount.CachedRoles))
|
||||
{
|
||||
configuredAccount.CachedRoles = newRoles;
|
||||
save = true;
|
||||
}
|
||||
|
||||
if (save)
|
||||
_configurationManager.Save(_configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Login failed with error {Error}", loginReply.Error);
|
||||
_loginInfo = new LoginInfo(null);
|
||||
if (loginReply.Error == LoginError.InvalidAccountId)
|
||||
}
|
||||
else
|
||||
{
|
||||
_configuration.RemoveAccount(RemoteUrl);
|
||||
_configurationManager.Save(_configuration);
|
||||
if (retry)
|
||||
_logger.LogError("Account creation failed with error {Error}", createAccountReply.Error);
|
||||
if (createAccountReply.Error == CreateAccountError.UpgradeRequired && !_warnedAboutUpgrade)
|
||||
{
|
||||
_logger.LogInformation("Attempting connection retry without account id");
|
||||
return await TryConnect(cancellationToken, retry: false);
|
||||
_chat.Error(Localization.ConnectionError_OldVersion);
|
||||
_warnedAboutUpgrade = true;
|
||||
}
|
||||
else
|
||||
return (false, Localization.ConnectionError_InvalidAccountId);
|
||||
|
||||
return (false,
|
||||
string.Format(Localization.ConnectionError_CreateAccountFailed, createAccountReply.Error));
|
||||
}
|
||||
if (loginReply.Error == LoginError.UpgradeRequired && !_warnedAboutUpgrade)
|
||||
{
|
||||
_chat.Error(Localization.ConnectionError_OldVersion);
|
||||
_warnedAboutUpgrade = true;
|
||||
}
|
||||
return (false, string.Format(Localization.ConnectionError_LoginFailed, loginReply.Error));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_loginInfo.IsValid)
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (configuredAccount == null)
|
||||
{
|
||||
_logger.LogWarning("No account to login with");
|
||||
return (false, Localization.ConnectionError_CreateAccountReturnedNoId);
|
||||
}
|
||||
|
||||
if (!_loginInfo.IsValid)
|
||||
{
|
||||
_logger.LogInformation("Logging in with account id {AccountId}",
|
||||
configuredAccount.AccountId.ToPartialId());
|
||||
LoginReply loginReply = await accountClient.LoginAsync(
|
||||
new LoginRequest { AccountId = configuredAccount.AccountId.ToString() },
|
||||
headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10),
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
if (loginReply.Success)
|
||||
{
|
||||
_logger.LogInformation("Login successful with account id: {AccountId}",
|
||||
configuredAccount.AccountId.ToPartialId());
|
||||
_loginInfo = new LoginInfo(loginReply.AuthToken);
|
||||
|
||||
bool save = configuredAccount.EncryptIfNeeded();
|
||||
|
||||
List<string> newRoles = _loginInfo.Claims?.Roles.ToList() ?? new();
|
||||
if (!newRoles.SequenceEqual(configuredAccount.CachedRoles))
|
||||
{
|
||||
configuredAccount.CachedRoles = newRoles;
|
||||
save = true;
|
||||
}
|
||||
|
||||
if (save)
|
||||
_configurationManager.Save(_configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Login failed with error {Error}", loginReply.Error);
|
||||
_loginInfo = new LoginInfo(null);
|
||||
if (loginReply.Error == LoginError.InvalidAccountId)
|
||||
{
|
||||
_configuration.RemoveAccount(RemoteUrl);
|
||||
_configurationManager.Save(_configuration);
|
||||
if (retry)
|
||||
{
|
||||
_logger.LogInformation("Attempting connection retry without account id");
|
||||
return await TryConnect(cancellationToken, retry: false);
|
||||
}
|
||||
else
|
||||
return (false, Localization.ConnectionError_InvalidAccountId);
|
||||
}
|
||||
|
||||
if (loginReply.Error == LoginError.UpgradeRequired && !_warnedAboutUpgrade)
|
||||
{
|
||||
_chat.Error(Localization.ConnectionError_OldVersion);
|
||||
_warnedAboutUpgrade = true;
|
||||
}
|
||||
|
||||
return (false, string.Format(Localization.ConnectionError_LoginFailed, loginReply.Error));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_loginInfo.IsValid)
|
||||
{
|
||||
_logger.LogError("Login state is loggedIn={LoggedIn}, expired={Expired}", _loginInfo.IsLoggedIn,
|
||||
_loginInfo.IsExpired);
|
||||
return (false, Localization.ConnectionError_LoginReturnedNoToken);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (true, string.Empty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_logger.LogError("Login state is loggedIn={LoggedIn}, expired={Expired}", _loginInfo.IsLoggedIn, _loginInfo.IsExpired);
|
||||
return (false, Localization.ConnectionError_LoginReturnedNoToken);
|
||||
_logger.LogTrace("Releasing connectLock");
|
||||
connectLock.Release();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (true, string.Empty);
|
||||
}
|
||||
|
||||
private async Task<bool> Connect(CancellationToken cancellationToken)
|
||||
@ -159,7 +187,8 @@ namespace Pal.Client.Net
|
||||
|
||||
_logger.LogInformation("Connection established, trying to verify auth token");
|
||||
var accountClient = new AccountService.AccountServiceClient(_channel);
|
||||
await accountClient.VerifyAsync(new VerifyRequest(), headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
||||
await accountClient.VerifyAsync(new VerifyRequest(), headers: AuthorizedHeaders(),
|
||||
deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
||||
|
||||
_logger.LogInformation("Verification returned no errors.");
|
||||
return Localization.ConnectionSuccessful;
|
||||
@ -182,7 +211,10 @@ namespace Pal.Client.Net
|
||||
public bool IsLoggedIn { get; }
|
||||
public string? AuthToken { get; }
|
||||
public JwtClaims? Claims { get; }
|
||||
private DateTimeOffset ExpiresAt => Claims?.ExpiresAt.Subtract(TimeSpan.FromMinutes(5)) ?? DateTimeOffset.MinValue;
|
||||
|
||||
private DateTimeOffset ExpiresAt =>
|
||||
Claims?.ExpiresAt.Subtract(TimeSpan.FromMinutes(5)) ?? DateTimeOffset.MinValue;
|
||||
|
||||
public bool IsExpired => ExpiresAt < DateTimeOffset.UtcNow;
|
||||
|
||||
public bool IsValid => IsLoggedIn && !IsExpired;
|
||||
|
@ -36,7 +36,7 @@ namespace Pal.Client.Net
|
||||
};
|
||||
uploadRequest.Objects.AddRange(locations.Select(m => new PalaceObject
|
||||
{
|
||||
Type = (ObjectType)m.Type,
|
||||
Type = m.Type.ToObjectType(),
|
||||
X = m.Position.X,
|
||||
Y = m.Position.Y,
|
||||
Z = m.Position.Z
|
||||
|
@ -11,7 +11,7 @@ namespace Pal.Client.Net
|
||||
internal sealed partial class RemoteApi : IDisposable
|
||||
{
|
||||
#if DEBUG
|
||||
public const string RemoteUrl = "http://localhost:5145";
|
||||
public const string RemoteUrl = "http://localhost:5415";
|
||||
#else
|
||||
//public const string RemoteUrl = "https://pal.liza.sh";
|
||||
#endif
|
||||
|
@ -36,7 +36,7 @@ namespace Pal.Client
|
||||
private readonly IServiceScope _rootScope;
|
||||
private readonly DependencyInjectionLoader _loader;
|
||||
|
||||
private Action? _loginAction = null;
|
||||
private Action? _loginAction;
|
||||
|
||||
public Plugin(
|
||||
DalamudPluginInterface pluginInterface,
|
||||
|
@ -9,6 +9,7 @@ using Pal.Client.Extensions;
|
||||
using Pal.Client.Floors;
|
||||
using Pal.Client.Floors.Tasks;
|
||||
using Pal.Client.Net;
|
||||
using Pal.Common;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
@ -47,12 +48,21 @@ namespace Pal.Client.Scheduled
|
||||
{
|
||||
recreateLayout = true;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Sync response for territory {Territory} of type {Type}, success = {Success}, response objects = {Count}",
|
||||
(ETerritoryType)queued.TerritoryType, queued.Type, queued.Success, queued.Locations.Count);
|
||||
var memoryTerritory = _floorService.GetTerritoryIfReady(queued.TerritoryType);
|
||||
if (memoryTerritory == null)
|
||||
{
|
||||
_logger.LogWarning("Discarding sync response for territory {Territory} as it isn't ready",
|
||||
(ETerritoryType)queued.TerritoryType);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var remoteMarkers = queued.Locations;
|
||||
var memoryTerritory = _floorService.GetTerritoryIfReady(queued.TerritoryType);
|
||||
if (memoryTerritory != null && _configuration.Mode == EMode.Online && queued.Success &&
|
||||
remoteMarkers.Count > 0)
|
||||
if (_configuration.Mode == EMode.Online && queued.Success && remoteMarkers.Count > 0)
|
||||
{
|
||||
switch (queued.Type)
|
||||
{
|
||||
@ -117,16 +127,17 @@ namespace Pal.Client.Scheduled
|
||||
if (queued.Type == SyncType.Download)
|
||||
{
|
||||
if (queued.Success)
|
||||
_territoryState.TerritorySyncState = ESyncState.Complete;
|
||||
memoryTerritory.SyncState = ESyncState.Complete;
|
||||
else
|
||||
_territoryState.TerritorySyncState = ESyncState.Failed;
|
||||
memoryTerritory.SyncState = ESyncState.Failed;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Sync failed for territory {Territory}", (ETerritoryType)queued.TerritoryType);
|
||||
_debugState.SetFromException(e);
|
||||
if (queued.Type == SyncType.Download)
|
||||
_territoryState.TerritorySyncState = ESyncState.Failed;
|
||||
memoryTerritory.SyncState = ESyncState.Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,12 +375,12 @@ namespace Pal.Client.Windows
|
||||
{
|
||||
if (_territoryState.IsInDeepDungeon())
|
||||
{
|
||||
MemoryTerritory? memoryTerritory = _floorService.GetTerritoryIfReady(_territoryState.LastTerritory);
|
||||
ImGui.Text($"You are in a deep dungeon, territory type {_territoryState.LastTerritory}.");
|
||||
ImGui.Text($"Sync State = {_territoryState.TerritorySyncState}");
|
||||
ImGui.Text($"Sync State = {memoryTerritory?.SyncState.ToString() ?? "Unknown"}");
|
||||
ImGui.Text($"{_debugState.DebugMessage}");
|
||||
|
||||
ImGui.Indent();
|
||||
MemoryTerritory? memoryTerritory = _floorService.GetTerritoryIfReady(_territoryState.LastTerritory);
|
||||
if (memoryTerritory != null)
|
||||
{
|
||||
if (_trapConfig.Show)
|
||||
|
Loading…
Reference in New Issue
Block a user