2025-08-22 02:19:48 +01:00
using MareSynchronos.MareConfiguration ;
using MareSynchronos.MareConfiguration.Models ;
using MareSynchronos.Services.Mediator ;
using MareSynchronos.Utils ;
using MareSynchronos.WebAPI ;
using Microsoft.Extensions.Logging ;
using System.Diagnostics ;
namespace MareSynchronos.Services.ServerConfiguration ;
public class ServerConfigurationManager
{
private readonly ServerConfigService _configService ;
private readonly DalamudUtilService _dalamudUtil ;
private readonly ILogger < ServerConfigurationManager > _logger ;
private readonly NotesConfigService _notesConfig ;
private readonly ServerBlockConfigService _blockConfig ;
private readonly ServerTagConfigService _serverTagConfig ;
private readonly SyncshellConfigService _syncshellConfig ;
private HashSet < string > ? _cachedWhitelistedUIDs = null ;
private HashSet < string > ? _cachedBlacklistedUIDs = null ;
private string? _realApiUrl = null ;
public ServerConfigurationManager ( ILogger < ServerConfigurationManager > logger , ServerConfigService configService ,
ServerTagConfigService serverTagConfig , SyncshellConfigService syncshellConfig , NotesConfigService notesConfig ,
ServerBlockConfigService blockConfig , DalamudUtilService dalamudUtil )
{
_logger = logger ;
_configService = configService ;
_serverTagConfig = serverTagConfig ;
_syncshellConfig = syncshellConfig ;
_notesConfig = notesConfig ;
_blockConfig = blockConfig ;
_dalamudUtil = dalamudUtil ;
EnsureMainExists ( ) ;
}
public string CurrentApiUrl = > CurrentServer . ServerUri ;
public string CurrentRealApiUrl
{
get
{
return _realApiUrl ? ? CurrentApiUrl ;
}
}
public ServerStorage CurrentServer = > _configService . Current . ServerStorage [ CurrentServerIndex ] ;
public IReadOnlyList < string > Whitelist = > CurrentBlockStorage ( ) . Whitelist ;
public IReadOnlyList < string > Blacklist = > CurrentBlockStorage ( ) . Blacklist ;
public int CurrentServerIndex
{
set
{
_configService . Current . CurrentServer = value ;
_cachedWhitelistedUIDs = null ;
_cachedBlacklistedUIDs = null ;
_realApiUrl = null ;
_configService . Save ( ) ;
}
get
{
if ( _configService . Current . CurrentServer < 0 )
{
_configService . Current . CurrentServer = 0 ;
_configService . Save ( ) ;
}
return _configService . Current . CurrentServer ;
}
}
public string? GetSecretKey ( out bool hasMulti , int serverIdx = - 1 )
{
ServerStorage ? currentServer ;
currentServer = serverIdx = = - 1 ? CurrentServer : GetServerByIndex ( serverIdx ) ;
if ( currentServer = = null )
{
currentServer = new ( ) ;
Save ( ) ;
}
hasMulti = false ;
var charaName = _dalamudUtil . GetPlayerNameAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
var worldId = _dalamudUtil . GetHomeWorldIdAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
if ( ! currentServer . Authentications . Any ( ) & & currentServer . SecretKeys . Any ( ) )
{
currentServer . Authentications . Add ( new Authentication ( )
{
CharacterName = charaName ,
WorldId = worldId ,
SecretKeyIdx = currentServer . SecretKeys . Last ( ) . Key ,
} ) ;
Save ( ) ;
}
var auth = currentServer . Authentications . FindAll ( f = > string . Equals ( f . CharacterName , charaName , StringComparison . Ordinal ) & & f . WorldId = = worldId ) ;
if ( auth . Count > = 2 )
{
_logger . LogTrace ( "GetSecretKey accessed, returning null because multiple ({count}) identical characters." , auth . Count ) ;
hasMulti = true ;
return null ;
}
if ( auth . Count = = 0 )
{
_logger . LogTrace ( "GetSecretKey accessed, returning null because no set up characters for {chara} on {world}" , charaName , worldId ) ;
return null ;
}
if ( currentServer . SecretKeys . TryGetValue ( auth . Single ( ) . SecretKeyIdx , out var secretKey ) )
{
_logger . LogTrace ( "GetSecretKey accessed, returning {key} ({keyValue}) for {chara} on {world}" , secretKey . FriendlyName , string . Join ( "" , secretKey . Key . Take ( 10 ) ) , charaName , worldId ) ;
return secretKey . Key ;
}
_logger . LogTrace ( "GetSecretKey accessed, returning null because no fitting key found for {chara} on {world} for idx {idx}." , charaName , worldId , auth . Single ( ) . SecretKeyIdx ) ;
return null ;
}
public string [ ] GetServerApiUrls ( )
{
return _configService . Current . ServerStorage . Select ( v = > v . ServerUri ) . ToArray ( ) ;
}
public ServerStorage GetServerByIndex ( int idx )
{
try
{
return _configService . Current . ServerStorage [ idx ] ;
}
catch
{
_configService . Current . CurrentServer = 0 ;
EnsureMainExists ( ) ;
return CurrentServer ! ;
}
}
public string [ ] GetServerNames ( )
{
return _configService . Current . ServerStorage . Select ( v = > v . ServerName ) . ToArray ( ) ;
}
public bool HasValidConfig ( )
{
return CurrentServer ! = null & & CurrentServer . SecretKeys . Any ( ) ;
}
public void Save ( )
{
var caller = new StackTrace ( ) . GetFrame ( 1 ) ? . GetMethod ( ) ? . ReflectedType ? . Name ? ? "Unknown" ;
_logger . LogDebug ( "{caller} Calling config save" , caller ) ;
_configService . Save ( ) ;
}
public void SelectServer ( int idx )
{
_configService . Current . CurrentServer = idx ;
CurrentServer ! . FullPause = false ;
Save ( ) ;
}
internal void AddCurrentCharacterToServer ( int serverSelectionIndex = - 1 , bool save = true )
{
if ( serverSelectionIndex = = - 1 ) serverSelectionIndex = CurrentServerIndex ;
var server = GetServerByIndex ( serverSelectionIndex ) ;
if ( server . Authentications . Any ( c = > string . Equals ( c . CharacterName , _dalamudUtil . GetPlayerNameAsync ( ) . GetAwaiter ( ) . GetResult ( ) , StringComparison . Ordinal )
& & c . WorldId = = _dalamudUtil . GetHomeWorldIdAsync ( ) . GetAwaiter ( ) . GetResult ( ) ) )
return ;
server . Authentications . Add ( new Authentication ( )
{
CharacterName = _dalamudUtil . GetPlayerNameAsync ( ) . GetAwaiter ( ) . GetResult ( ) ,
WorldId = _dalamudUtil . GetHomeWorldIdAsync ( ) . GetAwaiter ( ) . GetResult ( ) ,
SecretKeyIdx = server . SecretKeys . Last ( ) . Key ,
} ) ;
if ( save )
Save ( ) ;
}
internal void AddEmptyCharacterToServer ( int serverSelectionIndex )
{
var server = GetServerByIndex ( serverSelectionIndex ) ;
server . Authentications . Add ( new Authentication ( )
{
SecretKeyIdx = server . SecretKeys . Any ( ) ? server . SecretKeys . First ( ) . Key : - 1 ,
} ) ;
Save ( ) ;
}
internal void AddOpenPairTag ( string tag )
{
CurrentServerTagStorage ( ) . OpenPairTags . Add ( tag ) ;
_serverTagConfig . Save ( ) ;
}
internal void AddServer ( ServerStorage serverStorage )
{
_configService . Current . ServerStorage . Add ( serverStorage ) ;
Save ( ) ;
}
internal void AddTag ( string tag )
{
CurrentServerTagStorage ( ) . ServerAvailablePairTags . Add ( tag ) ;
_serverTagConfig . Save ( ) ;
}
internal void AddTagForUid ( string uid , string tagName )
{
if ( CurrentServerTagStorage ( ) . UidServerPairedUserTags . TryGetValue ( uid , out var tags ) )
{
tags . Add ( tagName ) ;
}
else
{
CurrentServerTagStorage ( ) . UidServerPairedUserTags [ uid ] = [ tagName ] ;
}
_serverTagConfig . Save ( ) ;
}
internal bool ContainsOpenPairTag ( string tag )
{
return CurrentServerTagStorage ( ) . OpenPairTags . Contains ( tag ) ;
}
internal bool ContainsTag ( string uid , string tag )
{
if ( CurrentServerTagStorage ( ) . UidServerPairedUserTags . TryGetValue ( uid , out var tags ) )
{
return tags . Contains ( tag , StringComparer . Ordinal ) ;
}
return false ;
}
internal void DeleteServer ( ServerStorage selectedServer )
{
if ( Array . IndexOf ( _configService . Current . ServerStorage . ToArray ( ) , selectedServer ) <
_configService . Current . CurrentServer )
{
_configService . Current . CurrentServer - - ;
}
_configService . Current . ServerStorage . Remove ( selectedServer ) ;
Save ( ) ;
}
internal string? GetNoteForGid ( string gID )
{
if ( CurrentNotesStorage ( ) . GidServerComments . TryGetValue ( gID , out var note ) )
{
if ( string . IsNullOrEmpty ( note ) ) return null ;
return note ;
}
return null ;
}
internal string? GetNoteForUid ( string uid )
{
if ( CurrentNotesStorage ( ) . UidServerComments . TryGetValue ( uid , out var note ) )
{
if ( string . IsNullOrEmpty ( note ) ) return null ;
return note ;
}
return null ;
}
internal string? GetNameForUid ( string uid )
{
if ( CurrentNotesStorage ( ) . UidLastSeenNames . TryGetValue ( uid , out var name ) )
{
if ( string . IsNullOrEmpty ( name ) ) return null ;
return name ;
}
return null ;
}
internal HashSet < string > GetServerAvailablePairTags ( )
{
return CurrentServerTagStorage ( ) . ServerAvailablePairTags ;
}
internal ShellConfig GetShellConfigForGid ( string gid )
{
if ( CurrentSyncshellStorage ( ) . GidShellConfig . TryGetValue ( gid , out var config ) )
return config ;
// Pick the next higher syncshell number that is available
int newShellNumber = CurrentSyncshellStorage ( ) . GidShellConfig . Count > 0 ? CurrentSyncshellStorage ( ) . GidShellConfig . Select ( x = > x . Value . ShellNumber ) . Max ( ) + 1 : 1 ;
var shellConfig = new ShellConfig {
ShellNumber = newShellNumber
} ;
// Save config to avoid auto-generated numbers shuffling around
SaveShellConfigForGid ( gid , shellConfig ) ;
return CurrentSyncshellStorage ( ) . GidShellConfig [ gid ] ;
}
internal int GetShellNumberForGid ( string gid )
{
return GetShellConfigForGid ( gid ) . ShellNumber ;
}
internal Dictionary < string , List < string > > GetUidServerPairedUserTags ( )
{
return CurrentServerTagStorage ( ) . UidServerPairedUserTags ;
}
internal HashSet < string > GetUidsForTag ( string tag )
{
return CurrentServerTagStorage ( ) . UidServerPairedUserTags . Where ( p = > p . Value . Contains ( tag , StringComparer . Ordinal ) ) . Select ( p = > p . Key ) . ToHashSet ( StringComparer . Ordinal ) ;
}
internal bool HasTags ( string uid )
{
if ( CurrentServerTagStorage ( ) . UidServerPairedUserTags . TryGetValue ( uid , out var tags ) )
{
return tags . Any ( ) ;
}
return false ;
}
internal void RemoveCharacterFromServer ( int serverSelectionIndex , Authentication item )
{
var server = GetServerByIndex ( serverSelectionIndex ) ;
server . Authentications . Remove ( item ) ;
Save ( ) ;
}
internal void RemoveOpenPairTag ( string tag )
{
CurrentServerTagStorage ( ) . OpenPairTags . Remove ( tag ) ;
_serverTagConfig . Save ( ) ;
}
internal void RemoveTag ( string tag )
{
CurrentServerTagStorage ( ) . ServerAvailablePairTags . Remove ( tag ) ;
foreach ( var uid in GetUidsForTag ( tag ) )
{
RemoveTagForUid ( uid , tag , save : false ) ;
}
_serverTagConfig . Save ( ) ;
}
internal void RemoveTagForUid ( string uid , string tagName , bool save = true )
{
if ( CurrentServerTagStorage ( ) . UidServerPairedUserTags . TryGetValue ( uid , out var tags ) )
{
tags . Remove ( tagName ) ;
if ( save )
{
_serverTagConfig . Save ( ) ;
}
}
}
internal void RenameTag ( string oldName , string newName )
{
CurrentServerTagStorage ( ) . ServerAvailablePairTags . Remove ( oldName ) ;
CurrentServerTagStorage ( ) . ServerAvailablePairTags . Add ( newName ) ;
foreach ( var existingTags in CurrentServerTagStorage ( ) . UidServerPairedUserTags . Select ( k = > k . Value ) )
{
if ( existingTags . Remove ( oldName ) )
existingTags . Add ( newName ) ;
}
}
internal void SaveNotes ( )
{
_notesConfig . Save ( ) ;
}
internal void SetNoteForGid ( string gid , string note , bool save = true )
{
if ( string . IsNullOrEmpty ( gid ) ) return ;
CurrentNotesStorage ( ) . GidServerComments [ gid ] = note ;
if ( save )
_notesConfig . Save ( ) ;
}
internal void SetNoteForUid ( string uid , string note , bool save = true )
{
if ( string . IsNullOrEmpty ( uid ) ) return ;
CurrentNotesStorage ( ) . UidServerComments [ uid ] = note ;
if ( save )
_notesConfig . Save ( ) ;
}
internal void SetNameForUid ( string uid , string name )
{
if ( string . IsNullOrEmpty ( uid ) ) return ;
if ( CurrentNotesStorage ( ) . UidLastSeenNames . TryGetValue ( uid , out var currentName ) & & currentName . Equals ( name , StringComparison . Ordinal ) )
return ;
CurrentNotesStorage ( ) . UidLastSeenNames [ uid ] = name ;
_notesConfig . Save ( ) ;
}
internal void SaveShellConfigForGid ( string gid , ShellConfig config )
{
if ( string . IsNullOrEmpty ( gid ) ) return ;
// This is somewhat pointless because ShellConfig is a ref type we returned to the caller anyway...
CurrentSyncshellStorage ( ) . GidShellConfig [ gid ] = config ;
_syncshellConfig . Save ( ) ;
}
internal bool IsUidWhitelisted ( string uid )
{
_cachedWhitelistedUIDs ? ? = [ . . CurrentBlockStorage ( ) . Whitelist ] ;
return _cachedWhitelistedUIDs . Contains ( uid ) ;
}
internal bool IsUidBlacklisted ( string uid )
{
_cachedBlacklistedUIDs ? ? = [ . . CurrentBlockStorage ( ) . Blacklist ] ;
return _cachedBlacklistedUIDs . Contains ( uid ) ;
}
internal void AddWhitelistUid ( string uid )
{
if ( IsUidWhitelisted ( uid ) )
return ;
if ( CurrentBlockStorage ( ) . Blacklist . RemoveAll ( u = > u . Equals ( uid , StringComparison . Ordinal ) ) > 0 )
_cachedBlacklistedUIDs = null ;
CurrentBlockStorage ( ) . Whitelist . Add ( uid ) ;
_cachedWhitelistedUIDs = null ;
_blockConfig . Save ( ) ;
}
internal void AddBlacklistUid ( string uid )
{
if ( IsUidBlacklisted ( uid ) )
return ;
if ( CurrentBlockStorage ( ) . Whitelist . RemoveAll ( u = > u . Equals ( uid , StringComparison . Ordinal ) ) > 0 )
_cachedWhitelistedUIDs = null ;
CurrentBlockStorage ( ) . Blacklist . Add ( uid ) ;
_cachedBlacklistedUIDs = null ;
_blockConfig . Save ( ) ;
}
internal void RemoveWhitelistUid ( string uid )
{
if ( CurrentBlockStorage ( ) . Whitelist . RemoveAll ( u = > u . Equals ( uid , StringComparison . Ordinal ) ) > 0 )
_cachedWhitelistedUIDs = null ;
_blockConfig . Save ( ) ;
}
internal void RemoveBlacklistUid ( string uid )
{
if ( CurrentBlockStorage ( ) . Blacklist . RemoveAll ( u = > u . Equals ( uid , StringComparison . Ordinal ) ) > 0 )
_cachedBlacklistedUIDs = null ;
_blockConfig . Save ( ) ;
}
private ServerNotesStorage CurrentNotesStorage ( )
{
TryCreateCurrentNotesStorage ( ) ;
return _notesConfig . Current . ServerNotes [ CurrentApiUrl ] ;
}
private ServerTagStorage CurrentServerTagStorage ( )
{
TryCreateCurrentServerTagStorage ( ) ;
return _serverTagConfig . Current . ServerTagStorage [ CurrentApiUrl ] ;
}
private ServerShellStorage CurrentSyncshellStorage ( )
{
TryCreateCurrentSyncshellStorage ( ) ;
return _syncshellConfig . Current . ServerShellStorage [ CurrentApiUrl ] ;
}
private ServerBlockStorage CurrentBlockStorage ( )
{
TryCreateCurrentBlockStorage ( ) ;
return _blockConfig . Current . ServerBlocks [ CurrentApiUrl ] ;
}
private void EnsureMainExists ( )
{
bool elfExists = false ;
for ( int i = 0 ; i < _configService . Current . ServerStorage . Count ; + + i )
{
var x = _configService . Current . ServerStorage [ i ] ;
2025-08-22 21:26:51 +01:00
if ( x . ServerUri . Equals ( ApiController . SnowcloakServiceUri , StringComparison . OrdinalIgnoreCase ) )
2025-08-22 02:19:48 +01:00
elfExists = true ;
}
if ( ! elfExists )
{
2025-08-22 21:26:51 +01:00
_logger . LogDebug ( "Re-adding missing server {uri}" , ApiController . SnowcloakServiceUri ) ;
_configService . Current . ServerStorage . Insert ( 0 , new ServerStorage ( ) { ServerUri = ApiController . SnowcloakServiceUri , ServerName = ApiController . SnowcloakServer } ) ;
2025-08-22 02:19:48 +01:00
if ( _configService . Current . CurrentServer > = 0 )
_configService . Current . CurrentServer + + ;
}
Save ( ) ;
}
private void TryCreateCurrentNotesStorage ( )
{
if ( ! _notesConfig . Current . ServerNotes . ContainsKey ( CurrentApiUrl ) )
{
_notesConfig . Current . ServerNotes [ CurrentApiUrl ] = new ( ) ;
}
}
private void TryCreateCurrentServerTagStorage ( )
{
if ( ! _serverTagConfig . Current . ServerTagStorage . ContainsKey ( CurrentApiUrl ) )
{
_serverTagConfig . Current . ServerTagStorage [ CurrentApiUrl ] = new ( ) ;
}
}
private void TryCreateCurrentSyncshellStorage ( )
{
if ( ! _syncshellConfig . Current . ServerShellStorage . ContainsKey ( CurrentApiUrl ) )
{
_syncshellConfig . Current . ServerShellStorage [ CurrentApiUrl ] = new ( ) ;
}
}
private void TryCreateCurrentBlockStorage ( )
{
if ( ! _blockConfig . Current . ServerBlocks . ContainsKey ( CurrentApiUrl ) )
{
_blockConfig . Current . ServerBlocks [ CurrentApiUrl ] = new ( ) ;
}
}
}