From 260c4a48ee9143a374e446ec2cce848073e573db Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Mon, 3 Oct 2022 15:58:51 +0200 Subject: [PATCH] add analyzers and api --- .editorconfig | 102 ++++++++++++++++++ MareAPI | 2 +- MareSynchronos.sln | 5 + MareSynchronos/Configuration.cs | 38 +++---- .../Factories/CharacterDataFactory.cs | 12 +-- MareSynchronos/FileCache/FileCache.cs | 2 +- MareSynchronos/FileCache/FileDbManager.cs | 36 +++---- .../FileCache/PeriodicFileScanner.cs | 13 ++- MareSynchronos/Managers/CachedPlayer.cs | 12 +-- MareSynchronos/Managers/IpcManager.cs | 2 +- .../Managers/OnlinePlayerManager.cs | 6 +- MareSynchronos/Managers/PlayerManager.cs | 10 +- .../Managers/TransientResourceManager.cs | 26 ++--- MareSynchronos/MareSynchronos.csproj | 8 ++ MareSynchronos/Models/CharacterData.cs | 8 +- MareSynchronos/Models/FileReplacement.cs | 4 +- MareSynchronos/Models/PlayerRelatedObject.cs | 2 +- MareSynchronos/Plugin.cs | 2 +- MareSynchronos/UI/CompactUI.cs | 26 +++-- MareSynchronos/UI/GroupPanel.cs | 56 ++++++---- MareSynchronos/UI/IntroUI.cs | 14 +-- MareSynchronos/UI/SettingsUi.cs | 2 +- MareSynchronos/UI/UIShared.cs | 4 +- MareSynchronos/Utils/Crypto.cs | 8 +- .../Utils/DalamudLoggingProvider.cs | 26 +++++ MareSynchronos/Utils/DalamudUtil.cs | 6 +- MareSynchronos/Utils/Logger.cs | 24 +---- .../{Various.cs => VariousExtensions.cs} | 2 +- .../WebAPI/ApIController.Functions.Files.cs | 60 +++++------ .../WebAPI/ApIController.Functions.Users.cs | 20 ++-- .../WebAPI/ApiController.Functions.Admin.cs | 10 +- .../ApiController.Functions.Callbacks.cs | 24 ++--- .../WebAPI/ApiController.Functions.Groups.cs | 52 ++++----- MareSynchronos/WebAPI/ApiController.cs | 76 ++++++++----- 34 files changed, 435 insertions(+), 265 deletions(-) create mode 100644 .editorconfig create mode 100644 MareSynchronos/Utils/DalamudLoggingProvider.cs rename MareSynchronos/Utils/{Various.cs => VariousExtensions.cs} (96%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7be38b9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,102 @@ +[*.cs] + +# MA0046: Use EventHandler to declare events +dotnet_diagnostic.MA0046.severity = silent +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +dotnet_diagnostic.MA0016.severity = suggestion +dotnet_diagnostic.MA0051.severity = suggestion + +# MA0009: Add regex evaluation timeout +dotnet_diagnostic.MA0009.severity = silent + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case diff --git a/MareAPI b/MareAPI index a2a4d07..2d5d9d9 160000 --- a/MareAPI +++ b/MareAPI @@ -1 +1 @@ -Subproject commit a2a4d07c046e0dc5ea5a871dda551f866760d5f6 +Subproject commit 2d5d9d9d1cc87eebcf89cddc182e2c47fe31a8b4 diff --git a/MareSynchronos.sln b/MareSynchronos.sln index d92ff59..f38743f 100644 --- a/MareSynchronos.sln +++ b/MareSynchronos.sln @@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "MareA EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{89DD407C-B2B7-4BB3-BF26-C550BA1841F8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{585B740D-BA2C-429B-9CF3-B2D223423748}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/MareSynchronos/Configuration.cs b/MareSynchronos/Configuration.cs index 5ab1507..36e2ffd 100644 --- a/MareSynchronos/Configuration.cs +++ b/MareSynchronos/Configuration.cs @@ -23,21 +23,21 @@ public static class ConfigurationExtensions { return configuration.UidServerComments.ContainsKey(configuration.ApiUri) ? configuration.UidServerComments[configuration.ApiUri] - : new Dictionary(); + : new Dictionary(StringComparer.Ordinal); } public static Dictionary GetCurrentServerGidComments(this Configuration configuration) { return configuration.GidServerComments.ContainsKey(configuration.ApiUri) ? configuration.GidServerComments[configuration.ApiUri] - : new Dictionary(); + : new Dictionary(StringComparer.Ordinal); } public static void SetCurrentServerGidComment(this Configuration configuration, string gid, string comment) { if (!configuration.GidServerComments.ContainsKey(configuration.ApiUri)) { - configuration.GidServerComments[configuration.ApiUri] = new Dictionary(); + configuration.GidServerComments[configuration.ApiUri] = new Dictionary(StringComparer.Ordinal); } configuration.GidServerComments[configuration.ApiUri][gid] = comment; @@ -47,7 +47,7 @@ public static class ConfigurationExtensions { if (!configuration.UidServerComments.ContainsKey(configuration.ApiUri)) { - configuration.UidServerComments[configuration.ApiUri] = new Dictionary(); + configuration.UidServerComments[configuration.ApiUri] = new Dictionary(StringComparer.Ordinal); } configuration.UidServerComments[configuration.ApiUri][uid] = comment; @@ -71,8 +71,8 @@ public class Configuration : IPluginConfiguration } public string CacheFolder { get; set; } = string.Empty; - public Dictionary ClientSecret { get; set; } = new(); - public Dictionary CustomServerList { get; set; } = new(); + public Dictionary ClientSecret { get; set; } = new(StringComparer.Ordinal); + public Dictionary CustomServerList { get; set; } = new(StringComparer.Ordinal); public int MaxLocalCacheInGiB { get; set; } = 20; public bool ReverseUserSort { get; set; } = false; @@ -82,10 +82,10 @@ public class Configuration : IPluginConfiguration public bool InitialScanComplete { get; set; } = false; public bool FullPause { get; set; } = false; - public Dictionary> UidServerComments { get; set; } = new(); - public Dictionary> GidServerComments { get; set; } = new(); + public Dictionary> UidServerComments { get; set; } = new(StringComparer.Ordinal); + public Dictionary> GidServerComments { get; set; } = new(StringComparer.Ordinal); - public Dictionary UidComments { get; set; } = new(); + public Dictionary UidComments { get; set; } = new(StringComparer.Ordinal); public int Version { get; set; } = 5; public bool ShowTransferWindow { get; set; } = true; @@ -114,10 +114,10 @@ public class Configuration : IPluginConfiguration { Logger.Debug("Migrating Configuration from V0 to V1"); Version = 1; - ApiUri = ApiUri.Replace("https", "wss"); + ApiUri = ApiUri.Replace("https", "wss", StringComparison.Ordinal); foreach (var kvp in ClientSecret.ToList()) { - var newKey = kvp.Key.Replace("https", "wss"); + var newKey = kvp.Key.Replace("https", "wss", StringComparison.Ordinal); ClientSecret.Remove(kvp.Key); if (ClientSecret.ContainsKey(newKey)) { @@ -128,7 +128,7 @@ public class Configuration : IPluginConfiguration ClientSecret.Add(newKey, kvp.Value); } } - UidServerComments.Add(ApiUri, UidComments.ToDictionary(k => k.Key, k => k.Value)); + UidServerComments.Add(ApiUri, UidComments.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal)); UidComments.Clear(); Save(); } @@ -136,10 +136,10 @@ public class Configuration : IPluginConfiguration if (Version == 1) { Logger.Debug("Migrating Configuration from V1 to V2"); - ApiUri = ApiUri.Replace("5001", "5000"); + ApiUri = ApiUri.Replace("5001", "5000", StringComparison.Ordinal); foreach (var kvp in ClientSecret.ToList()) { - var newKey = kvp.Key.Replace("5001", "5000"); + var newKey = kvp.Key.Replace("5001", "5000", StringComparison.Ordinal); ClientSecret.Remove(kvp.Key); if (ClientSecret.ContainsKey(newKey)) { @@ -153,7 +153,7 @@ public class Configuration : IPluginConfiguration foreach (var kvp in UidServerComments.ToList()) { - var newKey = kvp.Key.Replace("5001", "5000"); + var newKey = kvp.Key.Replace("5001", "5000", StringComparison.Ordinal); UidServerComments.Remove(kvp.Key); UidServerComments.Add(newKey, kvp.Value); } @@ -177,10 +177,10 @@ public class Configuration : IPluginConfiguration { Logger.Debug("Migrating Configuration from V3 to V4"); - ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872"); + ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal); foreach (var kvp in ClientSecret.ToList()) { - var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872"); + var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal); ClientSecret.Remove(kvp.Key); if (ClientSecret.ContainsKey(newKey)) { @@ -194,7 +194,7 @@ public class Configuration : IPluginConfiguration foreach (var kvp in UidServerComments.ToList()) { - var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872"); + var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal); UidServerComments.Remove(kvp.Key); UidServerComments.Add(newKey, kvp.Value); } @@ -207,7 +207,7 @@ public class Configuration : IPluginConfiguration { Logger.Debug("Migrating Configuration from V4 to V5"); - ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6872", "wss://maresynchronos.com"); + ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6872", "wss://maresynchronos.com", StringComparison.Ordinal); ClientSecret.Remove("wss://v2202207178628194299.powersrv.de:6872"); UidServerComments.Remove("wss://v2202207178628194299.powersrv.de:6872"); diff --git a/MareSynchronos/Factories/CharacterDataFactory.cs b/MareSynchronos/Factories/CharacterDataFactory.cs index f7e767b..efab6a1 100644 --- a/MareSynchronos/Factories/CharacterDataFactory.cs +++ b/MareSynchronos/Factories/CharacterDataFactory.cs @@ -158,7 +158,7 @@ public class CharacterDataFactory if (cache.FileReplacements.ContainsKey(objectKind)) { - if (cache.FileReplacements[objectKind].Any(c => c.ResolvedPath.Contains(mtrlPath))) + if (cache.FileReplacements[objectKind].Any(c => c.ResolvedPath.Contains(mtrlPath, StringComparison.Ordinal))) { return; } @@ -196,7 +196,7 @@ public class CharacterDataFactory if (cache.FileReplacements.ContainsKey(objectKind)) { - if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(varPath))) + if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(varPath, StringComparer.Ordinal))) { return; } @@ -214,7 +214,7 @@ public class CharacterDataFactory if (cache.FileReplacements.ContainsKey(objectKind)) { - if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(texPath))) + if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(texPath, StringComparer.Ordinal))) { return; } @@ -225,7 +225,7 @@ public class CharacterDataFactory cache.AddFileReplacement(objectKind, texFileReplacement); - if (texPath.Contains("/--")) return; + if (texPath.Contains("/--", StringComparison.Ordinal)) return; var texDx11Replacement = CreateFileReplacement(texPath.Insert(texPath.LastIndexOf('/') + 1, "--"), doNotReverseResolve); @@ -322,11 +322,11 @@ public class CharacterDataFactory previousData.FileReplacements.Add(objectKind, new()); } - if (!previousData.FileReplacements[objectKind].Any(k => k.GamePaths.Any(p => item.GamePaths.Select(p => p.ToLowerInvariant()).Contains(p.ToLowerInvariant())))) + if (!previousData.FileReplacements[objectKind].Any(k => k.GamePaths.Any(p => item.GamePaths.Contains(p, StringComparer.OrdinalIgnoreCase)))) { var penumResolve = _ipcManager.PenumbraResolvePath(item.GamePaths.First()).ToLowerInvariant(); var gamePath = item.GamePaths.First().ToLowerInvariant(); - if (penumResolve == gamePath) + if (string.Equals(penumResolve, gamePath, StringComparison.Ordinal)) { Logger.Debug("PenumResolve was same as GamePath, not adding " + item); transientResourceManager.RemoveTransientResource(charaPointer, item); diff --git a/MareSynchronos/FileCache/FileCache.cs b/MareSynchronos/FileCache/FileCache.cs index 38aceb9..1bd3b53 100644 --- a/MareSynchronos/FileCache/FileCache.cs +++ b/MareSynchronos/FileCache/FileCache.cs @@ -22,7 +22,7 @@ public class FileCache public void SetResolvedFilePath(string filePath) { - ResolvedFilepath = filePath.ToLowerInvariant().Replace("\\\\", "\\"); + ResolvedFilepath = filePath.ToLowerInvariant().Replace("\\\\", "\\", System.StringComparison.Ordinal); } public string CsvEntry => $"{Hash}{FileCacheManager.CsvSplit}{PrefixedFilePath}{FileCacheManager.CsvSplit}{LastModifiedDateTicks.ToString(CultureInfo.InvariantCulture)}"; diff --git a/MareSynchronos/FileCache/FileDbManager.cs b/MareSynchronos/FileCache/FileDbManager.cs index 7d97516..dd71bd4 100644 --- a/MareSynchronos/FileCache/FileDbManager.cs +++ b/MareSynchronos/FileCache/FileDbManager.cs @@ -26,9 +26,9 @@ public class FileCacheManager : IDisposable private readonly Configuration _configuration; private readonly string CsvPath; private string CsvBakPath => CsvPath + ".bak"; - private readonly ConcurrentDictionary FileCaches = new(); + private readonly ConcurrentDictionary FileCaches = new(StringComparer.Ordinal); public const string CsvSplit = "|"; - private object _fileWriteLock = new object(); + private object _fileWriteLock = new(); public FileCacheManager(IpcManager ipcManager, Configuration configuration, string configDirectoryName) { @@ -64,7 +64,7 @@ public class FileCacheManager : IDisposable public void WriteOutFullCsv() { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new(); foreach (var entry in FileCaches.OrderBy(f => f.Value.PrefixedFilePath)) { sb.AppendLine(entry.Value.CsvEntry); @@ -91,9 +91,9 @@ public class FileCacheManager : IDisposable public FileCache? GetFileCacheByHash(string hash) { - if (FileCaches.Any(f => f.Value.Hash == hash)) + if (FileCaches.Any(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal))) { - return GetValidatedFileCache(FileCaches.FirstOrDefault(f => f.Value.Hash == hash).Value); + return GetValidatedFileCache(FileCaches.FirstOrDefault(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal)).Value); } return null; @@ -107,7 +107,7 @@ public class FileCacheManager : IDisposable { return (FileState.RequireDeletion, fileCache); } - if (fi.LastWriteTimeUtc.Ticks.ToString() != fileCache.LastModifiedDateTicks) + if (!string.Equals(fi.LastWriteTimeUtc.Ticks.ToString(CultureInfo.InvariantCulture), fileCache.LastModifiedDateTicks, StringComparison.Ordinal)) { return (FileState.RequireUpdate, fileCache); } @@ -117,8 +117,8 @@ public class FileCacheManager : IDisposable public FileCache? GetFileCacheByPath(string path) { - var cleanedPath = path.Replace("/", "\\").ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), ""); - var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath)).Value; + var cleanedPath = path.Replace("/", "\\", StringComparison.Ordinal).ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), "", StringComparison.Ordinal); + var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath, StringComparison.Ordinal)).Value; if (entry == null) { @@ -137,9 +137,9 @@ public class FileCacheManager : IDisposable FileInfo fi = new(path); if (!fi.Exists) return null; var fullName = fi.FullName.ToLowerInvariant(); - if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant())) return null; - string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\").Replace("\\\\", "\\"); - return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper()); + if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant(), StringComparison.Ordinal)) return null; + string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal); + return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper(CultureInfo.InvariantCulture)); } public FileCache? CreateFileEntry(string path) @@ -148,8 +148,8 @@ public class FileCacheManager : IDisposable FileInfo fi = new(path); if (!fi.Exists) return null; var fullName = fi.FullName.ToLowerInvariant(); - if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant())) return null; - string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\").Replace("\\\\", "\\"); + if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), StringComparison.Ordinal)) return null; + string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal); return CreateFileCacheEntity(fi, prefixedPath); } @@ -187,7 +187,7 @@ public class FileCacheManager : IDisposable return null; } - if (file.LastWriteTimeUtc.Ticks.ToString() != fileCache.LastModifiedDateTicks) + if (!string.Equals(file.LastWriteTimeUtc.Ticks.ToString(), fileCache.LastModifiedDateTicks, StringComparison.Ordinal)) { UpdateHash(fileCache); } @@ -211,13 +211,13 @@ public class FileCacheManager : IDisposable private FileCache ReplacePathPrefixes(FileCache fileCache) { - if (fileCache.PrefixedFilePath.StartsWith(PenumbraPrefix)) + if (fileCache.PrefixedFilePath.StartsWith(PenumbraPrefix, StringComparison.OrdinalIgnoreCase)) { - fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(PenumbraPrefix, _ipcManager.PenumbraModDirectory())); + fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(PenumbraPrefix, _ipcManager.PenumbraModDirectory(), StringComparison.Ordinal)); } - else if (fileCache.PrefixedFilePath.StartsWith(CachePrefix)) + else if (fileCache.PrefixedFilePath.StartsWith(CachePrefix, StringComparison.OrdinalIgnoreCase)) { - fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(CachePrefix, _configuration.CacheFolder)); + fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(CachePrefix, _configuration.CacheFolder, StringComparison.Ordinal)); } return fileCache; diff --git a/MareSynchronos/FileCache/PeriodicFileScanner.cs b/MareSynchronos/FileCache/PeriodicFileScanner.cs index ce9e649..59d01ef 100644 --- a/MareSynchronos/FileCache/PeriodicFileScanner.cs +++ b/MareSynchronos/FileCache/PeriodicFileScanner.cs @@ -20,7 +20,7 @@ public class PeriodicFileScanner : IDisposable private readonly DalamudUtil _dalamudUtil; private CancellationTokenSource? _scanCancellationTokenSource; private Task? _fileScannerTask = null; - public ConcurrentDictionary haltScanLocks = new(); + public ConcurrentDictionary haltScanLocks = new(StringComparer.Ordinal); public PeriodicFileScanner(IpcManager ipcManager, Configuration pluginConfiguration, FileCacheManager fileDbManager, ApiController apiController, DalamudUtil dalamudUtil) { Logger.Verbose("Creating " + nameof(PeriodicFileScanner)); @@ -128,7 +128,7 @@ public class PeriodicFileScanner : IDisposable { while (haltScanLocks.Any(f => f.Value > 0)) { - await Task.Delay(TimeSpan.FromSeconds(1)); + await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); } isForced |= RecalculateFileCacheSize(); @@ -144,7 +144,7 @@ public class PeriodicFileScanner : IDisposable _timeUntilNextScan = TimeSpan.FromSeconds(timeBetweenScans); while (_timeUntilNextScan.TotalSeconds >= 0) { - await Task.Delay(TimeSpan.FromSeconds(1), token); + await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); _timeUntilNextScan -= TimeSpan.FromSeconds(1); } } @@ -206,11 +206,14 @@ public class PeriodicFileScanner : IDisposable var scannedFiles = new ConcurrentDictionary(Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories) .Select(s => s.ToLowerInvariant()) - .Where(f => ext.Any(e => f.EndsWith(e)) && !f.Contains(@"\bg\") && !f.Contains(@"\bgcommon\") && !f.Contains(@"\ui\")) + .Where(f => ext.Any(e => f.EndsWith(e, StringComparison.OrdinalIgnoreCase)) + && !f.Contains(@"\bg\", StringComparison.OrdinalIgnoreCase) + && !f.Contains(@"\bgcommon\", StringComparison.OrdinalIgnoreCase) + && !f.Contains(@"\ui\", StringComparison.OrdinalIgnoreCase)) .Concat(Directory.EnumerateFiles(_pluginConfiguration.CacheFolder, "*.*", SearchOption.TopDirectoryOnly) .Where(f => new FileInfo(f).Name.Length == 40) .Select(s => s.ToLowerInvariant()).ToList()) - .Select(c => new KeyValuePair(c, false))); + .Select(c => new KeyValuePair(c, false)), StringComparer.OrdinalIgnoreCase); TotalFiles = scannedFiles.Count; diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index b85d936..70318a4 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -71,7 +71,7 @@ public class CachedPlayer if (characterData.GetHashCode() == _cachedData.GetHashCode()) return; bool updateModdedPaths = false; - List charaDataToUpdate = new List(); + List charaDataToUpdate = new(); foreach (var objectKind in Enum.GetValues()) { _cachedData.FileReplacements.TryGetValue(objectKind, out var existingFileReplacements); @@ -108,7 +108,7 @@ public class CachedPlayer if (hasNewAndOldGlamourerData) { - bool glamourerDataDifferent = _cachedData.GlamourerData[objectKind] != characterData.GlamourerData[objectKind]; + bool glamourerDataDifferent = !string.Equals(_cachedData.GlamourerData[objectKind], characterData.GlamourerData[objectKind], StringComparison.Ordinal); if (glamourerDataDifferent) { Logger.Debug("Updating " + objectKind); @@ -159,7 +159,7 @@ public class CachedPlayer Logger.Debug("Downloading missing files for player " + PlayerName + ", kind: " + objectKind); if (toDownloadReplacements.Any()) { - await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken); + await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken).ConfigureAwait(false); _apiController.CancelDownload(downloadId); } if (downloadToken.IsCancellationRequested) @@ -168,7 +168,7 @@ public class CachedPlayer return; } - if ((TryCalculateModdedDictionary(out moddedPaths)).All(c => _apiController.ForbiddenTransfers.Any(f => f.Hash == c.Hash))) + if ((TryCalculateModdedDictionary(out moddedPaths)).All(c => _apiController.ForbiddenTransfers.Any(f => string.Equals(f.Hash, c.Hash, StringComparison.Ordinal)))) { break; } @@ -195,7 +195,7 @@ public class CachedPlayer private List TryCalculateModdedDictionary(out Dictionary moddedDictionary) { List missingFiles = new(); - moddedDictionary = new Dictionary(); + moddedDictionary = new Dictionary(StringComparer.Ordinal); try { foreach (var item in _cachedData.FileReplacements.SelectMany(k => k.Value.Where(v => string.IsNullOrEmpty(v.FileSwapPath))).ToList()) @@ -454,7 +454,7 @@ public class CachedPlayer private void IpcManagerOnPenumbraRedrawEvent(IntPtr address, int idx) { var player = _dalamudUtil.GetCharacterFromObjectTableByIndex(idx); - if (player == null || player.Name.ToString() != PlayerName) return; + if (player == null || !string.Equals(player.Name.ToString(), PlayerName, StringComparison.OrdinalIgnoreCase)) return; if (!_penumbraRedrawEventTask?.IsCompleted ?? false) return; _penumbraRedrawEventTask = Task.Run(() => diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index e7c5882..cdd351c 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -158,7 +158,7 @@ public class IpcManager : IDisposable { try { - return _heelsGetApiVersion.InvokeFunc() == "1.0.1"; + return string.Equals(_heelsGetApiVersion.InvokeFunc(), "1.0.1", StringComparison.Ordinal); } catch { diff --git a/MareSynchronos/Managers/OnlinePlayerManager.cs b/MareSynchronos/Managers/OnlinePlayerManager.cs index efbda2b..20a683c 100644 --- a/MareSynchronos/Managers/OnlinePlayerManager.cs +++ b/MareSynchronos/Managers/OnlinePlayerManager.cs @@ -19,8 +19,8 @@ public class OnlinePlayerManager : IDisposable private readonly IpcManager _ipcManager; private readonly PlayerManager _playerManager; private readonly FileCacheManager _fileDbManager; - private readonly ConcurrentDictionary _onlineCachedPlayers = new(); - private readonly ConcurrentDictionary _temporaryStoredCharacterCache = new(); + private readonly ConcurrentDictionary _onlineCachedPlayers = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary _temporaryStoredCharacterCache = new(StringComparer.Ordinal); private readonly ConcurrentDictionary _playerTokenDisposal = new(); private List OnlineVisiblePlayerHashes => _onlineCachedPlayers.Select(p => p.Value).Where(p => p.PlayerCharacter != IntPtr.Zero) @@ -226,7 +226,7 @@ public class OnlinePlayerManager : IDisposable Task.Run(async () => { await _apiController.PushCharacterData(_playerManager.LastCreatedCharacterData, - visiblePlayers); + visiblePlayers).ConfigureAwait(false); }); } } diff --git a/MareSynchronos/Managers/PlayerManager.cs b/MareSynchronos/Managers/PlayerManager.cs index 21e2879..accfd0c 100644 --- a/MareSynchronos/Managers/PlayerManager.cs +++ b/MareSynchronos/Managers/PlayerManager.cs @@ -34,7 +34,7 @@ public class PlayerManager : IDisposable private CancellationTokenSource? _playerChangedCts = new(); private CancellationTokenSource _transientUpdateCts = new(); - private List playerRelatedObjects = new List(); + private List playerRelatedObjects = new(); public unsafe PlayerManager(ApiController apiController, IpcManager ipcManager, CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil, TransientResourceManager transientResourceManager, @@ -88,7 +88,7 @@ public class PlayerManager : IDisposable Task.Run(async () => { Logger.Debug("Delaying transient resource load update"); - await Task.Delay(750, token); + await Task.Delay(750, token).ConfigureAwait(false); if (obj.HasUnprocessedUpdate || token.IsCancellationRequested) return; Logger.Debug("Firing transient resource load update"); obj.HasTransientsUpdate = true; @@ -169,7 +169,7 @@ public class PlayerManager : IDisposable while (!PermanentDataCache.IsReady && !token.IsCancellationRequested) { Logger.Verbose("Waiting until cache is ready"); - await Task.Delay(50, token); + await Task.Delay(50, token).ConfigureAwait(false); } if (token.IsCancellationRequested) return null; @@ -215,7 +215,7 @@ public class PlayerManager : IDisposable var token = _playerChangedCts.Token; // fix for redraw from anamnesis - while ((!_dalamudUtil.IsPlayerPresent || _dalamudUtil.PlayerName == "--") && !token.IsCancellationRequested) + while ((!_dalamudUtil.IsPlayerPresent || string.Equals(_dalamudUtil.PlayerName, "--", StringComparison.Ordinal)) && !token.IsCancellationRequested) { Logger.Debug("Waiting Until Player is Present"); Thread.Sleep(100); @@ -244,7 +244,7 @@ public class PlayerManager : IDisposable _dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, 10000, token); } - cacheDto = (await CreateFullCharacterCacheDto(token)); + cacheDto = (await CreateFullCharacterCacheDto(token).ConfigureAwait(false)); } catch { } finally diff --git a/MareSynchronos/Managers/TransientResourceManager.cs b/MareSynchronos/Managers/TransientResourceManager.cs index 660741a..97d02be 100644 --- a/MareSynchronos/Managers/TransientResourceManager.cs +++ b/MareSynchronos/Managers/TransientResourceManager.cs @@ -82,7 +82,7 @@ public class TransientResourceManager : IDisposable private void Manager_PenumbraResourceLoadEvent(IntPtr gameObject, string gamePath, string filePath) { - if (!FileTypesToHandle.Any(type => gamePath.ToLowerInvariant().EndsWith(type))) + if (!FileTypesToHandle.Any(type => gamePath.EndsWith(type, StringComparison.OrdinalIgnoreCase))) { return; } @@ -93,25 +93,25 @@ public class TransientResourceManager : IDisposable if (!TransientResources.ContainsKey(gameObject)) { - TransientResources[gameObject] = new(); + TransientResources[gameObject] = new(StringComparer.OrdinalIgnoreCase); } - if (filePath.StartsWith("|")) + if (filePath.StartsWith("|", StringComparison.OrdinalIgnoreCase)) { filePath = filePath.Split("|")[2]; } - filePath = filePath.ToLowerInvariant().Replace("\\", "/"); + filePath = filePath.ToLowerInvariant().Replace("\\", "/", StringComparison.OrdinalIgnoreCase); - var replacedGamePath = gamePath.ToLowerInvariant().Replace("\\", "/"); + var replacedGamePath = gamePath.ToLowerInvariant().Replace("\\", "/", StringComparison.OrdinalIgnoreCase); if (TransientResources[gameObject].Contains(replacedGamePath) || - SemiTransientResources.Any(r => r.Value.Any(f => f.GamePaths.First().ToLowerInvariant() == replacedGamePath - && f.ResolvedPath.ToLowerInvariant() == filePath))) + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath , StringComparison.OrdinalIgnoreCase) + && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase)))) { Logger.Debug("Not adding " + replacedGamePath + ":" + filePath); - Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) && string.Equals(f.ResolvedPath.ToLowerInvariant(), filePath, StringComparison.OrdinalIgnoreCase))).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath)); - && f.ResolvedPath.ToLowerInvariant() == filePath)).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath)); + Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) + && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase))).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath)); } else { @@ -125,7 +125,7 @@ public class TransientResourceManager : IDisposable { if (TransientResources.ContainsKey(gameObject)) { - TransientResources[gameObject].RemoveWhere(f => fileReplacement.GamePaths.Any(g => g.ToLowerInvariant() == f.ToLowerInvariant())); + TransientResources[gameObject].RemoveWhere(f => fileReplacement.GamePaths.Any(g => string.Equals(g, f, StringComparison.OrdinalIgnoreCase))); } } @@ -145,11 +145,11 @@ public class TransientResourceManager : IDisposable Logger.Debug("Persisting " + transientResources.Count + " transient resources"); foreach (var gamePath in transientResources) { - var existingResource = SemiTransientResources[objectKind].Any(f => f.GamePaths.First().ToLowerInvariant() == gamePath.ToLowerInvariant()); + var existingResource = SemiTransientResources[objectKind].Any(f => string.Equals(f.GamePaths.First(), gamePath, StringComparison.OrdinalIgnoreCase)); if (existingResource) { Logger.Debug("Semi Transient resource replaced: " + gamePath); - SemiTransientResources[objectKind].RemoveWhere(f => f.GamePaths.First().ToLowerInvariant() == gamePath.ToLowerInvariant()); + SemiTransientResources[objectKind].RemoveWhere(f => string.Equals(f.GamePaths.First(), gamePath, StringComparison.OrdinalIgnoreCase)); } try @@ -196,7 +196,7 @@ public class TransientResourceManager : IDisposable SemiTransientResources[objectKind] = new HashSet(); } - if (!SemiTransientResources[objectKind].Any(f => f.ResolvedPath.ToLowerInvariant() == item.ResolvedPath.ToLowerInvariant())) + if (!SemiTransientResources[objectKind].Any(f => string.Equals(f.ResolvedPath, item.ResolvedPath, StringComparison.OrdinalIgnoreCase))) { SemiTransientResources[objectKind].Add(item); } diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 4a8610c..0cb2bd2 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -28,6 +28,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -86,4 +90,8 @@ + + + + diff --git a/MareSynchronos/Models/CharacterData.cs b/MareSynchronos/Models/CharacterData.cs index b0edfc4..0724ef8 100644 --- a/MareSynchronos/Models/CharacterData.cs +++ b/MareSynchronos/Models/CharacterData.cs @@ -31,10 +31,10 @@ public class CharacterData if (!FileReplacements.ContainsKey(objectKind)) FileReplacements.Add(objectKind, new List()); - var existingReplacement = FileReplacements[objectKind].SingleOrDefault(f => f.ResolvedPath == fileReplacement.ResolvedPath); + var existingReplacement = FileReplacements[objectKind].SingleOrDefault(f => string.Equals(f.ResolvedPath, fileReplacement.ResolvedPath, System.StringComparison.OrdinalIgnoreCase)); if (existingReplacement != null) { - existingReplacement.GamePaths.AddRange(fileReplacement.GamePaths.Where(e => !existingReplacement.GamePaths.Contains(e))); + existingReplacement.GamePaths.AddRange(fileReplacement.GamePaths.Where(e => !existingReplacement.GamePaths.Contains(e, System.StringComparer.OrdinalIgnoreCase))); } else { @@ -44,11 +44,11 @@ public class CharacterData public CharacterCacheDto ToCharacterCacheDto() { - var fileReplacements = FileReplacements.ToDictionary(k => k.Key, k => k.Value.Where(f => f.HasFileReplacement && !f.IsFileSwap).GroupBy(f => f.Hash).Select(g => + var fileReplacements = FileReplacements.ToDictionary(k => k.Key, k => k.Value.Where(f => f.HasFileReplacement && !f.IsFileSwap).GroupBy(f => f.Hash, System.StringComparer.OrdinalIgnoreCase).Select(g => { return new FileReplacementDto() { - GamePaths = g.SelectMany(f => f.GamePaths).Distinct().ToArray(), + GamePaths = g.SelectMany(f => f.GamePaths).Distinct(System.StringComparer.OrdinalIgnoreCase).ToArray(), Hash = g.First().Hash, }; }).ToList()); diff --git a/MareSynchronos/Models/FileReplacement.cs b/MareSynchronos/Models/FileReplacement.cs index a231afa..238bdc1 100644 --- a/MareSynchronos/Models/FileReplacement.cs +++ b/MareSynchronos/Models/FileReplacement.cs @@ -21,9 +21,9 @@ public class FileReplacement public List GamePaths { get; set; } = new(); - public bool HasFileReplacement => GamePaths.Count >= 1 && GamePaths.Any(p => p != ResolvedPath); + public bool HasFileReplacement => GamePaths.Count >= 1 && GamePaths.Any(p => !string.Equals(p, ResolvedPath, System.StringComparison.Ordinal)); - public bool IsFileSwap => !Regex.IsMatch(ResolvedPath, @"^[a-zA-Z]:(/|\\)", RegexOptions.ECMAScript) && GamePaths.First() != ResolvedPath; + public bool IsFileSwap => !Regex.IsMatch(ResolvedPath, @"^[a-zA-Z]:(/|\\)", RegexOptions.ECMAScript) && !string.Equals(GamePaths.First(), ResolvedPath, System.StringComparison.Ordinal); public string Hash { get; set; } = string.Empty; diff --git a/MareSynchronos/Models/PlayerRelatedObject.cs b/MareSynchronos/Models/PlayerRelatedObject.cs index d425891..50ad1b8 100644 --- a/MareSynchronos/Models/PlayerRelatedObject.cs +++ b/MareSynchronos/Models/PlayerRelatedObject.cs @@ -61,7 +61,7 @@ public class PlayerRelatedObject bool equip = CompareAndUpdateByteData(chara->EquipSlotData, chara->CustomizeData); bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress; var name = new Utf8String(chara->GameObject.Name).ToString(); - bool nameChange = (name != _name); + bool nameChange = (!string.Equals(name, _name, StringComparison.Ordinal)); if (addr || equip || drawObj || nameChange) { _name = name; diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 5918753..c9aa278 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -175,7 +175,7 @@ public sealed class Plugin : IDalamudPlugin { while (!_dalamudUtil.IsPlayerPresent) { - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); } try diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index 7a02838..6cc3eb9 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Numerics; using System.Reflection; @@ -20,7 +21,7 @@ public class CompactUi : Window, IDisposable { private readonly ApiController _apiController; private readonly Configuration _configuration; - public readonly Dictionary ShowUidForEntry = new(); + public readonly Dictionary ShowUidForEntry = new(StringComparer.Ordinal); private readonly UiShared _uiShared; private readonly WindowSystem _windowSystem; private string _characterOrCommentFilter = string.Empty; @@ -162,7 +163,7 @@ public class CompactUi : Window, IDisposable ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X); if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) { - if (_apiController.PairedClients.All(w => w.OtherUID != _pairToAdd)) + if (_apiController.PairedClients.All(w => !string.Equals(w.OtherUID, _pairToAdd, StringComparison.Ordinal))) { _ = _apiController.SendPairedClientAddition(_pairToAdd); _pairToAdd = string.Empty; @@ -316,7 +317,7 @@ public class CompactUi : Window, IDisposable } ImGui.SameLine(); - if (EditNickEntry != entry.OtherUID) + if (!string.Equals(EditNickEntry, entry.OtherUID, StringComparison.Ordinal)) { ImGui.SetCursorPosY(textPos); if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont); @@ -415,7 +416,7 @@ public class CompactUi : Window, IDisposable ImGui.EndChild(); } - + private IEnumerable GetFilteredUsers() { @@ -424,17 +425,23 @@ public class CompactUi : Window, IDisposable if (_characterOrCommentFilter.IsNullOrEmpty()) return true; _configuration.GetCurrentServerUidComments().TryGetValue(p.OtherUID, out var comment); var uid = p.VanityUID.IsNullOrEmpty() ? p.OtherUID : p.VanityUID; - return uid.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) || - (comment?.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) ?? false); + return uid.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) || + (comment?.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) ?? false); }); } private void DrawServerStatus() { var buttonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Link); - var userCount = _apiController.OnlineUsers.ToString(); + var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture); var userSize = ImGui.CalcTextSize(userCount); var textSize = ImGui.CalcTextSize("Users Online"); +#if DEBUG + string shardConnection = $"Connected shard: {_apiController.ServerInfo.ShardName}"; +#else + string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase) ? string.Empty : $"Connected shard: {_apiController.ServerInfo.ShardName}"; +#endif + var shardTextSize = ImGui.CalcTextSize(shardConnection); if (_apiController.ServerState is ServerState.Connected) { @@ -444,6 +451,11 @@ public class CompactUi : Window, IDisposable ImGui.SameLine(); ImGui.AlignTextToFramePadding(); ImGui.Text("Users Online"); + ImGui.AlignTextToFramePadding(); + if (!string.IsNullOrEmpty(shardConnection)) + { + ImGui.TextUnformatted(shardConnection); + } } else { diff --git a/MareSynchronos/UI/GroupPanel.cs b/MareSynchronos/UI/GroupPanel.cs index 0059ed9..cceb985 100644 --- a/MareSynchronos/UI/GroupPanel.cs +++ b/MareSynchronos/UI/GroupPanel.cs @@ -19,7 +19,7 @@ namespace MareSynchronos.UI private Configuration _configuration; private ApiController _apiController; - private readonly Dictionary _showGidForEntry = new(); + private readonly Dictionary _showGidForEntry = new(StringComparer.Ordinal); private string _editGroupEntry = string.Empty; private string _editGroupComment = string.Empty; private string _syncShellPassword = string.Empty; @@ -33,7 +33,7 @@ namespace MareSynchronos.UI private bool _errorGroupJoin; private bool _errorGroupCreate = false; private GroupCreatedDto? _lastCreatedGroup = null; - private Dictionary ExpandedGroupState = new Dictionary(); + private readonly Dictionary ExpandedGroupState = new(StringComparer.Ordinal); public GroupPanel(CompactUi mainUi, UiShared uiShared, Configuration configuration, ApiController apiController) { @@ -56,23 +56,35 @@ namespace MareSynchronos.UI ImGui.SetNextItemWidth(UiShared.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X); ImGui.InputTextWithHint("##syncshellid", "Syncshell GID/Alias", ref _syncShellToJoin, 20); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X); + + bool userCanJoinMoreGroups = _apiController.Groups.Count < _apiController.ServerInfo.MaxGroupsJoinedByUser; + bool userCanCreateMoreGroups = _apiController.Groups.Count(u => string.Equals(u.OwnedBy, _apiController.UID, StringComparison.Ordinal)) < _apiController.ServerInfo.MaxGroupsCreatedByUser; + if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) { - if (_apiController.Groups.All(w => w.GID != _syncShellToJoin) && !string.IsNullOrEmpty(_syncShellToJoin)) + if (_apiController.Groups.All(w => !string.Equals(w.GID, _syncShellToJoin, StringComparison.Ordinal)) && !string.IsNullOrEmpty(_syncShellToJoin)) { - _errorGroupJoin = false; - _showModalEnterPassword = true; - ImGui.OpenPopup("Enter Syncshell Password"); + if (userCanJoinMoreGroups) + { + _errorGroupJoin = false; + _showModalEnterPassword = true; + ImGui.OpenPopup("Enter Syncshell Password"); + } } else { - _lastCreatedGroup = null; - _errorGroupCreate = false; - _showModalCreateGroup = true; - ImGui.OpenPopup("Create Syncshell"); + if (userCanCreateMoreGroups) + { + _lastCreatedGroup = null; + _errorGroupCreate = false; + _showModalCreateGroup = true; + ImGui.OpenPopup("Create Syncshell"); + } } } - UiShared.AttachToolTip(_syncShellToJoin.IsNullOrEmpty() ? "Create Syncshell" : "Join Syncshell" + _syncShellToJoin); + UiShared.AttachToolTip(_syncShellToJoin.IsNullOrEmpty() + ? (userCanCreateMoreGroups ? "Create Syncshell" : $"You cannot create more than {_apiController.ServerInfo.MaxGroupsCreatedByUser} Syncshells") + : (userCanJoinMoreGroups ? "Join Syncshell" + _syncShellToJoin : $"You cannot join more than {_apiController.ServerInfo.MaxGroupsJoinedByUser} Syncshells")); if (ImGui.BeginPopupModal("Enter Syncshell Password", ref _showModalEnterPassword, ImGuiWindowFlags.AlwaysAutoResize)) { @@ -82,7 +94,8 @@ namespace MareSynchronos.UI ImGui.InputTextWithHint("##password", _syncShellToJoin + " Password", ref _syncShellPassword, 255, ImGuiInputTextFlags.Password); if (_errorGroupJoin) { - UiShared.ColorTextWrapped("An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells (6), it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full (100 users) or the Syncshell has closed invites.", + UiShared.ColorTextWrapped($"An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells ({_apiController.ServerInfo.MaxGroupsJoinedByUser}), " + + $"it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full ({_apiController.ServerInfo.MaxGroupUserCount} users) or the Syncshell has closed invites.", new Vector4(1, 0, 0, 1)); } if (ImGui.Button("Join " + _syncShellToJoin)) @@ -141,7 +154,6 @@ namespace MareSynchronos.UI ImGui.EndPopup(); } - ImGuiHelpers.ScaledDummy(2); } @@ -161,7 +173,7 @@ namespace MareSynchronos.UI private void DrawSyncshell(GroupDto group) { var name = group.Alias ?? group.GID; - var pairsInGroup = _apiController.GroupPairedClients.Where(p => p.GroupGID == group.GID).ToList(); + var pairsInGroup = _apiController.GroupPairedClients.Where(p => string.Equals(p.GroupGID, group.GID, StringComparison.Ordinal)).ToList(); if (!ExpandedGroupState.TryGetValue(group.GID, out bool isExpanded)) { isExpanded = false; @@ -188,7 +200,7 @@ namespace MareSynchronos.UI var groupName = group.Alias ?? group.GID; var textIsGid = true; - if (group.OwnedBy == _apiController.UID) + if (string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal)) { ImGui.PushFont(UiBuilder.IconFont); ImGui.Text(FontAwesomeIcon.Crown.ToIconString()); @@ -207,7 +219,7 @@ namespace MareSynchronos.UI } } - if (_editGroupEntry != group.GID) + if (!string.Equals(_editGroupEntry, group.GID, StringComparison.Ordinal)) { if (textIsGid) ImGui.PushFont(UiBuilder.MonoFont); ImGui.TextUnformatted(groupName); @@ -258,12 +270,12 @@ namespace MareSynchronos.UI ImGui.Indent(collapseButton.X); if (ExpandedGroupState[group.GID]) { - pairsInGroup = pairsInGroup.OrderBy(p => p.UserUID == group.OwnedBy ? 0 : 1).ThenBy(p => p.IsPinned ?? false).ThenBy(p => p.UserAlias ?? p.UserUID).ToList(); + pairsInGroup = pairsInGroup.OrderBy(p => string.Equals(p.UserUID, group.OwnedBy, StringComparison.Ordinal) ? 0 : 1).ThenBy(p => p.IsPinned ?? false).ThenBy(p => p.UserAlias ?? p.UserUID).ToList(); ImGui.Indent(ImGui.GetStyle().ItemSpacing.X / 2); ImGui.Separator(); foreach (var pair in pairsInGroup) { - UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, group.OwnedBy == _apiController.UID, group?.IsPaused ?? false)); + UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal), group?.IsPaused ?? false)); } ImGui.Separator(); @@ -299,7 +311,7 @@ namespace MareSynchronos.UI _ = _apiController.SendLeaveGroup(entry.GID); } } - UiShared.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (entry.OwnedBy != _apiController.UID ? string.Empty : Environment.NewLine + UiShared.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal) ? string.Empty : Environment.NewLine + "WARNING: This action is irreverisble" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); if (UiShared.IconTextButton(FontAwesomeIcon.Copy, "Copy ID")) @@ -308,7 +320,7 @@ namespace MareSynchronos.UI } UiShared.AttachToolTip("Copy Syncshell ID to Clipboard"); - if (entry.OwnedBy == _apiController.UID) + if (string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal)) { ImGui.Separator(); @@ -428,7 +440,7 @@ namespace MareSynchronos.UI } ImGui.SameLine(); - if (_mainUi.EditNickEntry != entry.UserUID) + if (!string.Equals(_mainUi.EditNickEntry, entry.UserUID, StringComparison.Ordinal)) { ImGui.SetCursorPosY(textPos); if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont); @@ -476,7 +488,7 @@ namespace MareSynchronos.UI UiShared.AttachToolTip("Hit ENTER to save\nRight click to cancel"); } - bool plusButtonShown = !_apiController.PairedClients.Any(p => p.OtherUID == entry.UserUID); + bool plusButtonShown = !_apiController.PairedClients.Any(p => string.Equals(p.OtherUID, entry.UserUID, StringComparison.Ordinal)); if (plusButtonShown) { diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 26239a3..3135309 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -37,12 +37,12 @@ internal class IntroUi : Window, IDisposable private Task _timeoutTask; private string _timeoutTime; - private Dictionary _languages = new() { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } }; + private Dictionary _languages = new(StringComparer.Ordinal) { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } }; private int _currentLanguage; - private bool DarkSoulsCaptchaValid => _darkSoulsCaptcha1.Item2 == _enteredDarkSoulsCaptcha1.Trim() - && _darkSoulsCaptcha2.Item2 == _enteredDarkSoulsCaptcha2.Trim() - && _darkSoulsCaptcha3.Item2 == _enteredDarkSoulsCaptcha3.Trim(); + private bool DarkSoulsCaptchaValid => string.Equals(_darkSoulsCaptcha1.Item2, _enteredDarkSoulsCaptcha1.Trim() +, StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha2.Item2, _enteredDarkSoulsCaptcha2.Trim() +, StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha3.Item2, _enteredDarkSoulsCaptcha3.Trim(), StringComparison.Ordinal); public void Dispose() @@ -158,7 +158,7 @@ internal class IntroUi : Window, IDisposable { _timeoutTime = $"{i}s " + Strings.ToS.RemainingLabel; Logger.Debug(_timeoutTime); - await Task.Delay(TimeSpan.FromSeconds(1)); + await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); } }); } @@ -286,11 +286,11 @@ internal class IntroUi : Window, IDisposable private Tuple GetCaptchaTuple() { - Random random = new Random(); + Random random = new(); var paragraphIdx = random.Next(TosParagraphs.Length); var splitParagraph = TosParagraphs[paragraphIdx].Split(".", StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim()).ToArray(); var sentenceIdx = random.Next(splitParagraph.Length); - var splitSentence = splitParagraph[sentenceIdx].Split(" ").Select(c => c.Trim()).Select(c => c.Replace(".", "").Replace(",", "").Replace("'", "")).ToArray(); + var splitSentence = splitParagraph[sentenceIdx].Split(" ").Select(c => c.Trim()).Select(c => c.Replace(".", "", StringComparison.Ordinal).Replace(",", "", StringComparison.Ordinal).Replace("'", "", StringComparison.Ordinal)).ToArray(); var wordIdx = random.Next(splitSentence.Length); return new($"{Strings.ToS.ParagraphLabel} {paragraphIdx + 1}, {Strings.ToS.SentenceLabel} {sentenceIdx + 1}, {Strings.ToS.WordLabel} {wordIdx + 1}", splitSentence[wordIdx]); } diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index bfbf45d..0d72429 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -335,7 +335,7 @@ public class SettingsUi : Window, IDisposable }); } ImGui.SameLine(); - if (onlineUser.UID != _apiController.UID && _apiController.IsAdmin) + if (!string.Equals(onlineUser.UID, _apiController.UID, StringComparison.Ordinal) && _apiController.IsAdmin) { if (!onlineUser.IsModerator) { diff --git a/MareSynchronos/UI/UIShared.cs b/MareSynchronos/UI/UIShared.cs index 2c556ca..3867c1f 100644 --- a/MareSynchronos/UI/UIShared.cs +++ b/MareSynchronos/UI/UIShared.cs @@ -294,7 +294,7 @@ public class UiShared : IDisposable bool isSelected = _serverSelectionIndex == i; if (ImGui.Selectable(comboEntries[i], isSelected)) { - _pluginConfiguration.ApiUri = _apiController.ServerDictionary.Single(k => k.Value == comboEntries[i]).Key; + _pluginConfiguration.ApiUri = _apiController.ServerDictionary.Single(k => string.Equals(k.Value, comboEntries[i], StringComparison.Ordinal)).Key; _pluginConfiguration.Save(); _ = _apiController.CreateConnections(); } @@ -451,7 +451,7 @@ public class UiShared : IDisposable { if (!success) return; - _isPenumbraDirectory = path.ToLowerInvariant() == _ipcManager.PenumbraModDirectory()?.ToLowerInvariant(); + _isPenumbraDirectory = string.Equals(path.ToLowerInvariant(), _ipcManager.PenumbraModDirectory()?.ToLowerInvariant(), StringComparison.Ordinal); _isDirectoryWritable = IsDirectoryWritable(path); _cacheDirectoryHasOtherFilesThanCache = Directory.GetFiles(path, "*", SearchOption.AllDirectories).Any(f => new FileInfo(f).Name.Length != 40); _cacheDirectoryIsValidPath = Regex.IsMatch(path, @"^(?:[a-zA-Z]:\\[\w\s\-\\]+?|\/(?:[\w\s\-\/])+?)$", RegexOptions.ECMAScript); diff --git a/MareSynchronos/Utils/Crypto.cs b/MareSynchronos/Utils/Crypto.cs index a4062c0..7a10b54 100644 --- a/MareSynchronos/Utils/Crypto.cs +++ b/MareSynchronos/Utils/Crypto.cs @@ -11,24 +11,24 @@ public class Crypto public static string GetFileHash(string filePath) { using SHA1CryptoServiceProvider cryptoProvider = new(); - return BitConverter.ToString(cryptoProvider.ComputeHash(File.ReadAllBytes(filePath))).Replace("-", ""); + return BitConverter.ToString(cryptoProvider.ComputeHash(File.ReadAllBytes(filePath))).Replace("-", "", StringComparison.Ordinal); } public static string GetHash(string stringToHash) { using SHA1CryptoServiceProvider cryptoProvider = new(); - return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", ""); + return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "", StringComparison.Ordinal); } public static string GetHash256(string stringToHash) { using SHA256CryptoServiceProvider cryptoProvider = new(); - return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", ""); + return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "", StringComparison.Ordinal); } public static string GetHash256(PlayerCharacter character) { using SHA256CryptoServiceProvider cryptoProvider = new(); - return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(character.Name + character.HomeWorld.Id.ToString()))).Replace("-", ""); + return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(character.Name + character.HomeWorld.Id.ToString()))).Replace("-", "", StringComparison.Ordinal); } } diff --git a/MareSynchronos/Utils/DalamudLoggingProvider.cs b/MareSynchronos/Utils/DalamudLoggingProvider.cs new file mode 100644 index 0000000..f4813f8 --- /dev/null +++ b/MareSynchronos/Utils/DalamudLoggingProvider.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; + +namespace MareSynchronos.Utils; + +[ProviderAlias("Dalamud")] +public class DalamudLoggingProvider : ILoggerProvider +{ + private readonly ConcurrentDictionary _loggers = + new(StringComparer.OrdinalIgnoreCase); + + public DalamudLoggingProvider() + { + } + + public ILogger CreateLogger(string categoryName) + { + return _loggers.GetOrAdd(categoryName, name => new Logger(categoryName)); + } + + public void Dispose() + { + _loggers.Clear(); + } +} diff --git a/MareSynchronos/Utils/DalamudUtil.cs b/MareSynchronos/Utils/DalamudUtil.cs index 4a9b979..fe23079 100644 --- a/MareSynchronos/Utils/DalamudUtil.cs +++ b/MareSynchronos/Utils/DalamudUtil.cs @@ -186,7 +186,7 @@ public class DalamudUtil : IDisposable { return _objectTable.Where(obj => obj.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player && - obj.Name.ToString() != PlayerName).Select(p => (PlayerCharacter)p).ToList(); + !string.Equals(obj.Name.ToString(), PlayerName, StringComparison.Ordinal)).Select(p => (PlayerCharacter)p).ToList(); } public Dalamud.Game.ClientState.Objects.Types.Character? GetCharacterFromObjectTableByIndex(int index) @@ -201,7 +201,7 @@ public class DalamudUtil : IDisposable foreach (var item in _objectTable) { if (item.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue; - if (item.Name.ToString() == characterName) return (PlayerCharacter)item; + if (string.Equals(item.Name.ToString(), characterName, StringComparison.Ordinal)) return (PlayerCharacter)item; } return null; @@ -209,7 +209,7 @@ public class DalamudUtil : IDisposable public async Task RunOnFrameworkThread(Func func) { - return await _framework.RunOnFrameworkThread(func); + return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false); } public unsafe void WaitWhileCharacterIsDrawing(string name, IntPtr characterAddress, int timeOut = 5000, CancellationToken? ct = null) diff --git a/MareSynchronos/Utils/Logger.cs b/MareSynchronos/Utils/Logger.cs index 4d90bac..f816a5f 100644 --- a/MareSynchronos/Utils/Logger.cs +++ b/MareSynchronos/Utils/Logger.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Diagnostics; using Dalamud.Logging; using Dalamud.Utility; @@ -7,27 +6,6 @@ using Microsoft.Extensions.Logging; namespace MareSynchronos.Utils; -[ProviderAlias("Dalamud")] -public class DalamudLoggingProvider : ILoggerProvider -{ - private readonly ConcurrentDictionary _loggers = - new(StringComparer.OrdinalIgnoreCase); - - public DalamudLoggingProvider() - { - } - - public ILogger CreateLogger(string categoryName) - { - return _loggers.GetOrAdd(categoryName, name => new Logger(categoryName)); - } - - public void Dispose() - { - _loggers.Clear(); - } -} - internal class Logger : ILogger { private readonly string name; @@ -41,7 +19,7 @@ internal class Logger : ILogger public static void Debug(string debug, string stringToHighlight = "") { var caller = new StackTrace().GetFrame(1)?.GetMethod()?.ReflectedType?.Name ?? "Unknown"; - if (debug.Contains(stringToHighlight) && !stringToHighlight.IsNullOrEmpty()) + if (debug.Contains(stringToHighlight, StringComparison.Ordinal) && !stringToHighlight.IsNullOrEmpty()) { PluginLog.Warning($"[{caller}] {debug}"); } diff --git a/MareSynchronos/Utils/Various.cs b/MareSynchronos/Utils/VariousExtensions.cs similarity index 96% rename from MareSynchronos/Utils/Various.cs rename to MareSynchronos/Utils/VariousExtensions.cs index 98fb104..32fa32b 100644 --- a/MareSynchronos/Utils/Various.cs +++ b/MareSynchronos/Utils/VariousExtensions.cs @@ -18,7 +18,7 @@ public static class VariousExtensions if (attribute?.InformationalVersion != null) { var value = attribute.InformationalVersion; - var index = value.IndexOf(BuildVersionMetadataPrefix); + var index = value.IndexOf(BuildVersionMetadataPrefix, StringComparison.Ordinal); if (index > 0) { value = value[(index + BuildVersionMetadataPrefix.Length)..]; diff --git a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs index cd6b637..89727b4 100644 --- a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs +++ b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs @@ -33,7 +33,7 @@ public partial class ApiController public async Task DeleteAllMyFiles() { - await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles); + await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false); } private async Task DownloadFile(int downloadId, string hash, Uri downloadUri, CancellationToken ct) @@ -44,7 +44,7 @@ public partial class ApiController { try { - CurrentDownloads[downloadId].Single(f => f.Hash == hash).Transferred = e.BytesReceived; + CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Transferred = e.BytesReceived; } catch (Exception ex) { @@ -61,11 +61,11 @@ public partial class ApiController try { - await wc.DownloadFileTaskAsync(downloadUri, fileName); + await wc.DownloadFileTaskAsync(downloadUri, fileName).ConfigureAwait(false); } catch { } - CurrentDownloads[downloadId].Single(f => f.Hash == hash).Transferred = CurrentDownloads[downloadId].Single(f => f.Hash == hash).Total; + CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Transferred = CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Total; wc.DownloadProgressChanged -= progChanged; return fileName; @@ -78,7 +78,7 @@ public partial class ApiController DownloadStarted?.Invoke(); try { - await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct); + await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct).ConfigureAwait(false); } catch { @@ -94,8 +94,8 @@ public partial class ApiController { Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")"); - List downloadFileInfoFromService = new List(); - downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct)); + List downloadFileInfoFromService = new(); + downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct).ConfigureAwait(false)); Logger.Debug("Files with size 0 or less: " + string.Join(", ", downloadFileInfoFromService.Where(f => f.Size <= 0).Select(f => f.Hash))); @@ -104,7 +104,7 @@ public partial class ApiController foreach (var dto in downloadFileInfoFromService.Where(c => c.IsForbidden)) { - if (ForbiddenTransfers.All(f => f.Hash != dto.Hash)) + if (ForbiddenTransfers.All(f => !string.Equals(f.Hash, dto.Hash, StringComparison.Ordinal))) { ForbiddenTransfers.Add(new DownloadFileTransfer(dto)); } @@ -118,7 +118,7 @@ public partial class ApiController async (file, token) => { var hash = file.Hash; - var tempFile = await DownloadFile(currentDownloadId, file.Hash, file.DownloadUri, token); + var tempFile = await DownloadFile(currentDownloadId, file.Hash, file.DownloadUri, token).ConfigureAwait(false); if (token.IsCancellationRequested) { File.Delete(tempFile); @@ -128,16 +128,16 @@ public partial class ApiController return; } - var tempFileData = await File.ReadAllBytesAsync(tempFile, token); + var tempFileData = await File.ReadAllBytesAsync(tempFile, token).ConfigureAwait(false); var extractedFile = LZ4Codec.Unwrap(tempFileData); File.Delete(tempFile); var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash); - await File.WriteAllBytesAsync(filePath, extractedFile, token); + await File.WriteAllBytesAsync(filePath, extractedFile, token).ConfigureAwait(false); var fi = new FileInfo(filePath); Func RandomDayFunc() { - DateTime start = new DateTime(1995, 1, 1); - Random gen = new Random(); + DateTime start = new(1995, 1, 1); + Random gen = new(); int range = (DateTime.Today - start).Days; return () => start.AddDays(gen.Next(range)); } @@ -155,7 +155,7 @@ public partial class ApiController Logger.Warn(ex.Message); Logger.Warn(ex.StackTrace); } - }); + }).ConfigureAwait(false); Logger.Debug("Download complete, removing " + currentDownloadId); CancelDownload(currentDownloadId); @@ -163,7 +163,7 @@ public partial class ApiController public async Task PushCharacterData(CharacterCacheDto character, List visibleCharacterIds) { - if (!IsConnected || SecretKey == "-") return; + if (!IsConnected || string.Equals(SecretKey, "-", StringComparison.Ordinal)) return; Logger.Debug("Sending Character data to service " + ApiUri); CancelUpload(); @@ -172,7 +172,7 @@ public partial class ApiController Logger.Verbose("New Token Created"); List unverifiedUploadHashes = new(); - foreach (var item in character.FileReplacements.SelectMany(c => c.Value.Where(f => string.IsNullOrEmpty(f.FileSwapPath)).Select(v => v.Hash).Distinct()).Distinct().ToList()) + foreach (var item in character.FileReplacements.SelectMany(c => c.Value.Where(f => string.IsNullOrEmpty(f.FileSwapPath)).Select(v => v.Hash).Distinct(StringComparer.Ordinal)).Distinct(StringComparer.Ordinal).ToList()) { if (!_verifiedUploadedHashes.Contains(item)) { @@ -183,7 +183,7 @@ public partial class ApiController if (unverifiedUploadHashes.Any()) { Logger.Debug("Verifying " + unverifiedUploadHashes.Count + " files"); - var filesToUpload = await _mareHub!.InvokeAsync>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken); + var filesToUpload = await _mareHub!.InvokeAsync>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken).ConfigureAwait(false); foreach (var file in filesToUpload.Where(f => !f.IsForbidden)) { @@ -203,7 +203,7 @@ public partial class ApiController foreach (var file in filesToUpload.Where(c => c.IsForbidden)) { - if (ForbiddenTransfers.All(f => f.Hash != file.Hash)) + if (ForbiddenTransfers.All(f => !string.Equals(f.Hash, file.Hash, StringComparison.Ordinal))) { ForbiddenTransfers.Add(new UploadFileTransfer(file) { @@ -217,9 +217,9 @@ public partial class ApiController foreach (var file in CurrentUploads.Where(f => f.CanBeTransferred && !f.IsTransferred).ToList()) { Logger.Debug("Compressing and uploading " + file); - var data = await GetCompressedFileData(file.Hash, uploadToken); - CurrentUploads.Single(e => e.Hash == data.Item1).Total = data.Item2.Length; - await UploadFile(data.Item2, file.Hash, uploadToken); + var data = await GetCompressedFileData(file.Hash, uploadToken).ConfigureAwait(false); + CurrentUploads.Single(e => string.Equals(e.Hash, data.Item1, StringComparison.Ordinal)).Total = data.Item2.Length; + await UploadFile(data.Item2, file.Hash, uploadToken).ConfigureAwait(false); if (!uploadToken.IsCancellationRequested) continue; Logger.Warn("Cancel in filesToUpload loop detected"); CurrentUploads.Clear(); @@ -233,12 +233,12 @@ public partial class ApiController } Logger.Debug("Upload tasks complete, waiting for server to confirm"); - var anyUploadsOpen = await _mareHub!.InvokeAsync(Api.InvokeFileIsUploadFinished, uploadToken); + var anyUploadsOpen = await _mareHub!.InvokeAsync(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false); Logger.Debug("Uploads open: " + anyUploadsOpen); while (anyUploadsOpen && !uploadToken.IsCancellationRequested) { - anyUploadsOpen = await _mareHub!.InvokeAsync(Api.InvokeFileIsUploadFinished, uploadToken); - await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken); + anyUploadsOpen = await _mareHub!.InvokeAsync(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken).ConfigureAwait(false); Logger.Debug("Waiting for uploads to finish"); } @@ -257,7 +257,7 @@ public partial class ApiController if (!uploadToken.IsCancellationRequested) { Logger.Info("Pushing character data for " + character.GetHashCode() + " to " + string.Join(", ", visibleCharacterIds)); - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new(); foreach (var item in character.FileReplacements) { sb.AppendLine($"FileReplacements for {item.Key}: {item.Value.Count}"); @@ -267,7 +267,7 @@ public partial class ApiController sb.AppendLine($"GlamourerData for {item.Key}: {!string.IsNullOrEmpty(item.Value)}"); } Logger.Debug("Chara data contained: " + Environment.NewLine + sb.ToString()); - await _mareHub!.InvokeAsync(Api.InvokeUserPushCharacterDataToVisibleClients, character, visibleCharacterIds, uploadToken); + await _mareHub!.InvokeAsync(Api.InvokeUserPushCharacterDataToVisibleClients, character, visibleCharacterIds, uploadToken).ConfigureAwait(false); } else { @@ -281,7 +281,7 @@ public partial class ApiController private async Task<(string, byte[])> GetCompressedFileData(string fileHash, CancellationToken uploadToken) { var fileCache = _fileDbManager.GetFileCacheByHash(fileHash)!.ResolvedFilepath; - return (fileHash, LZ4Codec.WrapHC(await File.ReadAllBytesAsync(fileCache, uploadToken), 0, + return (fileHash, LZ4Codec.WrapHC(await File.ReadAllBytesAsync(fileCache, uploadToken).ConfigureAwait(false), 0, (int)new FileInfo(fileCache).Length)); } @@ -295,15 +295,15 @@ public partial class ApiController using var ms = new MemoryStream(compressedFile); var buffer = new byte[chunkSize]; int bytesRead; - while ((bytesRead = await ms.ReadAsync(buffer, 0, chunkSize, token)) > 0 && !token.IsCancellationRequested) + while ((bytesRead = await ms.ReadAsync(buffer, 0, chunkSize, token).ConfigureAwait(false)) > 0 && !token.IsCancellationRequested) { - CurrentUploads.Single(f => f.Hash == fileHash).Transferred += bytesRead; + CurrentUploads.Single(f => string.Equals(f.Hash, fileHash, StringComparison.Ordinal)).Transferred += bytesRead; token.ThrowIfCancellationRequested(); yield return bytesRead == chunkSize ? buffer.ToArray() : buffer.Take(bytesRead).ToArray(); } } - await _mareHub!.SendAsync(Api.SendFileUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken); + await _mareHub!.SendAsync(Api.SendFileUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken).ConfigureAwait(false); } public void CancelDownload(int downloadId) diff --git a/MareSynchronos/WebAPI/ApIController.Functions.Users.cs b/MareSynchronos/WebAPI/ApIController.Functions.Users.cs index 1e0223a..1b69cce 100644 --- a/MareSynchronos/WebAPI/ApIController.Functions.Users.cs +++ b/MareSynchronos/WebAPI/ApIController.Functions.Users.cs @@ -11,32 +11,32 @@ public partial class ApiController { _pluginConfiguration.ClientSecret.Remove(ApiUri); _pluginConfiguration.Save(); - await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles); - await _mareHub!.SendAsync(Api.SendUserDeleteAccount); - await CreateConnections(); + await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false); + await _mareHub!.SendAsync(Api.SendUserDeleteAccount).ConfigureAwait(false); + await CreateConnections().ConfigureAwait(false); } public async Task> GetOnlineCharacters() { - return await _mareHub!.InvokeAsync>(Api.InvokeUserGetOnlineCharacters); + return await _mareHub!.InvokeAsync>(Api.InvokeUserGetOnlineCharacters).ConfigureAwait(false); } public async Task SendPairedClientAddition(string uid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid).ConfigureAwait(false); } public async Task SendPairedClientPauseChange(string uid, bool paused) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused).ConfigureAwait(false); } public async Task SendPairedClientRemoval(string uid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid).ConfigureAwait(false); } } diff --git a/MareSynchronos/WebAPI/ApiController.Functions.Admin.cs b/MareSynchronos/WebAPI/ApiController.Functions.Admin.cs index c301460..c19df84 100644 --- a/MareSynchronos/WebAPI/ApiController.Functions.Admin.cs +++ b/MareSynchronos/WebAPI/ApiController.Functions.Admin.cs @@ -10,27 +10,27 @@ public partial class ApiController { public async Task AddOrUpdateForbiddenFileEntry(ForbiddenFileDto forbiddenFile) { - await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddForbiddenFile, forbiddenFile); + await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddForbiddenFile, forbiddenFile).ConfigureAwait(false); } public async Task DeleteForbiddenFileEntry(ForbiddenFileDto forbiddenFile) { - await _mareHub!.SendAsync(Api.SendAdminDeleteForbiddenFile, forbiddenFile); + await _mareHub!.SendAsync(Api.SendAdminDeleteForbiddenFile, forbiddenFile).ConfigureAwait(false); } public async Task AddOrUpdateBannedUserEntry(BannedUserDto bannedUser) { - await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddBannedUser, bannedUser); + await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddBannedUser, bannedUser).ConfigureAwait(false); } public async Task DeleteBannedUserEntry(BannedUserDto bannedUser) { - await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser); + await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser).ConfigureAwait(false); } public async Task RefreshOnlineUsers() { - AdminOnlineUsers = await _mareHub!.InvokeAsync>(Api.InvokeAdminGetOnlineUsers); + AdminOnlineUsers = await _mareHub!.InvokeAsync>(Api.InvokeAdminGetOnlineUsers).ConfigureAwait(false); } public List AdminOnlineUsers { get; set; } = new List(); diff --git a/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs b/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs index 851e888..04a8da9 100644 --- a/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs +++ b/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs @@ -17,10 +17,10 @@ public partial class ApiController private void UpdateLocalClientPairsCallback(ClientPairDto dto) { - var entry = PairedClients.SingleOrDefault(e => e.OtherUID == dto.OtherUID); + var entry = PairedClients.SingleOrDefault(e => string.Equals(e.OtherUID, dto.OtherUID, System.StringComparison.Ordinal)); if (dto.IsRemoved) { - PairedClients.RemoveAll(p => p.OtherUID == dto.OtherUID); + PairedClients.RemoveAll(p => string.Equals(p.OtherUID, dto.OtherUID, System.StringComparison.Ordinal)); return; } if (entry == null) @@ -43,7 +43,7 @@ public partial class ApiController private void UpdateOrAddBannedUserCallback(BannedUserDto obj) { - var user = AdminBannedUsers.SingleOrDefault(b => b.CharacterHash == obj.CharacterHash); + var user = AdminBannedUsers.SingleOrDefault(b => string.Equals(b.CharacterHash, obj.CharacterHash, System.StringComparison.Ordinal)); if (user == null) { AdminBannedUsers.Add(obj); @@ -56,12 +56,12 @@ public partial class ApiController private void DeleteBannedUserCallback(BannedUserDto obj) { - AdminBannedUsers.RemoveAll(a => a.CharacterHash == obj.CharacterHash); + AdminBannedUsers.RemoveAll(a => string.Equals(a.CharacterHash, obj.CharacterHash, System.StringComparison.Ordinal)); } private void UpdateOrAddForbiddenFileCallback(ForbiddenFileDto obj) { - var user = AdminForbiddenFiles.SingleOrDefault(b => b.Hash == obj.Hash); + var user = AdminForbiddenFiles.SingleOrDefault(b => string.Equals(b.Hash, obj.Hash, System.StringComparison.Ordinal)); if (user == null) { AdminForbiddenFiles.Add(obj); @@ -74,18 +74,18 @@ public partial class ApiController private void DeleteForbiddenFileCallback(ForbiddenFileDto obj) { - AdminForbiddenFiles.RemoveAll(f => f.Hash == obj.Hash); + AdminForbiddenFiles.RemoveAll(f => string.Equals(f.Hash, obj.Hash, System.StringComparison.Ordinal)); } private void GroupPairChangedCallback(GroupPairDto dto) { if (dto.IsRemoved.GetValueOrDefault(false)) { - GroupPairedClients.RemoveAll(g => g.GroupGID == dto.GroupGID && g.UserUID == dto.UserUID); + GroupPairedClients.RemoveAll(g => string.Equals(g.GroupGID, dto.GroupGID, System.StringComparison.Ordinal) && string.Equals(g.UserUID, dto.UserUID, System.StringComparison.Ordinal)); return; } - var existingUser = GroupPairedClients.FirstOrDefault(f => f.GroupGID == dto.GroupGID && f.UserUID == dto.UserUID); + var existingUser = GroupPairedClients.FirstOrDefault(f => string.Equals(f.GroupGID, dto.GroupGID, System.StringComparison.Ordinal) && string.Equals(f.UserUID, dto.UserUID, System.StringComparison.Ordinal)); if (existingUser == null) { GroupPairedClients.Add(dto); @@ -101,16 +101,16 @@ public partial class ApiController { if (dto.IsDeleted.GetValueOrDefault(false)) { - Groups.RemoveAll(g => g.GID == dto.GID); - GroupPairedClients.RemoveAll(g => g.GroupGID == dto.GID); + Groups.RemoveAll(g => string.Equals(g.GID, dto.GID, System.StringComparison.Ordinal)); + GroupPairedClients.RemoveAll(g => string.Equals(g.GroupGID, dto.GID, System.StringComparison.Ordinal)); return; } - var existingGroup = Groups.FirstOrDefault(g => g.GID == dto.GID); + var existingGroup = Groups.FirstOrDefault(g => string.Equals(g.GID, dto.GID, System.StringComparison.Ordinal)); if (existingGroup == null) { Groups.Add(dto); - GroupPairedClients.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGroupGetUsersInGroup, dto.GID)); + GroupPairedClients.AddRange(await _mareHub!.InvokeAsync>(Api.InvokeGroupGetUsersInGroup, dto.GID).ConfigureAwait(false)); return; } diff --git a/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs b/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs index 40b3f07..0ba2e71 100644 --- a/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs +++ b/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs @@ -9,79 +9,79 @@ public partial class ApiController { public async Task CreateGroup() { - if (!IsConnected || SecretKey == "-") return new GroupCreatedDto(); - return await _mareHub!.InvokeAsync(Api.InvokeGroupCreate); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new GroupCreatedDto(); + return await _mareHub!.InvokeAsync(Api.InvokeGroupCreate).ConfigureAwait(false); } public async Task ChangeGroupPassword(string gid, string newpassword) { - if (!IsConnected || SecretKey == "-") return false; - return await _mareHub!.InvokeAsync(Api.InvokeGroupChangePassword, gid, newpassword); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false; + return await _mareHub!.InvokeAsync(Api.InvokeGroupChangePassword, gid, newpassword).ConfigureAwait(false); } public async Task> GetGroups() { - if (!IsConnected || SecretKey == "-") return new List(); - return await _mareHub!.InvokeAsync>(Api.InvokeGroupGetGroups); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List(); + return await _mareHub!.InvokeAsync>(Api.InvokeGroupGetGroups).ConfigureAwait(false); } public async Task> GetUsersInGroup(string gid) { - if (!IsConnected || SecretKey == "-") return new List(); - return await _mareHub!.InvokeAsync>(Api.InvokeGroupGetUsersInGroup, gid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List(); + return await _mareHub!.InvokeAsync>(Api.InvokeGroupGetUsersInGroup, gid).ConfigureAwait(false); } public async Task SendGroupJoin(string gid, string password) { - if (!IsConnected || SecretKey == "-") return false; - return await _mareHub!.InvokeAsync(Api.InvokeGroupJoin, gid, password); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false; + return await _mareHub!.InvokeAsync(Api.InvokeGroupJoin, gid, password).ConfigureAwait(false); } public async Task SendGroupChangeInviteState(string gid, bool opened) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened).ConfigureAwait(false); } public async Task SendDeleteGroup(string gid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupDelete, gid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupDelete, gid).ConfigureAwait(false); } public async Task SendChangeUserPinned(string gid, string uid, bool isPinned) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned).ConfigureAwait(false); } public async Task SendClearGroup(string gid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupClear, gid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupClear, gid).ConfigureAwait(false); } public async Task SendLeaveGroup(string gid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupLeave, gid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupLeave, gid).ConfigureAwait(false); } public async Task SendPauseGroup(string gid, bool isPaused) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused).ConfigureAwait(false); } public async Task SendRemoveUserFromGroup(string gid, string uid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid).ConfigureAwait(false); } public async Task ChangeOwnerOfGroup(string gid, string uid) { - if (!IsConnected || SecretKey == "-") return; - await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid); + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid).ConfigureAwait(false); } } \ No newline at end of file diff --git a/MareSynchronos/WebAPI/ApiController.cs b/MareSynchronos/WebAPI/ApiController.cs index ac508cc..14c3bfc 100644 --- a/MareSynchronos/WebAPI/ApiController.cs +++ b/MareSynchronos/WebAPI/ApiController.cs @@ -33,8 +33,11 @@ public partial class ApiController : IDisposable private HubConnection? _mareHub; private CancellationTokenSource? _uploadCancellationTokenSource = new(); + private CancellationTokenSource? _healthCheckTokenSource = new(); private ConnectionDto? _connectionDto; + public ServerInfoDto ServerInfo => _connectionDto?.ServerInfo ?? new ServerInfoDto(); + public SystemInfoDto SystemInfoDto { get; private set; } = new(); public bool IsModerator => (_connectionDto?.IsAdmin ?? false) || (_connectionDto?.IsModerator ?? false); @@ -51,7 +54,7 @@ public partial class ApiController : IDisposable _dalamudUtil.LogIn += DalamudUtilOnLogIn; _dalamudUtil.LogOut += DalamudUtilOnLogOut; ServerState = ServerState.Offline; - _verifiedUploadedHashes = new(); + _verifiedUploadedHashes = new(StringComparer.Ordinal); if (_dalamudUtil.IsLoggedIn) { @@ -61,7 +64,7 @@ public partial class ApiController : IDisposable private void DalamudUtilOnLogOut() { - Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token)); + Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false)); ServerState = ServerState.Offline; } @@ -108,10 +111,10 @@ public partial class ApiController : IDisposable public bool ServerAlive => ServerState is ServerState.Connected or ServerState.RateLimited or ServerState.Unauthorized or ServerState.Disconnected; - public Dictionary ServerDictionary => new Dictionary() + public Dictionary ServerDictionary => new Dictionary(StringComparer.Ordinal) { { MainServiceUri, MainServer } } .Concat(_pluginConfiguration.CustomServerList) - .ToDictionary(k => k.Key, k => k.Value); + .ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal); public string UID => _connectionDto?.UID ?? string.Empty; public string DisplayName => _connectionDto?.UID ?? string.Empty; @@ -138,11 +141,11 @@ public partial class ApiController : IDisposable Logger.Info("Not recreating Connection, paused"); ServerState = ServerState.Disconnected; _connectionDto = null; - await StopConnection(_connectionCancellationTokenSource.Token); + await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false); return; } - await StopConnection(_connectionCancellationTokenSource.Token); + await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false); Logger.Info("Recreating Connection"); @@ -154,11 +157,11 @@ public partial class ApiController : IDisposable { if (string.IsNullOrEmpty(SecretKey)) { - await Task.Delay(TimeSpan.FromSeconds(2)); + await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false); continue; } - await StopConnection(token); + await StopConnection(token).ConfigureAwait(false); try { @@ -167,32 +170,32 @@ public partial class ApiController : IDisposable while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested) { Logger.Debug("Player not loaded in yet, waiting"); - await Task.Delay(TimeSpan.FromSeconds(1), token); + await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); } if (token.IsCancellationRequested) break; _mareHub = BuildHubConnection(Api.Path); - await _mareHub.StartAsync(token); + await _mareHub.StartAsync(token).ConfigureAwait(false); _mareHub.On(Api.OnUpdateSystemInfo, (dto) => SystemInfoDto = dto); _connectionDto = - await _mareHub.InvokeAsync(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token); + await _mareHub.InvokeAsync(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token).ConfigureAwait(false); ServerState = ServerState.Connected; if (_connectionDto.ServerVersion != Api.Version) { ServerState = ServerState.VersionMisMatch; - await StopConnection(token); + await StopConnection(token).ConfigureAwait(false); return; } if (ServerState is ServerState.Connected) // user is authorized && server is legit { - await InitializeData(token); + await InitializeData(token).ConfigureAwait(false); _mareHub.Closed += MareHubOnClosed; _mareHub.Reconnecting += MareHubOnReconnecting; @@ -206,7 +209,7 @@ public partial class ApiController : IDisposable Logger.Warn(ex.StackTrace ?? string.Empty); ServerState = ServerState.RateLimited; - await StopConnection(token); + await StopConnection(token).ConfigureAwait(false); return; } catch (HttpRequestException ex) @@ -218,14 +221,14 @@ public partial class ApiController : IDisposable if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) { ServerState = ServerState.Unauthorized; - await StopConnection(token); + await StopConnection(token).ConfigureAwait(false); return; } else { ServerState = ServerState.Offline; Logger.Info("Failed to establish connection, retrying"); - await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token); + await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token).ConfigureAwait(false); } } catch (Exception ex) @@ -234,7 +237,7 @@ public partial class ApiController : IDisposable Logger.Warn(ex.Message); Logger.Warn(ex.StackTrace ?? string.Empty); Logger.Info("Failed to establish connection, retrying"); - await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token); + await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token).ConfigureAwait(false); } } } @@ -245,6 +248,21 @@ public partial class ApiController : IDisposable return Task.CompletedTask; } + private async Task ClientHealthCheck(CancellationToken ct) + { + while (!ct.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false); + if (ct.IsCancellationRequested) break; + var needsRestart = await _mareHub!.InvokeAsync(Api.InvokeCheckClientHealth, ct).ConfigureAwait(false); + Logger.Debug("Checked Client Health State, healthy: " + !needsRestart); + if (needsRestart) + { + _ = CreateConnections(); + } + } + } + private async Task InitializeData(CancellationToken token) { if (_mareHub == null) return; @@ -263,22 +281,22 @@ public partial class ApiController : IDisposable _mareHub.On(Api.OnGroupUserChange, GroupPairChangedCallback); PairedClients = - await _mareHub!.InvokeAsync>(Api.InvokeUserGetPairedClients, token); - Groups = await GetGroups(); + await _mareHub!.InvokeAsync>(Api.InvokeUserGetPairedClients, token).ConfigureAwait(false); + Groups = await GetGroups().ConfigureAwait(false); GroupPairedClients.Clear(); foreach (var group in Groups) { - GroupPairedClients.AddRange(await GetUsersInGroup(group.GID)); + GroupPairedClients.AddRange(await GetUsersInGroup(group.GID).ConfigureAwait(false)); } if (IsModerator) { AdminForbiddenFiles = await _mareHub.InvokeAsync>(Api.InvokeAdminGetForbiddenFiles, - token); + token).ConfigureAwait(false); AdminBannedUsers = await _mareHub.InvokeAsync>(Api.InvokeAdminGetBannedUsers, - token); + token).ConfigureAwait(false); _mareHub.On(Api.OnAdminUpdateOrAddBannedUser, UpdateOrAddBannedUserCallback); _mareHub.On(Api.OnAdminDeleteBannedUser, DeleteBannedUserCallback); @@ -288,6 +306,11 @@ public partial class ApiController : IDisposable DeleteForbiddenFileCallback); } + _healthCheckTokenSource?.Cancel(); + _healthCheckTokenSource?.Dispose(); + _healthCheckTokenSource = new CancellationTokenSource(); + _ = ClientHealthCheck(_healthCheckTokenSource.Token); + Connected?.Invoke(); } @@ -298,7 +321,7 @@ public partial class ApiController : IDisposable _dalamudUtil.LogIn -= DalamudUtilOnLogIn; _dalamudUtil.LogOut -= DalamudUtilOnLogOut; - Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token)); + Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false)); _connectionCancellationTokenSource?.Cancel(); } @@ -332,6 +355,7 @@ public partial class ApiController : IDisposable private Task MareHubOnReconnecting(Exception? arg) { + _healthCheckTokenSource?.Cancel(); ServerState = ServerState.Disconnected; Logger.Warn("Connection closed... Reconnecting"); Logger.Warn(arg?.Message ?? string.Empty); @@ -350,8 +374,8 @@ public partial class ApiController : IDisposable _mareHub.Closed -= MareHubOnClosed; _mareHub.Reconnecting -= MareHubOnReconnecting; _mareHub.Reconnected -= MareHubOnReconnected; - await _mareHub.StopAsync(token); - await _mareHub.DisposeAsync(); + await _mareHub.StopAsync(token).ConfigureAwait(false); + await _mareHub.DisposeAsync().ConfigureAwait(false); CurrentUploads.Clear(); CurrentDownloads.Clear(); _uploadCancellationTokenSource?.Cancel(); @@ -363,7 +387,7 @@ public partial class ApiController : IDisposable { while (ServerState != ServerState.Offline) { - await Task.Delay(16); + await Task.Delay(16).ConfigureAwait(false); } } }