rework file cache management, force usage of websocket, add uid comments per server

This commit is contained in:
Stanley Dimant
2022-06-28 23:45:49 +02:00
parent 3ee082d371
commit 71d48b0d8c
7 changed files with 203 additions and 115 deletions

View File

@@ -3,11 +3,40 @@ using Dalamud.Plugin;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using MareSynchronos.Utils;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using Newtonsoft.Json;
namespace MareSynchronos namespace MareSynchronos
{ {
public static class ConfigurationExtensions
{
public static bool HasValidSetup(this Configuration configuration)
{
return configuration.AcceptedAgreement && configuration.InitialScanComplete
&& !string.IsNullOrEmpty(configuration.CacheFolder)
&& Directory.Exists(configuration.CacheFolder)
&& configuration.ClientSecret.ContainsKey(configuration.ApiUri);
}
public static Dictionary<string, string> GetCurrentServerUidComments(this Configuration configuration)
{
return configuration.UidServerComments.ContainsKey(configuration.ApiUri)
? configuration.UidServerComments[configuration.ApiUri]
: new Dictionary<string, string>();
}
public static void SetCurrentServerUidComment(this Configuration configuration, string uid, string comment)
{
if (!configuration.UidServerComments.ContainsKey(configuration.ApiUri))
{
configuration.UidServerComments[configuration.ApiUri] = new Dictionary<string, string>();
}
configuration.UidServerComments[configuration.ApiUri][uid] = comment;
}
}
[Serializable] [Serializable]
public class Configuration : IPluginConfiguration public class Configuration : IPluginConfiguration
{ {
@@ -26,9 +55,6 @@ namespace MareSynchronos
public string CacheFolder { get; set; } = string.Empty; public string CacheFolder { get; set; } = string.Empty;
public Dictionary<string, string> ClientSecret { get; set; } = new(); public Dictionary<string, string> ClientSecret { get; set; } = new();
public Dictionary<string, string> CustomServerList { get; set; } = new(); public Dictionary<string, string> CustomServerList { get; set; } = new();
[JsonIgnore]
public bool HasValidSetup => AcceptedAgreement && InitialScanComplete && !string.IsNullOrEmpty(CacheFolder) &&
Directory.Exists(CacheFolder) && ClientSecret.ContainsKey(ApiUri);
public bool InitialScanComplete { get; set; } = false; public bool InitialScanComplete { get; set; } = false;
public int MaxParallelScan public int MaxParallelScan
@@ -46,8 +72,10 @@ namespace MareSynchronos
} }
public bool FullPause { get; set; } = false; public bool FullPause { get; set; } = false;
public Dictionary<string, Dictionary<string, string>> UidServerComments { get; set; } = new();
public Dictionary<string, string> UidComments { get; set; } = new(); public Dictionary<string, string> UidComments { get; set; } = new();
public int Version { get; set; } = 0; public int Version { get; set; } = 1;
public bool ShowTransferWindow { get; set; } = true; public bool ShowTransferWindow { get; set; } = true;
@@ -61,5 +89,31 @@ namespace MareSynchronos
{ {
_pluginInterface!.SavePluginConfig(this); _pluginInterface!.SavePluginConfig(this);
} }
public void Migrate()
{
if (Version == 0)
{
Logger.Debug("Migrating Configuration from V0 to V1");
Version = 1;
ApiUri = ApiUri.Replace("https", "wss");
foreach (var kvp in ClientSecret.ToList())
{
var newKey = kvp.Key.Replace("https", "wss");
ClientSecret.Remove(kvp.Key);
if (ClientSecret.ContainsKey(newKey))
{
ClientSecret[newKey] = kvp.Value;
}
else
{
ClientSecret.Add(newKey, kvp.Value);
}
}
UidServerComments.Add(ApiUri, UidComments.ToDictionary(k => k.Key, k => k.Value));
UidComments.Clear();
Save();
}
}
} }
} }

View File

@@ -14,9 +14,13 @@ namespace MareSynchronos.Managers
public class FileCacheManager : IDisposable public class FileCacheManager : IDisposable
{ {
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly ConcurrentBag<string> _modifiedFiles = new();
private readonly Configuration _pluginConfiguration; private readonly Configuration _pluginConfiguration;
private FileSystemWatcher? _cacheDirWatcher; private FileSystemWatcher? _cacheDirWatcher;
private FileSystemWatcher? _penumbraDirWatcher; private FileSystemWatcher? _penumbraDirWatcher;
private Task? _rescanTask;
private CancellationTokenSource? _rescanTaskCancellationTokenSource;
private CancellationTokenSource? _rescanTaskRunCancellationTokenSource;
private CancellationTokenSource? _scanCancellationTokenSource; private CancellationTokenSource? _scanCancellationTokenSource;
private Task? _scanTask; private Task? _scanTask;
public FileCacheManager(IpcManager ipcManager, Configuration pluginConfiguration) public FileCacheManager(IpcManager ipcManager, Configuration pluginConfiguration)
@@ -32,26 +36,10 @@ namespace MareSynchronos.Managers
_ipcManager.PenumbraDisposed += IpcManagerOnPenumbraDisposed; _ipcManager.PenumbraDisposed += IpcManagerOnPenumbraDisposed;
} }
private void StartWatchersAndScan()
{
if (!_ipcManager.Initialized || !_pluginConfiguration.HasValidSetup) return;
Logger.Debug("Penumbra is active, configuration is valid, starting watchers and scan");
StartWatchers();
StartInitialScan();
}
private void IpcManagerOnPenumbraInitialized(object? sender, EventArgs e)
{
StartWatchersAndScan();
}
private void IpcManagerOnPenumbraDisposed(object? sender, EventArgs e)
{
StopWatchersAndScan();
}
public long CurrentFileProgress { get; private set; } public long CurrentFileProgress { get; private set; }
public long FileCacheSize { get; set; } public long FileCacheSize { get; set; }
public bool IsScanRunning => !_scanTask?.IsCompleted ?? false; public bool IsScanRunning => !_scanTask?.IsCompleted ?? false;
public long TotalFiles { get; private set; } public long TotalFiles { get; private set; }
@@ -83,17 +71,12 @@ namespace MareSynchronos.Managers
_ipcManager.PenumbraInitialized -= IpcManagerOnPenumbraInitialized; _ipcManager.PenumbraInitialized -= IpcManagerOnPenumbraInitialized;
_ipcManager.PenumbraDisposed -= IpcManagerOnPenumbraDisposed; _ipcManager.PenumbraDisposed -= IpcManagerOnPenumbraDisposed;
_rescanTaskCancellationTokenSource?.Cancel();
_rescanTaskRunCancellationTokenSource?.Cancel();
StopWatchersAndScan(); StopWatchersAndScan();
} }
private void StopWatchersAndScan()
{
_cacheDirWatcher?.Dispose();
_penumbraDirWatcher?.Dispose();
_scanCancellationTokenSource?.Cancel();
}
public void StartInitialScan() public void StartInitialScan()
{ {
_scanCancellationTokenSource = new CancellationTokenSource(); _scanCancellationTokenSource = new CancellationTokenSource();
@@ -102,8 +85,8 @@ namespace MareSynchronos.Managers
public void StartWatchers() public void StartWatchers()
{ {
if (!_ipcManager.Initialized || !_pluginConfiguration.HasValidSetup) return; if (!_ipcManager.Initialized || !_pluginConfiguration.HasValidSetup()) return;
Logger.Debug("Starting File System Watchers"); Logger.Verbose("Starting File System Watchers");
_penumbraDirWatcher?.Dispose(); _penumbraDirWatcher?.Dispose();
_cacheDirWatcher?.Dispose(); _cacheDirWatcher?.Dispose();
@@ -113,8 +96,9 @@ namespace MareSynchronos.Managers
InternalBufferSize = 1048576 InternalBufferSize = 1048576
}; };
_penumbraDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; _penumbraDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
_penumbraDirWatcher.Deleted += OnDeleted; _penumbraDirWatcher.Deleted += OnModified;
_penumbraDirWatcher.Changed += OnModified; _penumbraDirWatcher.Changed += OnModified;
_penumbraDirWatcher.Renamed += OnModified;
_penumbraDirWatcher.Filters.Add("*.mtrl"); _penumbraDirWatcher.Filters.Add("*.mtrl");
_penumbraDirWatcher.Filters.Add("*.mdl"); _penumbraDirWatcher.Filters.Add("*.mdl");
_penumbraDirWatcher.Filters.Add("*.tex"); _penumbraDirWatcher.Filters.Add("*.tex");
@@ -127,8 +111,9 @@ namespace MareSynchronos.Managers
InternalBufferSize = 1048576 InternalBufferSize = 1048576
}; };
_cacheDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; _cacheDirWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
_cacheDirWatcher.Deleted += OnDeleted; _cacheDirWatcher.Deleted += OnModified;
_cacheDirWatcher.Changed += OnModified; _cacheDirWatcher.Changed += OnModified;
_cacheDirWatcher.Renamed += OnModified;
_cacheDirWatcher.Filters.Add("*.mtrl"); _cacheDirWatcher.Filters.Add("*.mtrl");
_cacheDirWatcher.Filters.Add("*.mdl"); _cacheDirWatcher.Filters.Add("*.mdl");
_cacheDirWatcher.Filters.Add("*.tex"); _cacheDirWatcher.Filters.Add("*.tex");
@@ -139,6 +124,16 @@ namespace MareSynchronos.Managers
Task.Run(RecalculateFileCacheSize); Task.Run(RecalculateFileCacheSize);
} }
private void IpcManagerOnPenumbraDisposed(object? sender, EventArgs e)
{
StopWatchersAndScan();
}
private void IpcManagerOnPenumbraInitialized(object? sender, EventArgs e)
{
StartWatchersAndScan();
}
private bool IsFileLocked(FileInfo file) private bool IsFileLocked(FileInfo file)
{ {
try try
@@ -153,62 +148,10 @@ namespace MareSynchronos.Managers
return false; return false;
} }
private void OnDeleted(object sender, FileSystemEventArgs e)
{
var fi = new FileInfo(e.FullPath);
using var db = new FileCacheContext();
var ext = fi.Extension.ToLower();
if (ext is ".mdl" or ".tex" or ".mtrl")
{
Logger.Debug("File deleted: " + e.FullPath);
var fileInDb = db.FileCaches.SingleOrDefault(f => f.Filepath == fi.FullName.ToLower());
if (fileInDb == null) return;
db.Remove(fileInDb);
}
else
{
if (fi.Extension == string.Empty)
{
// this is most likely a folder
var filesToRemove = db.FileCaches.Where(f => f.Filepath.StartsWith(e.FullPath.ToLower())).ToList();
Logger.Debug($"Folder deleted: {e.FullPath}, removing {filesToRemove.Count} files");
db.RemoveRange(filesToRemove);
}
}
db.SaveChanges();
if (e.FullPath.Contains(_pluginConfiguration.CacheFolder, StringComparison.OrdinalIgnoreCase))
{
Task.Run(RecalculateFileCacheSize);
}
}
private void OnModified(object sender, FileSystemEventArgs e) private void OnModified(object sender, FileSystemEventArgs e)
{ {
var fi = new FileInfo(e.FullPath); _modifiedFiles.Add(e.FullPath);
Logger.Debug("File changed: " + e.FullPath); Task.Run(() => _ = RescanTask());
using var db = new FileCacheContext();
var modifiedFile = Create(fi.FullName);
var fileInDb = db.FileCaches.SingleOrDefault(f => f.Filepath == fi.FullName.ToLower());
if (fileInDb != null)
db.Remove(fileInDb);
else
{
var files = db.FileCaches.Where(f => f.Hash == modifiedFile.Hash);
foreach (var file in files)
{
if (!File.Exists(file.Filepath)) db.Remove(file.Filepath);
}
}
db.Add(modifiedFile);
db.SaveChanges();
if (e.FullPath.Contains(_pluginConfiguration.CacheFolder, StringComparison.OrdinalIgnoreCase))
{
Task.Run(RecalculateFileCacheSize);
}
} }
private void RecalculateFileCacheSize() private void RecalculateFileCacheSize()
@@ -227,6 +170,55 @@ namespace MareSynchronos.Managers
} }
} }
public async Task RescanTask(bool force = false)
{
_rescanTaskRunCancellationTokenSource?.Cancel();
_rescanTaskRunCancellationTokenSource = new CancellationTokenSource();
var token = _rescanTaskRunCancellationTokenSource.Token;
if(!force)
await Task.Delay(TimeSpan.FromSeconds(1), token);
while ((!_rescanTask?.IsCompleted ?? false) && !token.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
if (token.IsCancellationRequested) return;
PluginLog.Debug("File changes detected, scanning the changes");
if (!_modifiedFiles.Any()) return;
_rescanTaskCancellationTokenSource = new CancellationTokenSource();
_rescanTask = Task.Run(async () =>
{
var listCopy = _modifiedFiles.ToList();
_modifiedFiles.Clear();
await using var db = new FileCacheContext();
foreach (var item in listCopy.Distinct())
{
var fi = new FileInfo(item);
if (!fi.Exists)
{
PluginLog.Verbose("Removed: " + item);
db.RemoveRange(db.FileCaches.Where(f => f.Filepath.ToLower() == item.ToLower()));
}
else
{
PluginLog.Verbose("Changed :" + item);
var fileCache = Create(item);
db.RemoveRange(db.FileCaches.Where(f => f.Hash == fileCache.Hash));
await db.AddAsync(fileCache, _rescanTaskCancellationTokenSource.Token);
}
}
await db.SaveChangesAsync(_rescanTaskCancellationTokenSource.Token);
RecalculateFileCacheSize();
}, _rescanTaskCancellationTokenSource.Token);
}
private async Task StartFileScan(CancellationToken ct) private async Task StartFileScan(CancellationToken ct)
{ {
_scanCancellationTokenSource = new CancellationTokenSource(); _scanCancellationTokenSource = new CancellationTokenSource();
@@ -341,5 +333,17 @@ namespace MareSynchronos.Managers
_pluginConfiguration.Save(); _pluginConfiguration.Save();
} }
} }
private void StartWatchersAndScan()
{
if (!_ipcManager.Initialized || !_pluginConfiguration.HasValidSetup()) return;
Logger.Verbose("Penumbra is active, configuration is valid, starting watchers and scan");
StartWatchers();
StartInitialScan();
}
private void StopWatchersAndScan()
{
_cacheDirWatcher?.Dispose();
}
} }
} }

View File

@@ -29,7 +29,6 @@
<PackageReference Include="lz4net" Version="1.0.15.93" /> <PackageReference Include="lz4net" Version="1.0.15.93" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.6" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.17" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.17" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -47,6 +47,7 @@ namespace MareSynchronos
_clientState = clientState; _clientState = clientState;
_configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); _configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
_configuration.Initialize(PluginInterface); _configuration.Initialize(PluginInterface);
_configuration.Migrate();
_windowSystem = new WindowSystem("MareSynchronos"); _windowSystem = new WindowSystem("MareSynchronos");
@@ -123,7 +124,7 @@ namespace MareSynchronos
HelpMessage = "Opens the Mare Synchronos UI" HelpMessage = "Opens the Mare Synchronos UI"
}); });
if (!_configuration.HasValidSetup) if (!_configuration.HasValidSetup())
{ {
_introUi.IsOpen = true; _introUi.IsOpen = true;
return; return;
@@ -188,7 +189,7 @@ namespace MareSynchronos
private void OpenConfigUi() private void OpenConfigUi()
{ {
if (_configuration.HasValidSetup) if (_configuration.HasValidSetup())
_pluginUi.Toggle(); _pluginUi.Toggle();
else else
_introUi.Toggle(); _introUi.Toggle();

View File

@@ -4,6 +4,7 @@ using Dalamud.Interface.Windowing;
using ImGuiNET; using ImGuiNET;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
@@ -179,7 +180,7 @@ namespace MareSynchronos.UI
var marePaused = _configuration.FullPause; var marePaused = _configuration.FullPause;
if (_configuration.HasValidSetup) if (_configuration.HasValidSetup())
{ {
if (ImGui.Checkbox("Pause Mare Synchronos", ref marePaused)) if (ImGui.Checkbox("Pause Mare Synchronos", ref marePaused))
{ {
@@ -299,6 +300,8 @@ namespace MareSynchronos.UI
{ {
File.Delete(file); File.Delete(file);
} }
_uiShared.ForceRescan();
}); });
} }
ImGui.TreePop(); ImGui.TreePop();
@@ -340,11 +343,16 @@ namespace MareSynchronos.UI
: ((item.IsPaused || item.IsPausedFromOthers) ? "Unpaired" : "Paired"); : ((item.IsPaused || item.IsPausedFromOthers) ? "Unpaired" : "Paired");
ImGui.TextColored(UiShared.GetBoolColor(item.IsSynced && !item.IsPaused && !item.IsPausedFromOthers), pairString); ImGui.TextColored(UiShared.GetBoolColor(item.IsSynced && !item.IsPaused && !item.IsPausedFromOthers), pairString);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
string charComment = _configuration.UidComments.ContainsKey(item.OtherUID) ? _configuration.UidComments[item.OtherUID] : string.Empty; string charComment = _configuration.GetCurrentServerUidComments().ContainsKey(item.OtherUID) ? _configuration.GetCurrentServerUidComments()[item.OtherUID] : string.Empty;
ImGui.SetNextItemWidth(400); ImGui.SetNextItemWidth(400);
if (ImGui.InputTextWithHint("##comment" + item.OtherUID, "Add your comment here (comments will not be synced)", ref charComment, 255)) if (ImGui.InputTextWithHint("##comment" + item.OtherUID, "Add your comment here (comments will not be synced)", ref charComment, 255))
{ {
_configuration.UidComments[item.OtherUID] = charComment; if (_configuration.GetCurrentServerUidComments().Count == 0)
{
_configuration.UidServerComments[_configuration.ApiUri] =
new Dictionary<string, string>();
}
_configuration.SetCurrentServerUidComment(item.OtherUID, charComment);
_configuration.Save(); _configuration.Save();
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@@ -362,21 +370,21 @@ namespace MareSynchronos.UI
ImGui.EndTable(); ImGui.EndTable();
} }
var pairedClientEntry = tempNameUID; var pairedClientEntry = _tempNameUID;
ImGui.SetNextItemWidth(200); ImGui.SetNextItemWidth(200);
if (ImGui.InputText("UID", ref pairedClientEntry, 20)) if (ImGui.InputText("UID", ref pairedClientEntry, 20))
{ {
tempNameUID = pairedClientEntry; _tempNameUID = pairedClientEntry;
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString() + "##addToPairedClients")) if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString() + "##addToPairedClients"))
{ {
if (_apiController.PairedClients.All(w => w.OtherUID != tempNameUID)) if (_apiController.PairedClients.All(w => w.OtherUID != _tempNameUID))
{ {
var nameToSend = tempNameUID; var nameToSend = _tempNameUID;
tempNameUID = string.Empty; _tempNameUID = string.Empty;
_ = _apiController.SendPairedClientAddition(nameToSend); _ = _apiController.SendPairedClientAddition(nameToSend);
} }
} }
@@ -386,6 +394,6 @@ namespace MareSynchronos.UI
} }
} }
private string tempNameUID = string.Empty; private string _tempNameUID = string.Empty;
} }
} }

View File

@@ -54,6 +54,11 @@ namespace MareSynchronos.UI
return true; return true;
} }
public void ForceRescan()
{
Task.Run(() => _ = _fileCacheManager.RescanTask(true));
}
public void DrawFileScanState() public void DrawFileScanState()
{ {
ImGui.Text("File Scanner Status"); ImGui.Text("File Scanner Status");
@@ -78,10 +83,21 @@ namespace MareSynchronos.UI
var serverName = _apiController.ServerDictionary.ContainsKey(_pluginConfiguration.ApiUri) var serverName = _apiController.ServerDictionary.ContainsKey(_pluginConfiguration.ApiUri)
? _apiController.ServerDictionary[_pluginConfiguration.ApiUri] ? _apiController.ServerDictionary[_pluginConfiguration.ApiUri]
: _pluginConfiguration.ApiUri; : _pluginConfiguration.ApiUri;
ImGui.Text("Service status of " + serverName); ImGui.Text("Service status of \"" + serverName + "\":");
ImGui.SameLine(); ImGui.SameLine();
var color = _apiController.ServerAlive ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; var color = _apiController.ServerAlive ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
ImGui.TextColored(color, _apiController.ServerAlive ? "Available" : "Unavailable"); ImGui.TextColored(color, _apiController.ServerAlive ? "Available" : "Unavailable");
if (_apiController.ServerAlive)
{
ImGui.SameLine();
ImGui.TextUnformatted("(");
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.ParsedGreen, _apiController.OnlineUsers.ToString());
ImGui.SameLine();
ImGui.Text("Users Online (server-wide)");
ImGui.SameLine();
ImGui.Text(")");
}
} }
public static void TextWrapped(string text) public static void TextWrapped(string text)
@@ -209,7 +225,7 @@ namespace MareSynchronos.UI
ImGui.InputText("Custom Service Address", ref _customServerUri, 255); ImGui.InputText("Custom Service Address", ref _customServerUri, 255);
if (ImGui.Button("Add Custom Service")) if (ImGui.Button("Add Custom Service"))
{ {
if (!string.IsNullOrEmpty(_customServerUri) if (!string.IsNullOrEmpty(_customServerUri)
&& !string.IsNullOrEmpty(_customServerName) && !string.IsNullOrEmpty(_customServerName)
&& !_pluginConfiguration.CustomServerList.ContainsValue(_customServerName)) && !_pluginConfiguration.CustomServerList.ContainsValue(_customServerName))
{ {

View File

@@ -1,5 +1,4 @@
using Dalamud.Logging; using System;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -12,8 +11,8 @@ using LZ4;
using MareSynchronos.API; using MareSynchronos.API;
using MareSynchronos.FileCacheDB; using MareSynchronos.FileCacheDB;
using MareSynchronos.Utils; using MareSynchronos.Utils;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
namespace MareSynchronos.WebAPI namespace MareSynchronos.WebAPI
{ {
@@ -21,7 +20,7 @@ namespace MareSynchronos.WebAPI
{ {
#if DEBUG #if DEBUG
public const string MainServer = "darkarchons Debug Server (Dev Server (CH))"; public const string MainServer = "darkarchons Debug Server (Dev Server (CH))";
public const string MainServiceUri = "https://darkarchon.internet-box.ch:5001"; public const string MainServiceUri = "wss://darkarchon.internet-box.ch:5001";
#else #else
public const string MainServer = "Lunae Crescere Incipientis (Central Server EU)"; public const string MainServer = "Lunae Crescere Incipientis (Central Server EU)";
public const string MainServiceUri = "to be defined"; public const string MainServiceUri = "to be defined";
@@ -88,12 +87,14 @@ namespace MareSynchronos.WebAPI
public string UID { get; private set; } = string.Empty; public string UID { get; private set; } = string.Empty;
private string ApiUri => _pluginConfiguration.ApiUri; private string ApiUri => _pluginConfiguration.ApiUri;
public int OnlineUsers { get; private set; }
public async Task CreateConnections() public async Task CreateConnections()
{ {
await StopAllConnections(_cts.Token);
_cts = new CancellationTokenSource(); _cts = new CancellationTokenSource();
var token = _cts.Token; var token = _cts.Token;
await StopAllConnections(token);
while (!ServerAlive && !token.IsCancellationRequested) while (!ServerAlive && !token.IsCancellationRequested)
{ {
@@ -110,11 +111,14 @@ namespace MareSynchronos.WebAPI
await _userHub.StartAsync(token); await _userHub.StartAsync(token);
await _fileHub.StartAsync(token); await _fileHub.StartAsync(token);
OnlineUsers = await _userHub.InvokeAsync<int>("GetOnlineUsers", token);
if (_pluginConfiguration.FullPause) if (_pluginConfiguration.FullPause)
{ {
UID = string.Empty; UID = string.Empty;
return; return;
} }
UID = await _heartbeatHub.InvokeAsync<string>("Heartbeat", token); UID = await _heartbeatHub.InvokeAsync<string>("Heartbeat", token);
if (!string.IsNullOrEmpty(UID) && !token.IsCancellationRequested) // user is authorized if (!string.IsNullOrEmpty(UID) && !token.IsCancellationRequested) // user is authorized
{ {
@@ -125,6 +129,7 @@ namespace MareSynchronos.WebAPI
(s) => PairedClientOffline?.Invoke(s, EventArgs.Empty)); (s) => PairedClientOffline?.Invoke(s, EventArgs.Empty));
_userHub.On<string>("AddOnlinePairedPlayer", _userHub.On<string>("AddOnlinePairedPlayer",
(s) => PairedClientOnline?.Invoke(s, EventArgs.Empty)); (s) => PairedClientOnline?.Invoke(s, EventArgs.Empty));
_userHub.On<int>("UsersOnline", (count) => OnlineUsers = count);
PairedClients = await _userHub!.InvokeAsync<List<ClientPairDto>>("GetPairedClients", token); PairedClients = await _userHub!.InvokeAsync<List<ClientPairDto>>("GetPairedClients", token);
@@ -161,13 +166,12 @@ namespace MareSynchronos.WebAPI
{ {
options.Headers.Add("Authorization", SecretKey); options.Headers.Add("Authorization", SecretKey);
} }
options.Transports = HttpTransportType.WebSockets;
#if DEBUG #if DEBUG
options.HttpMessageHandlerFactory = (message) => options.HttpMessageHandlerFactory = (message) => new HttpClientHandler()
{ {
if (message is HttpClientHandler clientHandler) ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
clientHandler.ServerCertificateCustomValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => true;
return message;
}; };
#endif #endif
}) })
@@ -185,6 +189,8 @@ namespace MareSynchronos.WebAPI
private Task HeartbeatHubOnReconnected(string? arg) private Task HeartbeatHubOnReconnected(string? arg)
{ {
Logger.Debug("Connection restored"); Logger.Debug("Connection restored");
OnlineUsers = _userHub!.InvokeAsync<int>("GetOnlineUsers").Result;
UID = _heartbeatHub!.InvokeAsync<string>("Heartbeat").Result;
Connected?.Invoke(this, EventArgs.Empty); Connected?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -198,7 +204,7 @@ namespace MareSynchronos.WebAPI
private async Task StopAllConnections(CancellationToken token) private async Task StopAllConnections(CancellationToken token)
{ {
if (_heartbeatHub is { State: HubConnectionState.Connected }) if (_heartbeatHub is { State: HubConnectionState.Connected or HubConnectionState.Connecting or HubConnectionState.Reconnecting })
{ {
await _heartbeatHub.StopAsync(token); await _heartbeatHub.StopAsync(token);
_heartbeatHub.Closed -= HeartbeatHubOnClosed; _heartbeatHub.Closed -= HeartbeatHubOnClosed;
@@ -207,13 +213,13 @@ namespace MareSynchronos.WebAPI
await _heartbeatHub.DisposeAsync(); await _heartbeatHub.DisposeAsync();
} }
if (_fileHub is { State: HubConnectionState.Connected }) if (_fileHub is { State: HubConnectionState.Connected or HubConnectionState.Connecting or HubConnectionState.Reconnecting })
{ {
await _fileHub.StopAsync(token); await _fileHub.StopAsync(token);
await _fileHub.DisposeAsync(); await _fileHub.DisposeAsync();
} }
if (_userHub is { State: HubConnectionState.Connected }) if (_userHub is { State: HubConnectionState.Connected or HubConnectionState.Connecting or HubConnectionState.Reconnecting })
{ {
await _userHub.StopAsync(token); await _userHub.StopAsync(token);
await _userHub.DisposeAsync(); await _userHub.DisposeAsync();