add analyzers and api

This commit is contained in:
Stanley Dimant
2022-10-03 15:58:51 +02:00
parent 3b9b260ab3
commit 260c4a48ee
34 changed files with 435 additions and 265 deletions

102
.editorconfig Normal file
View File

@@ -0,0 +1,102 @@
[*.cs]
# MA0046: Use EventHandler<T> 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

Submodule MareAPI updated: a2a4d07c04...2d5d9d9d1c

View File

@@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "MareA
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{89DD407C-B2B7-4BB3-BF26-C550BA1841F8}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{89DD407C-B2B7-4BB3-BF26-C550BA1841F8}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{585B740D-BA2C-429B-9CF3-B2D223423748}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@@ -23,21 +23,21 @@ public static class ConfigurationExtensions
{ {
return configuration.UidServerComments.ContainsKey(configuration.ApiUri) return configuration.UidServerComments.ContainsKey(configuration.ApiUri)
? configuration.UidServerComments[configuration.ApiUri] ? configuration.UidServerComments[configuration.ApiUri]
: new Dictionary<string, string>(); : new Dictionary<string, string>(StringComparer.Ordinal);
} }
public static Dictionary<string, string> GetCurrentServerGidComments(this Configuration configuration) public static Dictionary<string, string> GetCurrentServerGidComments(this Configuration configuration)
{ {
return configuration.GidServerComments.ContainsKey(configuration.ApiUri) return configuration.GidServerComments.ContainsKey(configuration.ApiUri)
? configuration.GidServerComments[configuration.ApiUri] ? configuration.GidServerComments[configuration.ApiUri]
: new Dictionary<string, string>(); : new Dictionary<string, string>(StringComparer.Ordinal);
} }
public static void SetCurrentServerGidComment(this Configuration configuration, string gid, string comment) public static void SetCurrentServerGidComment(this Configuration configuration, string gid, string comment)
{ {
if (!configuration.GidServerComments.ContainsKey(configuration.ApiUri)) if (!configuration.GidServerComments.ContainsKey(configuration.ApiUri))
{ {
configuration.GidServerComments[configuration.ApiUri] = new Dictionary<string, string>(); configuration.GidServerComments[configuration.ApiUri] = new Dictionary<string, string>(StringComparer.Ordinal);
} }
configuration.GidServerComments[configuration.ApiUri][gid] = comment; configuration.GidServerComments[configuration.ApiUri][gid] = comment;
@@ -47,7 +47,7 @@ public static class ConfigurationExtensions
{ {
if (!configuration.UidServerComments.ContainsKey(configuration.ApiUri)) if (!configuration.UidServerComments.ContainsKey(configuration.ApiUri))
{ {
configuration.UidServerComments[configuration.ApiUri] = new Dictionary<string, string>(); configuration.UidServerComments[configuration.ApiUri] = new Dictionary<string, string>(StringComparer.Ordinal);
} }
configuration.UidServerComments[configuration.ApiUri][uid] = comment; configuration.UidServerComments[configuration.ApiUri][uid] = comment;
@@ -71,8 +71,8 @@ public class Configuration : IPluginConfiguration
} }
public string CacheFolder { get; set; } = string.Empty; public string CacheFolder { get; set; } = string.Empty;
public Dictionary<string, string> ClientSecret { get; set; } = new(); public Dictionary<string, string> ClientSecret { get; set; } = new(StringComparer.Ordinal);
public Dictionary<string, string> CustomServerList { get; set; } = new(); public Dictionary<string, string> CustomServerList { get; set; } = new(StringComparer.Ordinal);
public int MaxLocalCacheInGiB { get; set; } = 20; public int MaxLocalCacheInGiB { get; set; } = 20;
public bool ReverseUserSort { get; set; } = false; public bool ReverseUserSort { get; set; } = false;
@@ -82,10 +82,10 @@ public class Configuration : IPluginConfiguration
public bool InitialScanComplete { get; set; } = false; public bool InitialScanComplete { get; set; } = false;
public bool FullPause { get; set; } = false; public bool FullPause { get; set; } = false;
public Dictionary<string, Dictionary<string, string>> UidServerComments { get; set; } = new(); public Dictionary<string, Dictionary<string, string>> UidServerComments { get; set; } = new(StringComparer.Ordinal);
public Dictionary<string, Dictionary<string, string>> GidServerComments { get; set; } = new(); public Dictionary<string, Dictionary<string, string>> GidServerComments { get; set; } = new(StringComparer.Ordinal);
public Dictionary<string, string> UidComments { get; set; } = new(); public Dictionary<string, string> UidComments { get; set; } = new(StringComparer.Ordinal);
public int Version { get; set; } = 5; public int Version { get; set; } = 5;
public bool ShowTransferWindow { get; set; } = true; public bool ShowTransferWindow { get; set; } = true;
@@ -114,10 +114,10 @@ public class Configuration : IPluginConfiguration
{ {
Logger.Debug("Migrating Configuration from V0 to V1"); Logger.Debug("Migrating Configuration from V0 to V1");
Version = 1; Version = 1;
ApiUri = ApiUri.Replace("https", "wss"); ApiUri = ApiUri.Replace("https", "wss", StringComparison.Ordinal);
foreach (var kvp in ClientSecret.ToList()) 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); ClientSecret.Remove(kvp.Key);
if (ClientSecret.ContainsKey(newKey)) if (ClientSecret.ContainsKey(newKey))
{ {
@@ -128,7 +128,7 @@ public class Configuration : IPluginConfiguration
ClientSecret.Add(newKey, kvp.Value); 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(); UidComments.Clear();
Save(); Save();
} }
@@ -136,10 +136,10 @@ public class Configuration : IPluginConfiguration
if (Version == 1) if (Version == 1)
{ {
Logger.Debug("Migrating Configuration from V1 to V2"); 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()) 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); ClientSecret.Remove(kvp.Key);
if (ClientSecret.ContainsKey(newKey)) if (ClientSecret.ContainsKey(newKey))
{ {
@@ -153,7 +153,7 @@ public class Configuration : IPluginConfiguration
foreach (var kvp in UidServerComments.ToList()) 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.Remove(kvp.Key);
UidServerComments.Add(newKey, kvp.Value); UidServerComments.Add(newKey, kvp.Value);
} }
@@ -177,10 +177,10 @@ public class Configuration : IPluginConfiguration
{ {
Logger.Debug("Migrating Configuration from V3 to V4"); 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()) 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); ClientSecret.Remove(kvp.Key);
if (ClientSecret.ContainsKey(newKey)) if (ClientSecret.ContainsKey(newKey))
{ {
@@ -194,7 +194,7 @@ public class Configuration : IPluginConfiguration
foreach (var kvp in UidServerComments.ToList()) 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.Remove(kvp.Key);
UidServerComments.Add(newKey, kvp.Value); UidServerComments.Add(newKey, kvp.Value);
} }
@@ -207,7 +207,7 @@ public class Configuration : IPluginConfiguration
{ {
Logger.Debug("Migrating Configuration from V4 to V5"); 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"); ClientSecret.Remove("wss://v2202207178628194299.powersrv.de:6872");
UidServerComments.Remove("wss://v2202207178628194299.powersrv.de:6872"); UidServerComments.Remove("wss://v2202207178628194299.powersrv.de:6872");

View File

@@ -158,7 +158,7 @@ public class CharacterDataFactory
if (cache.FileReplacements.ContainsKey(objectKind)) 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; return;
} }
@@ -196,7 +196,7 @@ public class CharacterDataFactory
if (cache.FileReplacements.ContainsKey(objectKind)) 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; return;
} }
@@ -214,7 +214,7 @@ public class CharacterDataFactory
if (cache.FileReplacements.ContainsKey(objectKind)) 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; return;
} }
@@ -225,7 +225,7 @@ public class CharacterDataFactory
cache.AddFileReplacement(objectKind, texFileReplacement); cache.AddFileReplacement(objectKind, texFileReplacement);
if (texPath.Contains("/--")) return; if (texPath.Contains("/--", StringComparison.Ordinal)) return;
var texDx11Replacement = var texDx11Replacement =
CreateFileReplacement(texPath.Insert(texPath.LastIndexOf('/') + 1, "--"), doNotReverseResolve); CreateFileReplacement(texPath.Insert(texPath.LastIndexOf('/') + 1, "--"), doNotReverseResolve);
@@ -322,11 +322,11 @@ public class CharacterDataFactory
previousData.FileReplacements.Add(objectKind, new()); 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 penumResolve = _ipcManager.PenumbraResolvePath(item.GamePaths.First()).ToLowerInvariant();
var gamePath = 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); Logger.Debug("PenumResolve was same as GamePath, not adding " + item);
transientResourceManager.RemoveTransientResource(charaPointer, item); transientResourceManager.RemoveTransientResource(charaPointer, item);

View File

@@ -22,7 +22,7 @@ public class FileCache
public void SetResolvedFilePath(string filePath) 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)}"; public string CsvEntry => $"{Hash}{FileCacheManager.CsvSplit}{PrefixedFilePath}{FileCacheManager.CsvSplit}{LastModifiedDateTicks.ToString(CultureInfo.InvariantCulture)}";

View File

@@ -26,9 +26,9 @@ public class FileCacheManager : IDisposable
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly string CsvPath; private readonly string CsvPath;
private string CsvBakPath => CsvPath + ".bak"; private string CsvBakPath => CsvPath + ".bak";
private readonly ConcurrentDictionary<string, FileCache> FileCaches = new(); private readonly ConcurrentDictionary<string, FileCache> FileCaches = new(StringComparer.Ordinal);
public const string CsvSplit = "|"; public const string CsvSplit = "|";
private object _fileWriteLock = new object(); private object _fileWriteLock = new();
public FileCacheManager(IpcManager ipcManager, Configuration configuration, string configDirectoryName) public FileCacheManager(IpcManager ipcManager, Configuration configuration, string configDirectoryName)
{ {
@@ -64,7 +64,7 @@ public class FileCacheManager : IDisposable
public void WriteOutFullCsv() public void WriteOutFullCsv()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
foreach (var entry in FileCaches.OrderBy(f => f.Value.PrefixedFilePath)) foreach (var entry in FileCaches.OrderBy(f => f.Value.PrefixedFilePath))
{ {
sb.AppendLine(entry.Value.CsvEntry); sb.AppendLine(entry.Value.CsvEntry);
@@ -91,9 +91,9 @@ public class FileCacheManager : IDisposable
public FileCache? GetFileCacheByHash(string hash) 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; return null;
@@ -107,7 +107,7 @@ public class FileCacheManager : IDisposable
{ {
return (FileState.RequireDeletion, fileCache); 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); return (FileState.RequireUpdate, fileCache);
} }
@@ -117,8 +117,8 @@ public class FileCacheManager : IDisposable
public FileCache? GetFileCacheByPath(string path) public FileCache? GetFileCacheByPath(string path)
{ {
var cleanedPath = path.Replace("/", "\\").ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), ""); var cleanedPath = path.Replace("/", "\\", StringComparison.Ordinal).ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), "", StringComparison.Ordinal);
var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath)).Value; var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath, StringComparison.Ordinal)).Value;
if (entry == null) if (entry == null)
{ {
@@ -137,9 +137,9 @@ public class FileCacheManager : IDisposable
FileInfo fi = new(path); FileInfo fi = new(path);
if (!fi.Exists) return null; if (!fi.Exists) return null;
var fullName = fi.FullName.ToLowerInvariant(); var fullName = fi.FullName.ToLowerInvariant();
if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant())) return null; if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant(), StringComparison.Ordinal)) return null;
string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\").Replace("\\\\", "\\"); string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal);
return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper()); return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper(CultureInfo.InvariantCulture));
} }
public FileCache? CreateFileEntry(string path) public FileCache? CreateFileEntry(string path)
@@ -148,8 +148,8 @@ public class FileCacheManager : IDisposable
FileInfo fi = new(path); FileInfo fi = new(path);
if (!fi.Exists) return null; if (!fi.Exists) return null;
var fullName = fi.FullName.ToLowerInvariant(); var fullName = fi.FullName.ToLowerInvariant();
if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant())) return null; if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), StringComparison.Ordinal)) return null;
string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\").Replace("\\\\", "\\"); string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal);
return CreateFileCacheEntity(fi, prefixedPath); return CreateFileCacheEntity(fi, prefixedPath);
} }
@@ -187,7 +187,7 @@ public class FileCacheManager : IDisposable
return null; return null;
} }
if (file.LastWriteTimeUtc.Ticks.ToString() != fileCache.LastModifiedDateTicks) if (!string.Equals(file.LastWriteTimeUtc.Ticks.ToString(), fileCache.LastModifiedDateTicks, StringComparison.Ordinal))
{ {
UpdateHash(fileCache); UpdateHash(fileCache);
} }
@@ -211,13 +211,13 @@ public class FileCacheManager : IDisposable
private FileCache ReplacePathPrefixes(FileCache fileCache) 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; return fileCache;

View File

@@ -20,7 +20,7 @@ public class PeriodicFileScanner : IDisposable
private readonly DalamudUtil _dalamudUtil; private readonly DalamudUtil _dalamudUtil;
private CancellationTokenSource? _scanCancellationTokenSource; private CancellationTokenSource? _scanCancellationTokenSource;
private Task? _fileScannerTask = null; private Task? _fileScannerTask = null;
public ConcurrentDictionary<string, int> haltScanLocks = new(); public ConcurrentDictionary<string, int> haltScanLocks = new(StringComparer.Ordinal);
public PeriodicFileScanner(IpcManager ipcManager, Configuration pluginConfiguration, FileCacheManager fileDbManager, ApiController apiController, DalamudUtil dalamudUtil) public PeriodicFileScanner(IpcManager ipcManager, Configuration pluginConfiguration, FileCacheManager fileDbManager, ApiController apiController, DalamudUtil dalamudUtil)
{ {
Logger.Verbose("Creating " + nameof(PeriodicFileScanner)); Logger.Verbose("Creating " + nameof(PeriodicFileScanner));
@@ -128,7 +128,7 @@ public class PeriodicFileScanner : IDisposable
{ {
while (haltScanLocks.Any(f => f.Value > 0)) while (haltScanLocks.Any(f => f.Value > 0))
{ {
await Task.Delay(TimeSpan.FromSeconds(1)); await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
} }
isForced |= RecalculateFileCacheSize(); isForced |= RecalculateFileCacheSize();
@@ -144,7 +144,7 @@ public class PeriodicFileScanner : IDisposable
_timeUntilNextScan = TimeSpan.FromSeconds(timeBetweenScans); _timeUntilNextScan = TimeSpan.FromSeconds(timeBetweenScans);
while (_timeUntilNextScan.TotalSeconds >= 0) while (_timeUntilNextScan.TotalSeconds >= 0)
{ {
await Task.Delay(TimeSpan.FromSeconds(1), token); await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
_timeUntilNextScan -= TimeSpan.FromSeconds(1); _timeUntilNextScan -= TimeSpan.FromSeconds(1);
} }
} }
@@ -206,11 +206,14 @@ public class PeriodicFileScanner : IDisposable
var scannedFiles = new ConcurrentDictionary<string, bool>(Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories) var scannedFiles = new ConcurrentDictionary<string, bool>(Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories)
.Select(s => s.ToLowerInvariant()) .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) .Concat(Directory.EnumerateFiles(_pluginConfiguration.CacheFolder, "*.*", SearchOption.TopDirectoryOnly)
.Where(f => new FileInfo(f).Name.Length == 40) .Where(f => new FileInfo(f).Name.Length == 40)
.Select(s => s.ToLowerInvariant()).ToList()) .Select(s => s.ToLowerInvariant()).ToList())
.Select(c => new KeyValuePair<string, bool>(c, false))); .Select(c => new KeyValuePair<string, bool>(c, false)), StringComparer.OrdinalIgnoreCase);
TotalFiles = scannedFiles.Count; TotalFiles = scannedFiles.Count;

View File

@@ -71,7 +71,7 @@ public class CachedPlayer
if (characterData.GetHashCode() == _cachedData.GetHashCode()) return; if (characterData.GetHashCode() == _cachedData.GetHashCode()) return;
bool updateModdedPaths = false; bool updateModdedPaths = false;
List<ObjectKind> charaDataToUpdate = new List<ObjectKind>(); List<ObjectKind> charaDataToUpdate = new();
foreach (var objectKind in Enum.GetValues<ObjectKind>()) foreach (var objectKind in Enum.GetValues<ObjectKind>())
{ {
_cachedData.FileReplacements.TryGetValue(objectKind, out var existingFileReplacements); _cachedData.FileReplacements.TryGetValue(objectKind, out var existingFileReplacements);
@@ -108,7 +108,7 @@ public class CachedPlayer
if (hasNewAndOldGlamourerData) if (hasNewAndOldGlamourerData)
{ {
bool glamourerDataDifferent = _cachedData.GlamourerData[objectKind] != characterData.GlamourerData[objectKind]; bool glamourerDataDifferent = !string.Equals(_cachedData.GlamourerData[objectKind], characterData.GlamourerData[objectKind], StringComparison.Ordinal);
if (glamourerDataDifferent) if (glamourerDataDifferent)
{ {
Logger.Debug("Updating " + objectKind); Logger.Debug("Updating " + objectKind);
@@ -159,7 +159,7 @@ public class CachedPlayer
Logger.Debug("Downloading missing files for player " + PlayerName + ", kind: " + objectKind); Logger.Debug("Downloading missing files for player " + PlayerName + ", kind: " + objectKind);
if (toDownloadReplacements.Any()) if (toDownloadReplacements.Any())
{ {
await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken); await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken).ConfigureAwait(false);
_apiController.CancelDownload(downloadId); _apiController.CancelDownload(downloadId);
} }
if (downloadToken.IsCancellationRequested) if (downloadToken.IsCancellationRequested)
@@ -168,7 +168,7 @@ public class CachedPlayer
return; 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; break;
} }
@@ -195,7 +195,7 @@ public class CachedPlayer
private List<FileReplacementDto> TryCalculateModdedDictionary(out Dictionary<string, string> moddedDictionary) private List<FileReplacementDto> TryCalculateModdedDictionary(out Dictionary<string, string> moddedDictionary)
{ {
List<FileReplacementDto> missingFiles = new(); List<FileReplacementDto> missingFiles = new();
moddedDictionary = new Dictionary<string, string>(); moddedDictionary = new Dictionary<string, string>(StringComparer.Ordinal);
try try
{ {
foreach (var item in _cachedData.FileReplacements.SelectMany(k => k.Value.Where(v => string.IsNullOrEmpty(v.FileSwapPath))).ToList()) 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) private void IpcManagerOnPenumbraRedrawEvent(IntPtr address, int idx)
{ {
var player = _dalamudUtil.GetCharacterFromObjectTableByIndex(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; if (!_penumbraRedrawEventTask?.IsCompleted ?? false) return;
_penumbraRedrawEventTask = Task.Run(() => _penumbraRedrawEventTask = Task.Run(() =>

View File

@@ -158,7 +158,7 @@ public class IpcManager : IDisposable
{ {
try try
{ {
return _heelsGetApiVersion.InvokeFunc() == "1.0.1"; return string.Equals(_heelsGetApiVersion.InvokeFunc(), "1.0.1", StringComparison.Ordinal);
} }
catch catch
{ {

View File

@@ -19,8 +19,8 @@ public class OnlinePlayerManager : IDisposable
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly PlayerManager _playerManager; private readonly PlayerManager _playerManager;
private readonly FileCacheManager _fileDbManager; private readonly FileCacheManager _fileDbManager;
private readonly ConcurrentDictionary<string, CachedPlayer> _onlineCachedPlayers = new(); private readonly ConcurrentDictionary<string, CachedPlayer> _onlineCachedPlayers = new(StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, CharacterCacheDto> _temporaryStoredCharacterCache = new(); private readonly ConcurrentDictionary<string, CharacterCacheDto> _temporaryStoredCharacterCache = new(StringComparer.Ordinal);
private readonly ConcurrentDictionary<CachedPlayer, CancellationTokenSource> _playerTokenDisposal = new(); private readonly ConcurrentDictionary<CachedPlayer, CancellationTokenSource> _playerTokenDisposal = new();
private List<string> OnlineVisiblePlayerHashes => _onlineCachedPlayers.Select(p => p.Value).Where(p => p.PlayerCharacter != IntPtr.Zero) private List<string> OnlineVisiblePlayerHashes => _onlineCachedPlayers.Select(p => p.Value).Where(p => p.PlayerCharacter != IntPtr.Zero)
@@ -226,7 +226,7 @@ public class OnlinePlayerManager : IDisposable
Task.Run(async () => Task.Run(async () =>
{ {
await _apiController.PushCharacterData(_playerManager.LastCreatedCharacterData, await _apiController.PushCharacterData(_playerManager.LastCreatedCharacterData,
visiblePlayers); visiblePlayers).ConfigureAwait(false);
}); });
} }
} }

View File

@@ -34,7 +34,7 @@ public class PlayerManager : IDisposable
private CancellationTokenSource? _playerChangedCts = new(); private CancellationTokenSource? _playerChangedCts = new();
private CancellationTokenSource _transientUpdateCts = new(); private CancellationTokenSource _transientUpdateCts = new();
private List<PlayerRelatedObject> playerRelatedObjects = new List<PlayerRelatedObject>(); private List<PlayerRelatedObject> playerRelatedObjects = new();
public unsafe PlayerManager(ApiController apiController, IpcManager ipcManager, public unsafe PlayerManager(ApiController apiController, IpcManager ipcManager,
CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil, TransientResourceManager transientResourceManager, CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil, TransientResourceManager transientResourceManager,
@@ -88,7 +88,7 @@ public class PlayerManager : IDisposable
Task.Run(async () => Task.Run(async () =>
{ {
Logger.Debug("Delaying transient resource load update"); 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; if (obj.HasUnprocessedUpdate || token.IsCancellationRequested) return;
Logger.Debug("Firing transient resource load update"); Logger.Debug("Firing transient resource load update");
obj.HasTransientsUpdate = true; obj.HasTransientsUpdate = true;
@@ -169,7 +169,7 @@ public class PlayerManager : IDisposable
while (!PermanentDataCache.IsReady && !token.IsCancellationRequested) while (!PermanentDataCache.IsReady && !token.IsCancellationRequested)
{ {
Logger.Verbose("Waiting until cache is ready"); Logger.Verbose("Waiting until cache is ready");
await Task.Delay(50, token); await Task.Delay(50, token).ConfigureAwait(false);
} }
if (token.IsCancellationRequested) return null; if (token.IsCancellationRequested) return null;
@@ -215,7 +215,7 @@ public class PlayerManager : IDisposable
var token = _playerChangedCts.Token; var token = _playerChangedCts.Token;
// fix for redraw from anamnesis // 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"); Logger.Debug("Waiting Until Player is Present");
Thread.Sleep(100); Thread.Sleep(100);
@@ -244,7 +244,7 @@ public class PlayerManager : IDisposable
_dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, 10000, token); _dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, 10000, token);
} }
cacheDto = (await CreateFullCharacterCacheDto(token)); cacheDto = (await CreateFullCharacterCacheDto(token).ConfigureAwait(false));
} }
catch { } catch { }
finally finally

View File

@@ -82,7 +82,7 @@ public class TransientResourceManager : IDisposable
private void Manager_PenumbraResourceLoadEvent(IntPtr gameObject, string gamePath, string filePath) 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; return;
} }
@@ -93,25 +93,25 @@ public class TransientResourceManager : IDisposable
if (!TransientResources.ContainsKey(gameObject)) 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.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) || if (TransientResources[gameObject].Contains(replacedGamePath) ||
SemiTransientResources.Any(r => r.Value.Any(f => f.GamePaths.First().ToLowerInvariant() == replacedGamePath SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath , StringComparison.OrdinalIgnoreCase)
&& f.ResolvedPath.ToLowerInvariant() == filePath))) && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase))))
{ {
Logger.Debug("Not adding " + replacedGamePath + ":" + filePath); 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)); Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase)
&& f.ResolvedPath.ToLowerInvariant() == filePath)).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath)); && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase))).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath));
} }
else else
{ {
@@ -125,7 +125,7 @@ public class TransientResourceManager : IDisposable
{ {
if (TransientResources.ContainsKey(gameObject)) 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"); Logger.Debug("Persisting " + transientResources.Count + " transient resources");
foreach (var gamePath in transientResources) 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) if (existingResource)
{ {
Logger.Debug("Semi Transient resource replaced: " + gamePath); 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 try
@@ -196,7 +196,7 @@ public class TransientResourceManager : IDisposable
SemiTransientResources[objectKind] = new HashSet<FileReplacement>(); SemiTransientResources[objectKind] = new HashSet<FileReplacement>();
} }
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); SemiTransientResources[objectKind].Add(item);
} }

View File

@@ -28,6 +28,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.8" /> <PackageReference Include="DalamudPackager" Version="2.1.8" />
<PackageReference Include="lz4net" Version="1.0.15.93" /> <PackageReference Include="lz4net" Version="1.0.15.93" />
<PackageReference Include="Meziantou.Analyzer" Version="1.0.733">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.8" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.8" />
</ItemGroup> </ItemGroup>
@@ -86,4 +90,8 @@
<EmbeddedResource Include="Localization\fr.json" /> <EmbeddedResource Include="Localization\fr.json" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
</Project> </Project>

View File

@@ -31,10 +31,10 @@ public class CharacterData
if (!FileReplacements.ContainsKey(objectKind)) FileReplacements.Add(objectKind, new List<FileReplacement>()); if (!FileReplacements.ContainsKey(objectKind)) FileReplacements.Add(objectKind, new List<FileReplacement>());
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) 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 else
{ {
@@ -44,11 +44,11 @@ public class CharacterData
public CharacterCacheDto ToCharacterCacheDto() 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() 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, Hash = g.First().Hash,
}; };
}).ToList()); }).ToList());

View File

@@ -21,9 +21,9 @@ public class FileReplacement
public List<string> GamePaths { get; set; } = new(); public List<string> 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; public string Hash { get; set; } = string.Empty;

View File

@@ -61,7 +61,7 @@ public class PlayerRelatedObject
bool equip = CompareAndUpdateByteData(chara->EquipSlotData, chara->CustomizeData); bool equip = CompareAndUpdateByteData(chara->EquipSlotData, chara->CustomizeData);
bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress; bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress;
var name = new Utf8String(chara->GameObject.Name).ToString(); 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) if (addr || equip || drawObj || nameChange)
{ {
_name = name; _name = name;

View File

@@ -175,7 +175,7 @@ public sealed class Plugin : IDalamudPlugin
{ {
while (!_dalamudUtil.IsPlayerPresent) while (!_dalamudUtil.IsPlayerPresent)
{ {
await Task.Delay(100); await Task.Delay(100).ConfigureAwait(false);
} }
try try

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Reflection; using System.Reflection;
@@ -20,7 +21,7 @@ public class CompactUi : Window, IDisposable
{ {
private readonly ApiController _apiController; private readonly ApiController _apiController;
private readonly Configuration _configuration; private readonly Configuration _configuration;
public readonly Dictionary<string, bool> ShowUidForEntry = new(); public readonly Dictionary<string, bool> ShowUidForEntry = new(StringComparer.Ordinal);
private readonly UiShared _uiShared; private readonly UiShared _uiShared;
private readonly WindowSystem _windowSystem; private readonly WindowSystem _windowSystem;
private string _characterOrCommentFilter = string.Empty; private string _characterOrCommentFilter = string.Empty;
@@ -162,7 +163,7 @@ public class CompactUi : Window, IDisposable
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) 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); _ = _apiController.SendPairedClientAddition(_pairToAdd);
_pairToAdd = string.Empty; _pairToAdd = string.Empty;
@@ -316,7 +317,7 @@ public class CompactUi : Window, IDisposable
} }
ImGui.SameLine(); ImGui.SameLine();
if (EditNickEntry != entry.OtherUID) if (!string.Equals(EditNickEntry, entry.OtherUID, StringComparison.Ordinal))
{ {
ImGui.SetCursorPosY(textPos); ImGui.SetCursorPosY(textPos);
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont); if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
@@ -415,7 +416,7 @@ public class CompactUi : Window, IDisposable
ImGui.EndChild(); ImGui.EndChild();
} }
private IEnumerable<ClientPairDto> GetFilteredUsers() private IEnumerable<ClientPairDto> GetFilteredUsers()
{ {
@@ -424,17 +425,23 @@ public class CompactUi : Window, IDisposable
if (_characterOrCommentFilter.IsNullOrEmpty()) return true; if (_characterOrCommentFilter.IsNullOrEmpty()) return true;
_configuration.GetCurrentServerUidComments().TryGetValue(p.OtherUID, out var comment); _configuration.GetCurrentServerUidComments().TryGetValue(p.OtherUID, out var comment);
var uid = p.VanityUID.IsNullOrEmpty() ? p.OtherUID : p.VanityUID; var uid = p.VanityUID.IsNullOrEmpty() ? p.OtherUID : p.VanityUID;
return uid.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) || return uid.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) ||
(comment?.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) ?? false); (comment?.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) ?? false);
}); });
} }
private void DrawServerStatus() private void DrawServerStatus()
{ {
var buttonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Link); var buttonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Link);
var userCount = _apiController.OnlineUsers.ToString(); var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
var userSize = ImGui.CalcTextSize(userCount); var userSize = ImGui.CalcTextSize(userCount);
var textSize = ImGui.CalcTextSize("Users Online"); 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) if (_apiController.ServerState is ServerState.Connected)
{ {
@@ -444,6 +451,11 @@ public class CompactUi : Window, IDisposable
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.Text("Users Online"); ImGui.Text("Users Online");
ImGui.AlignTextToFramePadding();
if (!string.IsNullOrEmpty(shardConnection))
{
ImGui.TextUnformatted(shardConnection);
}
} }
else else
{ {

View File

@@ -19,7 +19,7 @@ namespace MareSynchronos.UI
private Configuration _configuration; private Configuration _configuration;
private ApiController _apiController; private ApiController _apiController;
private readonly Dictionary<string, bool> _showGidForEntry = new(); private readonly Dictionary<string, bool> _showGidForEntry = new(StringComparer.Ordinal);
private string _editGroupEntry = string.Empty; private string _editGroupEntry = string.Empty;
private string _editGroupComment = string.Empty; private string _editGroupComment = string.Empty;
private string _syncShellPassword = string.Empty; private string _syncShellPassword = string.Empty;
@@ -33,7 +33,7 @@ namespace MareSynchronos.UI
private bool _errorGroupJoin; private bool _errorGroupJoin;
private bool _errorGroupCreate = false; private bool _errorGroupCreate = false;
private GroupCreatedDto? _lastCreatedGroup = null; private GroupCreatedDto? _lastCreatedGroup = null;
private Dictionary<string, bool> ExpandedGroupState = new Dictionary<string, bool>(); private readonly Dictionary<string, bool> ExpandedGroupState = new(StringComparer.Ordinal);
public GroupPanel(CompactUi mainUi, UiShared uiShared, Configuration configuration, ApiController apiController) 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.SetNextItemWidth(UiShared.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X);
ImGui.InputTextWithHint("##syncshellid", "Syncshell GID/Alias", ref _syncShellToJoin, 20); ImGui.InputTextWithHint("##syncshellid", "Syncshell GID/Alias", ref _syncShellToJoin, 20);
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X); 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 (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; if (userCanJoinMoreGroups)
_showModalEnterPassword = true; {
ImGui.OpenPopup("Enter Syncshell Password"); _errorGroupJoin = false;
_showModalEnterPassword = true;
ImGui.OpenPopup("Enter Syncshell Password");
}
} }
else else
{ {
_lastCreatedGroup = null; if (userCanCreateMoreGroups)
_errorGroupCreate = false; {
_showModalCreateGroup = true; _lastCreatedGroup = null;
ImGui.OpenPopup("Create Syncshell"); _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)) 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); ImGui.InputTextWithHint("##password", _syncShellToJoin + " Password", ref _syncShellPassword, 255, ImGuiInputTextFlags.Password);
if (_errorGroupJoin) 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)); new Vector4(1, 0, 0, 1));
} }
if (ImGui.Button("Join " + _syncShellToJoin)) if (ImGui.Button("Join " + _syncShellToJoin))
@@ -141,7 +154,6 @@ namespace MareSynchronos.UI
ImGui.EndPopup(); ImGui.EndPopup();
} }
ImGuiHelpers.ScaledDummy(2); ImGuiHelpers.ScaledDummy(2);
} }
@@ -161,7 +173,7 @@ namespace MareSynchronos.UI
private void DrawSyncshell(GroupDto group) private void DrawSyncshell(GroupDto group)
{ {
var name = group.Alias ?? group.GID; 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)) if (!ExpandedGroupState.TryGetValue(group.GID, out bool isExpanded))
{ {
isExpanded = false; isExpanded = false;
@@ -188,7 +200,7 @@ namespace MareSynchronos.UI
var groupName = group.Alias ?? group.GID; var groupName = group.Alias ?? group.GID;
var textIsGid = true; var textIsGid = true;
if (group.OwnedBy == _apiController.UID) if (string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal))
{ {
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
ImGui.Text(FontAwesomeIcon.Crown.ToIconString()); 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); if (textIsGid) ImGui.PushFont(UiBuilder.MonoFont);
ImGui.TextUnformatted(groupName); ImGui.TextUnformatted(groupName);
@@ -258,12 +270,12 @@ namespace MareSynchronos.UI
ImGui.Indent(collapseButton.X); ImGui.Indent(collapseButton.X);
if (ExpandedGroupState[group.GID]) 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.Indent(ImGui.GetStyle().ItemSpacing.X / 2);
ImGui.Separator(); ImGui.Separator();
foreach (var pair in pairsInGroup) 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(); ImGui.Separator();
@@ -299,7 +311,7 @@ namespace MareSynchronos.UI
_ = _apiController.SendLeaveGroup(entry.GID); _ = _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.")); + "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")) if (UiShared.IconTextButton(FontAwesomeIcon.Copy, "Copy ID"))
@@ -308,7 +320,7 @@ namespace MareSynchronos.UI
} }
UiShared.AttachToolTip("Copy Syncshell ID to Clipboard"); UiShared.AttachToolTip("Copy Syncshell ID to Clipboard");
if (entry.OwnedBy == _apiController.UID) if (string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal))
{ {
ImGui.Separator(); ImGui.Separator();
@@ -428,7 +440,7 @@ namespace MareSynchronos.UI
} }
ImGui.SameLine(); ImGui.SameLine();
if (_mainUi.EditNickEntry != entry.UserUID) if (!string.Equals(_mainUi.EditNickEntry, entry.UserUID, StringComparison.Ordinal))
{ {
ImGui.SetCursorPosY(textPos); ImGui.SetCursorPosY(textPos);
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont); if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
@@ -476,7 +488,7 @@ namespace MareSynchronos.UI
UiShared.AttachToolTip("Hit ENTER to save\nRight click to cancel"); 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) if (plusButtonShown)
{ {

View File

@@ -37,12 +37,12 @@ internal class IntroUi : Window, IDisposable
private Task _timeoutTask; private Task _timeoutTask;
private string _timeoutTime; private string _timeoutTime;
private Dictionary<string, string> _languages = new() { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } }; private Dictionary<string, string> _languages = new(StringComparer.Ordinal) { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } };
private int _currentLanguage; private int _currentLanguage;
private bool DarkSoulsCaptchaValid => _darkSoulsCaptcha1.Item2 == _enteredDarkSoulsCaptcha1.Trim() private bool DarkSoulsCaptchaValid => string.Equals(_darkSoulsCaptcha1.Item2, _enteredDarkSoulsCaptcha1.Trim()
&& _darkSoulsCaptcha2.Item2 == _enteredDarkSoulsCaptcha2.Trim() , StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha2.Item2, _enteredDarkSoulsCaptcha2.Trim()
&& _darkSoulsCaptcha3.Item2 == _enteredDarkSoulsCaptcha3.Trim(); , StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha3.Item2, _enteredDarkSoulsCaptcha3.Trim(), StringComparison.Ordinal);
public void Dispose() public void Dispose()
@@ -158,7 +158,7 @@ internal class IntroUi : Window, IDisposable
{ {
_timeoutTime = $"{i}s " + Strings.ToS.RemainingLabel; _timeoutTime = $"{i}s " + Strings.ToS.RemainingLabel;
Logger.Debug(_timeoutTime); 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<string, string> GetCaptchaTuple() private Tuple<string, string> GetCaptchaTuple()
{ {
Random random = new Random(); Random random = new();
var paragraphIdx = random.Next(TosParagraphs.Length); var paragraphIdx = random.Next(TosParagraphs.Length);
var splitParagraph = TosParagraphs[paragraphIdx].Split(".", StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim()).ToArray(); var splitParagraph = TosParagraphs[paragraphIdx].Split(".", StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim()).ToArray();
var sentenceIdx = random.Next(splitParagraph.Length); 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); 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]); return new($"{Strings.ToS.ParagraphLabel} {paragraphIdx + 1}, {Strings.ToS.SentenceLabel} {sentenceIdx + 1}, {Strings.ToS.WordLabel} {wordIdx + 1}", splitSentence[wordIdx]);
} }

View File

@@ -335,7 +335,7 @@ public class SettingsUi : Window, IDisposable
}); });
} }
ImGui.SameLine(); ImGui.SameLine();
if (onlineUser.UID != _apiController.UID && _apiController.IsAdmin) if (!string.Equals(onlineUser.UID, _apiController.UID, StringComparison.Ordinal) && _apiController.IsAdmin)
{ {
if (!onlineUser.IsModerator) if (!onlineUser.IsModerator)
{ {

View File

@@ -294,7 +294,7 @@ public class UiShared : IDisposable
bool isSelected = _serverSelectionIndex == i; bool isSelected = _serverSelectionIndex == i;
if (ImGui.Selectable(comboEntries[i], isSelected)) 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(); _pluginConfiguration.Save();
_ = _apiController.CreateConnections(); _ = _apiController.CreateConnections();
} }
@@ -451,7 +451,7 @@ public class UiShared : IDisposable
{ {
if (!success) return; if (!success) return;
_isPenumbraDirectory = path.ToLowerInvariant() == _ipcManager.PenumbraModDirectory()?.ToLowerInvariant(); _isPenumbraDirectory = string.Equals(path.ToLowerInvariant(), _ipcManager.PenumbraModDirectory()?.ToLowerInvariant(), StringComparison.Ordinal);
_isDirectoryWritable = IsDirectoryWritable(path); _isDirectoryWritable = IsDirectoryWritable(path);
_cacheDirectoryHasOtherFilesThanCache = Directory.GetFiles(path, "*", SearchOption.AllDirectories).Any(f => new FileInfo(f).Name.Length != 40); _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); _cacheDirectoryIsValidPath = Regex.IsMatch(path, @"^(?:[a-zA-Z]:\\[\w\s\-\\]+?|\/(?:[\w\s\-\/])+?)$", RegexOptions.ECMAScript);

View File

@@ -11,24 +11,24 @@ public class Crypto
public static string GetFileHash(string filePath) public static string GetFileHash(string filePath)
{ {
using SHA1CryptoServiceProvider cryptoProvider = new(); 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) public static string GetHash(string stringToHash)
{ {
using SHA1CryptoServiceProvider cryptoProvider = new(); 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) public static string GetHash256(string stringToHash)
{ {
using SHA256CryptoServiceProvider cryptoProvider = new(); 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) public static string GetHash256(PlayerCharacter character)
{ {
using SHA256CryptoServiceProvider cryptoProvider = new(); 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);
} }
} }

View File

@@ -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<string, Logger> _loggers =
new(StringComparer.OrdinalIgnoreCase);
public DalamudLoggingProvider()
{
}
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName, name => new Logger(categoryName));
}
public void Dispose()
{
_loggers.Clear();
}
}

View File

@@ -186,7 +186,7 @@ public class DalamudUtil : IDisposable
{ {
return _objectTable.Where(obj => return _objectTable.Where(obj =>
obj.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player && 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) public Dalamud.Game.ClientState.Objects.Types.Character? GetCharacterFromObjectTableByIndex(int index)
@@ -201,7 +201,7 @@ public class DalamudUtil : IDisposable
foreach (var item in _objectTable) foreach (var item in _objectTable)
{ {
if (item.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue; 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; return null;
@@ -209,7 +209,7 @@ public class DalamudUtil : IDisposable
public async Task<T> RunOnFrameworkThread<T>(Func<T> func) public async Task<T> RunOnFrameworkThread<T>(Func<T> 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) public unsafe void WaitWhileCharacterIsDrawing(string name, IntPtr characterAddress, int timeOut = 5000, CancellationToken? ct = null)

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using Dalamud.Logging; using Dalamud.Logging;
using Dalamud.Utility; using Dalamud.Utility;
@@ -7,27 +6,6 @@ using Microsoft.Extensions.Logging;
namespace MareSynchronos.Utils; namespace MareSynchronos.Utils;
[ProviderAlias("Dalamud")]
public class DalamudLoggingProvider : ILoggerProvider
{
private readonly ConcurrentDictionary<string, Logger> _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 internal class Logger : ILogger
{ {
private readonly string name; private readonly string name;
@@ -41,7 +19,7 @@ internal class Logger : ILogger
public static void Debug(string debug, string stringToHighlight = "") public static void Debug(string debug, string stringToHighlight = "")
{ {
var caller = new StackTrace().GetFrame(1)?.GetMethod()?.ReflectedType?.Name ?? "Unknown"; 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}"); PluginLog.Warning($"[{caller}] {debug}");
} }

View File

@@ -18,7 +18,7 @@ public static class VariousExtensions
if (attribute?.InformationalVersion != null) if (attribute?.InformationalVersion != null)
{ {
var value = attribute.InformationalVersion; var value = attribute.InformationalVersion;
var index = value.IndexOf(BuildVersionMetadataPrefix); var index = value.IndexOf(BuildVersionMetadataPrefix, StringComparison.Ordinal);
if (index > 0) if (index > 0)
{ {
value = value[(index + BuildVersionMetadataPrefix.Length)..]; value = value[(index + BuildVersionMetadataPrefix.Length)..];

View File

@@ -33,7 +33,7 @@ public partial class ApiController
public async Task DeleteAllMyFiles() public async Task DeleteAllMyFiles()
{ {
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles); await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false);
} }
private async Task<string> DownloadFile(int downloadId, string hash, Uri downloadUri, CancellationToken ct) private async Task<string> DownloadFile(int downloadId, string hash, Uri downloadUri, CancellationToken ct)
@@ -44,7 +44,7 @@ public partial class ApiController
{ {
try 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) catch (Exception ex)
{ {
@@ -61,11 +61,11 @@ public partial class ApiController
try try
{ {
await wc.DownloadFileTaskAsync(downloadUri, fileName); await wc.DownloadFileTaskAsync(downloadUri, fileName).ConfigureAwait(false);
} }
catch { } 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; wc.DownloadProgressChanged -= progChanged;
return fileName; return fileName;
@@ -78,7 +78,7 @@ public partial class ApiController
DownloadStarted?.Invoke(); DownloadStarted?.Invoke();
try try
{ {
await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct); await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct).ConfigureAwait(false);
} }
catch catch
{ {
@@ -94,8 +94,8 @@ public partial class ApiController
{ {
Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")"); Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")");
List<DownloadFileDto> downloadFileInfoFromService = new List<DownloadFileDto>(); List<DownloadFileDto> downloadFileInfoFromService = new();
downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync<List<DownloadFileDto>>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct)); downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync<List<DownloadFileDto>>(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))); 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)) 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)); ForbiddenTransfers.Add(new DownloadFileTransfer(dto));
} }
@@ -118,7 +118,7 @@ public partial class ApiController
async (file, token) => async (file, token) =>
{ {
var hash = file.Hash; 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) if (token.IsCancellationRequested)
{ {
File.Delete(tempFile); File.Delete(tempFile);
@@ -128,16 +128,16 @@ public partial class ApiController
return; return;
} }
var tempFileData = await File.ReadAllBytesAsync(tempFile, token); var tempFileData = await File.ReadAllBytesAsync(tempFile, token).ConfigureAwait(false);
var extractedFile = LZ4Codec.Unwrap(tempFileData); var extractedFile = LZ4Codec.Unwrap(tempFileData);
File.Delete(tempFile); File.Delete(tempFile);
var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash); 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); var fi = new FileInfo(filePath);
Func<DateTime> RandomDayFunc() Func<DateTime> RandomDayFunc()
{ {
DateTime start = new DateTime(1995, 1, 1); DateTime start = new(1995, 1, 1);
Random gen = new Random(); Random gen = new();
int range = (DateTime.Today - start).Days; int range = (DateTime.Today - start).Days;
return () => start.AddDays(gen.Next(range)); return () => start.AddDays(gen.Next(range));
} }
@@ -155,7 +155,7 @@ public partial class ApiController
Logger.Warn(ex.Message); Logger.Warn(ex.Message);
Logger.Warn(ex.StackTrace); Logger.Warn(ex.StackTrace);
} }
}); }).ConfigureAwait(false);
Logger.Debug("Download complete, removing " + currentDownloadId); Logger.Debug("Download complete, removing " + currentDownloadId);
CancelDownload(currentDownloadId); CancelDownload(currentDownloadId);
@@ -163,7 +163,7 @@ public partial class ApiController
public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds) public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", StringComparison.Ordinal)) return;
Logger.Debug("Sending Character data to service " + ApiUri); Logger.Debug("Sending Character data to service " + ApiUri);
CancelUpload(); CancelUpload();
@@ -172,7 +172,7 @@ public partial class ApiController
Logger.Verbose("New Token Created"); Logger.Verbose("New Token Created");
List<string> unverifiedUploadHashes = new(); List<string> 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)) if (!_verifiedUploadedHashes.Contains(item))
{ {
@@ -183,7 +183,7 @@ public partial class ApiController
if (unverifiedUploadHashes.Any()) if (unverifiedUploadHashes.Any())
{ {
Logger.Debug("Verifying " + unverifiedUploadHashes.Count + " files"); Logger.Debug("Verifying " + unverifiedUploadHashes.Count + " files");
var filesToUpload = await _mareHub!.InvokeAsync<List<UploadFileDto>>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken); var filesToUpload = await _mareHub!.InvokeAsync<List<UploadFileDto>>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken).ConfigureAwait(false);
foreach (var file in filesToUpload.Where(f => !f.IsForbidden)) 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)) 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) 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()) foreach (var file in CurrentUploads.Where(f => f.CanBeTransferred && !f.IsTransferred).ToList())
{ {
Logger.Debug("Compressing and uploading " + file); Logger.Debug("Compressing and uploading " + file);
var data = await GetCompressedFileData(file.Hash, uploadToken); var data = await GetCompressedFileData(file.Hash, uploadToken).ConfigureAwait(false);
CurrentUploads.Single(e => e.Hash == data.Item1).Total = data.Item2.Length; CurrentUploads.Single(e => string.Equals(e.Hash, data.Item1, StringComparison.Ordinal)).Total = data.Item2.Length;
await UploadFile(data.Item2, file.Hash, uploadToken); await UploadFile(data.Item2, file.Hash, uploadToken).ConfigureAwait(false);
if (!uploadToken.IsCancellationRequested) continue; if (!uploadToken.IsCancellationRequested) continue;
Logger.Warn("Cancel in filesToUpload loop detected"); Logger.Warn("Cancel in filesToUpload loop detected");
CurrentUploads.Clear(); CurrentUploads.Clear();
@@ -233,12 +233,12 @@ public partial class ApiController
} }
Logger.Debug("Upload tasks complete, waiting for server to confirm"); Logger.Debug("Upload tasks complete, waiting for server to confirm");
var anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken); var anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false);
Logger.Debug("Uploads open: " + anyUploadsOpen); Logger.Debug("Uploads open: " + anyUploadsOpen);
while (anyUploadsOpen && !uploadToken.IsCancellationRequested) while (anyUploadsOpen && !uploadToken.IsCancellationRequested)
{ {
anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken); anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken); await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken).ConfigureAwait(false);
Logger.Debug("Waiting for uploads to finish"); Logger.Debug("Waiting for uploads to finish");
} }
@@ -257,7 +257,7 @@ public partial class ApiController
if (!uploadToken.IsCancellationRequested) if (!uploadToken.IsCancellationRequested)
{ {
Logger.Info("Pushing character data for " + character.GetHashCode() + " to " + string.Join(", ", visibleCharacterIds)); 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) foreach (var item in character.FileReplacements)
{ {
sb.AppendLine($"FileReplacements for {item.Key}: {item.Value.Count}"); 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)}"); sb.AppendLine($"GlamourerData for {item.Key}: {!string.IsNullOrEmpty(item.Value)}");
} }
Logger.Debug("Chara data contained: " + Environment.NewLine + sb.ToString()); 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 else
{ {
@@ -281,7 +281,7 @@ public partial class ApiController
private async Task<(string, byte[])> GetCompressedFileData(string fileHash, CancellationToken uploadToken) private async Task<(string, byte[])> GetCompressedFileData(string fileHash, CancellationToken uploadToken)
{ {
var fileCache = _fileDbManager.GetFileCacheByHash(fileHash)!.ResolvedFilepath; 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)); (int)new FileInfo(fileCache).Length));
} }
@@ -295,15 +295,15 @@ public partial class ApiController
using var ms = new MemoryStream(compressedFile); using var ms = new MemoryStream(compressedFile);
var buffer = new byte[chunkSize]; var buffer = new byte[chunkSize];
int bytesRead; 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(); token.ThrowIfCancellationRequested();
yield return bytesRead == chunkSize ? buffer.ToArray() : buffer.Take(bytesRead).ToArray(); 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) public void CancelDownload(int downloadId)

View File

@@ -11,32 +11,32 @@ public partial class ApiController
{ {
_pluginConfiguration.ClientSecret.Remove(ApiUri); _pluginConfiguration.ClientSecret.Remove(ApiUri);
_pluginConfiguration.Save(); _pluginConfiguration.Save();
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles); await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false);
await _mareHub!.SendAsync(Api.SendUserDeleteAccount); await _mareHub!.SendAsync(Api.SendUserDeleteAccount).ConfigureAwait(false);
await CreateConnections(); await CreateConnections().ConfigureAwait(false);
} }
public async Task<List<string>> GetOnlineCharacters() public async Task<List<string>> GetOnlineCharacters()
{ {
return await _mareHub!.InvokeAsync<List<string>>(Api.InvokeUserGetOnlineCharacters); return await _mareHub!.InvokeAsync<List<string>>(Api.InvokeUserGetOnlineCharacters).ConfigureAwait(false);
} }
public async Task SendPairedClientAddition(string uid) public async Task SendPairedClientAddition(string uid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid); await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid).ConfigureAwait(false);
} }
public async Task SendPairedClientPauseChange(string uid, bool paused) public async Task SendPairedClientPauseChange(string uid, bool paused)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused); await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused).ConfigureAwait(false);
} }
public async Task SendPairedClientRemoval(string uid) public async Task SendPairedClientRemoval(string uid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid); await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid).ConfigureAwait(false);
} }
} }

View File

@@ -10,27 +10,27 @@ public partial class ApiController
{ {
public async Task AddOrUpdateForbiddenFileEntry(ForbiddenFileDto forbiddenFile) 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) 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) 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) public async Task DeleteBannedUserEntry(BannedUserDto bannedUser)
{ {
await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser); await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser).ConfigureAwait(false);
} }
public async Task RefreshOnlineUsers() public async Task RefreshOnlineUsers()
{ {
AdminOnlineUsers = await _mareHub!.InvokeAsync<List<OnlineUserDto>>(Api.InvokeAdminGetOnlineUsers); AdminOnlineUsers = await _mareHub!.InvokeAsync<List<OnlineUserDto>>(Api.InvokeAdminGetOnlineUsers).ConfigureAwait(false);
} }
public List<OnlineUserDto> AdminOnlineUsers { get; set; } = new List<OnlineUserDto>(); public List<OnlineUserDto> AdminOnlineUsers { get; set; } = new List<OnlineUserDto>();

View File

@@ -17,10 +17,10 @@ public partial class ApiController
private void UpdateLocalClientPairsCallback(ClientPairDto dto) 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) if (dto.IsRemoved)
{ {
PairedClients.RemoveAll(p => p.OtherUID == dto.OtherUID); PairedClients.RemoveAll(p => string.Equals(p.OtherUID, dto.OtherUID, System.StringComparison.Ordinal));
return; return;
} }
if (entry == null) if (entry == null)
@@ -43,7 +43,7 @@ public partial class ApiController
private void UpdateOrAddBannedUserCallback(BannedUserDto obj) 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) if (user == null)
{ {
AdminBannedUsers.Add(obj); AdminBannedUsers.Add(obj);
@@ -56,12 +56,12 @@ public partial class ApiController
private void DeleteBannedUserCallback(BannedUserDto obj) 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) 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) if (user == null)
{ {
AdminForbiddenFiles.Add(obj); AdminForbiddenFiles.Add(obj);
@@ -74,18 +74,18 @@ public partial class ApiController
private void DeleteForbiddenFileCallback(ForbiddenFileDto obj) 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) private void GroupPairChangedCallback(GroupPairDto dto)
{ {
if (dto.IsRemoved.GetValueOrDefault(false)) 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; 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) if (existingUser == null)
{ {
GroupPairedClients.Add(dto); GroupPairedClients.Add(dto);
@@ -101,16 +101,16 @@ public partial class ApiController
{ {
if (dto.IsDeleted.GetValueOrDefault(false)) if (dto.IsDeleted.GetValueOrDefault(false))
{ {
Groups.RemoveAll(g => g.GID == dto.GID); Groups.RemoveAll(g => string.Equals(g.GID, dto.GID, System.StringComparison.Ordinal));
GroupPairedClients.RemoveAll(g => g.GroupGID == dto.GID); GroupPairedClients.RemoveAll(g => string.Equals(g.GroupGID, dto.GID, System.StringComparison.Ordinal));
return; 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) if (existingGroup == null)
{ {
Groups.Add(dto); Groups.Add(dto);
GroupPairedClients.AddRange(await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, dto.GID)); GroupPairedClients.AddRange(await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, dto.GID).ConfigureAwait(false));
return; return;
} }

View File

@@ -9,79 +9,79 @@ public partial class ApiController
{ {
public async Task<GroupCreatedDto> CreateGroup() public async Task<GroupCreatedDto> CreateGroup()
{ {
if (!IsConnected || SecretKey == "-") return new GroupCreatedDto(); if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new GroupCreatedDto();
return await _mareHub!.InvokeAsync<GroupCreatedDto>(Api.InvokeGroupCreate); return await _mareHub!.InvokeAsync<GroupCreatedDto>(Api.InvokeGroupCreate).ConfigureAwait(false);
} }
public async Task<bool> ChangeGroupPassword(string gid, string newpassword) public async Task<bool> ChangeGroupPassword(string gid, string newpassword)
{ {
if (!IsConnected || SecretKey == "-") return false; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false;
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupChangePassword, gid, newpassword); return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupChangePassword, gid, newpassword).ConfigureAwait(false);
} }
public async Task<List<GroupDto>> GetGroups() public async Task<List<GroupDto>> GetGroups()
{ {
if (!IsConnected || SecretKey == "-") return new List<GroupDto>(); if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List<GroupDto>();
return await _mareHub!.InvokeAsync<List<GroupDto>>(Api.InvokeGroupGetGroups); return await _mareHub!.InvokeAsync<List<GroupDto>>(Api.InvokeGroupGetGroups).ConfigureAwait(false);
} }
public async Task<List<GroupPairDto>> GetUsersInGroup(string gid) public async Task<List<GroupPairDto>> GetUsersInGroup(string gid)
{ {
if (!IsConnected || SecretKey == "-") return new List<GroupPairDto>(); if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List<GroupPairDto>();
return await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, gid); return await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, gid).ConfigureAwait(false);
} }
public async Task<bool> SendGroupJoin(string gid, string password) public async Task<bool> SendGroupJoin(string gid, string password)
{ {
if (!IsConnected || SecretKey == "-") return false; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false;
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupJoin, gid, password); return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupJoin, gid, password).ConfigureAwait(false);
} }
public async Task SendGroupChangeInviteState(string gid, bool opened) public async Task SendGroupChangeInviteState(string gid, bool opened)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened); await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened).ConfigureAwait(false);
} }
public async Task SendDeleteGroup(string gid) public async Task SendDeleteGroup(string gid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupDelete, gid); await _mareHub!.SendAsync(Api.SendGroupDelete, gid).ConfigureAwait(false);
} }
public async Task SendChangeUserPinned(string gid, string uid, bool isPinned) public async Task SendChangeUserPinned(string gid, string uid, bool isPinned)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned); await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned).ConfigureAwait(false);
} }
public async Task SendClearGroup(string gid) public async Task SendClearGroup(string gid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupClear, gid); await _mareHub!.SendAsync(Api.SendGroupClear, gid).ConfigureAwait(false);
} }
public async Task SendLeaveGroup(string gid) public async Task SendLeaveGroup(string gid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupLeave, gid); await _mareHub!.SendAsync(Api.SendGroupLeave, gid).ConfigureAwait(false);
} }
public async Task SendPauseGroup(string gid, bool isPaused) public async Task SendPauseGroup(string gid, bool isPaused)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused); await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused).ConfigureAwait(false);
} }
public async Task SendRemoveUserFromGroup(string gid, string uid) public async Task SendRemoveUserFromGroup(string gid, string uid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid); await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid).ConfigureAwait(false);
} }
public async Task ChangeOwnerOfGroup(string gid, string uid) public async Task ChangeOwnerOfGroup(string gid, string uid)
{ {
if (!IsConnected || SecretKey == "-") return; if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid); await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid).ConfigureAwait(false);
} }
} }

View File

@@ -33,8 +33,11 @@ public partial class ApiController : IDisposable
private HubConnection? _mareHub; private HubConnection? _mareHub;
private CancellationTokenSource? _uploadCancellationTokenSource = new(); private CancellationTokenSource? _uploadCancellationTokenSource = new();
private CancellationTokenSource? _healthCheckTokenSource = new();
private ConnectionDto? _connectionDto; private ConnectionDto? _connectionDto;
public ServerInfoDto ServerInfo => _connectionDto?.ServerInfo ?? new ServerInfoDto();
public SystemInfoDto SystemInfoDto { get; private set; } = new(); public SystemInfoDto SystemInfoDto { get; private set; } = new();
public bool IsModerator => (_connectionDto?.IsAdmin ?? false) || (_connectionDto?.IsModerator ?? false); public bool IsModerator => (_connectionDto?.IsAdmin ?? false) || (_connectionDto?.IsModerator ?? false);
@@ -51,7 +54,7 @@ public partial class ApiController : IDisposable
_dalamudUtil.LogIn += DalamudUtilOnLogIn; _dalamudUtil.LogIn += DalamudUtilOnLogIn;
_dalamudUtil.LogOut += DalamudUtilOnLogOut; _dalamudUtil.LogOut += DalamudUtilOnLogOut;
ServerState = ServerState.Offline; ServerState = ServerState.Offline;
_verifiedUploadedHashes = new(); _verifiedUploadedHashes = new(StringComparer.Ordinal);
if (_dalamudUtil.IsLoggedIn) if (_dalamudUtil.IsLoggedIn)
{ {
@@ -61,7 +64,7 @@ public partial class ApiController : IDisposable
private void DalamudUtilOnLogOut() private void DalamudUtilOnLogOut()
{ {
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token)); Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false));
ServerState = ServerState.Offline; 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 bool ServerAlive => ServerState is ServerState.Connected or ServerState.RateLimited or ServerState.Unauthorized or ServerState.Disconnected;
public Dictionary<string, string> ServerDictionary => new Dictionary<string, string>() public Dictionary<string, string> ServerDictionary => new Dictionary<string, string>(StringComparer.Ordinal)
{ { MainServiceUri, MainServer } } { { MainServiceUri, MainServer } }
.Concat(_pluginConfiguration.CustomServerList) .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 UID => _connectionDto?.UID ?? string.Empty;
public string DisplayName => _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"); Logger.Info("Not recreating Connection, paused");
ServerState = ServerState.Disconnected; ServerState = ServerState.Disconnected;
_connectionDto = null; _connectionDto = null;
await StopConnection(_connectionCancellationTokenSource.Token); await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false);
return; return;
} }
await StopConnection(_connectionCancellationTokenSource.Token); await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false);
Logger.Info("Recreating Connection"); Logger.Info("Recreating Connection");
@@ -154,11 +157,11 @@ public partial class ApiController : IDisposable
{ {
if (string.IsNullOrEmpty(SecretKey)) if (string.IsNullOrEmpty(SecretKey))
{ {
await Task.Delay(TimeSpan.FromSeconds(2)); await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
continue; continue;
} }
await StopConnection(token); await StopConnection(token).ConfigureAwait(false);
try try
{ {
@@ -167,32 +170,32 @@ public partial class ApiController : IDisposable
while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested) while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested)
{ {
Logger.Debug("Player not loaded in yet, waiting"); 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; if (token.IsCancellationRequested) break;
_mareHub = BuildHubConnection(Api.Path); _mareHub = BuildHubConnection(Api.Path);
await _mareHub.StartAsync(token); await _mareHub.StartAsync(token).ConfigureAwait(false);
_mareHub.On<SystemInfoDto>(Api.OnUpdateSystemInfo, (dto) => SystemInfoDto = dto); _mareHub.On<SystemInfoDto>(Api.OnUpdateSystemInfo, (dto) => SystemInfoDto = dto);
_connectionDto = _connectionDto =
await _mareHub.InvokeAsync<ConnectionDto>(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token); await _mareHub.InvokeAsync<ConnectionDto>(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token).ConfigureAwait(false);
ServerState = ServerState.Connected; ServerState = ServerState.Connected;
if (_connectionDto.ServerVersion != Api.Version) if (_connectionDto.ServerVersion != Api.Version)
{ {
ServerState = ServerState.VersionMisMatch; ServerState = ServerState.VersionMisMatch;
await StopConnection(token); await StopConnection(token).ConfigureAwait(false);
return; return;
} }
if (ServerState is ServerState.Connected) // user is authorized && server is legit if (ServerState is ServerState.Connected) // user is authorized && server is legit
{ {
await InitializeData(token); await InitializeData(token).ConfigureAwait(false);
_mareHub.Closed += MareHubOnClosed; _mareHub.Closed += MareHubOnClosed;
_mareHub.Reconnecting += MareHubOnReconnecting; _mareHub.Reconnecting += MareHubOnReconnecting;
@@ -206,7 +209,7 @@ public partial class ApiController : IDisposable
Logger.Warn(ex.StackTrace ?? string.Empty); Logger.Warn(ex.StackTrace ?? string.Empty);
ServerState = ServerState.RateLimited; ServerState = ServerState.RateLimited;
await StopConnection(token); await StopConnection(token).ConfigureAwait(false);
return; return;
} }
catch (HttpRequestException ex) catch (HttpRequestException ex)
@@ -218,14 +221,14 @@ public partial class ApiController : IDisposable
if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{ {
ServerState = ServerState.Unauthorized; ServerState = ServerState.Unauthorized;
await StopConnection(token); await StopConnection(token).ConfigureAwait(false);
return; return;
} }
else else
{ {
ServerState = ServerState.Offline; ServerState = ServerState.Offline;
Logger.Info("Failed to establish connection, retrying"); 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) catch (Exception ex)
@@ -234,7 +237,7 @@ public partial class ApiController : IDisposable
Logger.Warn(ex.Message); Logger.Warn(ex.Message);
Logger.Warn(ex.StackTrace ?? string.Empty); Logger.Warn(ex.StackTrace ?? string.Empty);
Logger.Info("Failed to establish connection, retrying"); 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; 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<bool>(Api.InvokeCheckClientHealth, ct).ConfigureAwait(false);
Logger.Debug("Checked Client Health State, healthy: " + !needsRestart);
if (needsRestart)
{
_ = CreateConnections();
}
}
}
private async Task InitializeData(CancellationToken token) private async Task InitializeData(CancellationToken token)
{ {
if (_mareHub == null) return; if (_mareHub == null) return;
@@ -263,22 +281,22 @@ public partial class ApiController : IDisposable
_mareHub.On<GroupPairDto>(Api.OnGroupUserChange, GroupPairChangedCallback); _mareHub.On<GroupPairDto>(Api.OnGroupUserChange, GroupPairChangedCallback);
PairedClients = PairedClients =
await _mareHub!.InvokeAsync<List<ClientPairDto>>(Api.InvokeUserGetPairedClients, token); await _mareHub!.InvokeAsync<List<ClientPairDto>>(Api.InvokeUserGetPairedClients, token).ConfigureAwait(false);
Groups = await GetGroups(); Groups = await GetGroups().ConfigureAwait(false);
GroupPairedClients.Clear(); GroupPairedClients.Clear();
foreach (var group in Groups) foreach (var group in Groups)
{ {
GroupPairedClients.AddRange(await GetUsersInGroup(group.GID)); GroupPairedClients.AddRange(await GetUsersInGroup(group.GID).ConfigureAwait(false));
} }
if (IsModerator) if (IsModerator)
{ {
AdminForbiddenFiles = AdminForbiddenFiles =
await _mareHub.InvokeAsync<List<ForbiddenFileDto>>(Api.InvokeAdminGetForbiddenFiles, await _mareHub.InvokeAsync<List<ForbiddenFileDto>>(Api.InvokeAdminGetForbiddenFiles,
token); token).ConfigureAwait(false);
AdminBannedUsers = AdminBannedUsers =
await _mareHub.InvokeAsync<List<BannedUserDto>>(Api.InvokeAdminGetBannedUsers, await _mareHub.InvokeAsync<List<BannedUserDto>>(Api.InvokeAdminGetBannedUsers,
token); token).ConfigureAwait(false);
_mareHub.On<BannedUserDto>(Api.OnAdminUpdateOrAddBannedUser, _mareHub.On<BannedUserDto>(Api.OnAdminUpdateOrAddBannedUser,
UpdateOrAddBannedUserCallback); UpdateOrAddBannedUserCallback);
_mareHub.On<BannedUserDto>(Api.OnAdminDeleteBannedUser, DeleteBannedUserCallback); _mareHub.On<BannedUserDto>(Api.OnAdminDeleteBannedUser, DeleteBannedUserCallback);
@@ -288,6 +306,11 @@ public partial class ApiController : IDisposable
DeleteForbiddenFileCallback); DeleteForbiddenFileCallback);
} }
_healthCheckTokenSource?.Cancel();
_healthCheckTokenSource?.Dispose();
_healthCheckTokenSource = new CancellationTokenSource();
_ = ClientHealthCheck(_healthCheckTokenSource.Token);
Connected?.Invoke(); Connected?.Invoke();
} }
@@ -298,7 +321,7 @@ public partial class ApiController : IDisposable
_dalamudUtil.LogIn -= DalamudUtilOnLogIn; _dalamudUtil.LogIn -= DalamudUtilOnLogIn;
_dalamudUtil.LogOut -= DalamudUtilOnLogOut; _dalamudUtil.LogOut -= DalamudUtilOnLogOut;
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token)); Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false));
_connectionCancellationTokenSource?.Cancel(); _connectionCancellationTokenSource?.Cancel();
} }
@@ -332,6 +355,7 @@ public partial class ApiController : IDisposable
private Task MareHubOnReconnecting(Exception? arg) private Task MareHubOnReconnecting(Exception? arg)
{ {
_healthCheckTokenSource?.Cancel();
ServerState = ServerState.Disconnected; ServerState = ServerState.Disconnected;
Logger.Warn("Connection closed... Reconnecting"); Logger.Warn("Connection closed... Reconnecting");
Logger.Warn(arg?.Message ?? string.Empty); Logger.Warn(arg?.Message ?? string.Empty);
@@ -350,8 +374,8 @@ public partial class ApiController : IDisposable
_mareHub.Closed -= MareHubOnClosed; _mareHub.Closed -= MareHubOnClosed;
_mareHub.Reconnecting -= MareHubOnReconnecting; _mareHub.Reconnecting -= MareHubOnReconnecting;
_mareHub.Reconnected -= MareHubOnReconnected; _mareHub.Reconnected -= MareHubOnReconnected;
await _mareHub.StopAsync(token); await _mareHub.StopAsync(token).ConfigureAwait(false);
await _mareHub.DisposeAsync(); await _mareHub.DisposeAsync().ConfigureAwait(false);
CurrentUploads.Clear(); CurrentUploads.Clear();
CurrentDownloads.Clear(); CurrentDownloads.Clear();
_uploadCancellationTokenSource?.Cancel(); _uploadCancellationTokenSource?.Cancel();
@@ -363,7 +387,7 @@ public partial class ApiController : IDisposable
{ {
while (ServerState != ServerState.Offline) while (ServerState != ServerState.Offline)
{ {
await Task.Delay(16); await Task.Delay(16).ConfigureAwait(false);
} }
} }
} }