using System; using System.Collections.Concurrent; using LightlessSync.API.Dto.User; using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Models; using LightlessSync.Services.Events; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; using Microsoft.Extensions.Logging; namespace LightlessSync.PlayerData.Pairs; /// /// wires mediator events into the pair system /// public sealed partial class PairCoordinator : MediatorSubscriberBase { private readonly ILogger _logger; private readonly LightlessConfigService _configService; private readonly LightlessMediator _mediator; private readonly PairHandlerRegistry _handlerRegistry; private readonly PairManager _pairManager; private readonly PairLedger _pairLedger; private readonly ServerConfigurationManager _serverConfigurationManager; private readonly ConcurrentDictionary _pendingCharacterData = new(StringComparer.Ordinal); public PairCoordinator( ILogger logger, LightlessConfigService configService, LightlessMediator mediator, PairHandlerRegistry handlerRegistry, PairManager pairManager, PairLedger pairLedger, ServerConfigurationManager serverConfigurationManager) : base(logger, mediator) { _logger = logger; _configService = configService; _mediator = mediator; _handlerRegistry = handlerRegistry; _pairManager = pairManager; _pairLedger = pairLedger; _serverConfigurationManager = serverConfigurationManager; mediator.Subscribe(this, msg => HandleActiveServerChange(msg.ServerUrl)); mediator.Subscribe(this, _ => HandleDisconnected()); } internal PairLedger Ledger => _pairLedger; private void PublishPairDataChanged(bool groupChanged = false) { _mediator.Publish(new RefreshUiMessage()); _mediator.Publish(new PairDataChangedMessage()); if (groupChanged) { _mediator.Publish(new GroupCollectionChangedMessage()); } } private void NotifyUserOnline(PairConnection? connection, bool sendNotification) { if (connection is null) { return; } var config = _configService.Current; if (config.ShowOnlineNotifications && _logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Pair {Uid} marked online", connection.User.UID); } if (!sendNotification || !config.ShowOnlineNotifications) { return; } if (config.ShowOnlineNotificationsOnlyForIndividualPairs && (!connection.IsDirectlyPaired || connection.IsOneSided)) { return; } var note = _serverConfigurationManager.GetNoteForUid(connection.User.UID); if (config.ShowOnlineNotificationsOnlyForNamedPairs && string.IsNullOrEmpty(note)) { return; } var message = !string.IsNullOrEmpty(note) ? $"{note} ({connection.User.AliasOrUID}) is now online" : $"{connection.User.AliasOrUID} is now online"; _mediator.Publish(new NotificationMessage("User online", message, NotificationType.Info, TimeSpan.FromSeconds(5))); } private void ReapplyLastKnownData(string userId, string ident, bool forced = false) { var result = _handlerRegistry.ApplyLastReceivedData(new PairUniqueIdentifier(userId), ident, forced); if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Failed to reapply cached data for {Uid}: {Error}", userId, result.Error); } } private void HandleActiveServerChange(string serverUrl) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Active server changed to {Server}", serverUrl); } ResetPairState(); } private void HandleDisconnected() { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Lightless disconnected, clearing pair state"); } ResetPairState(); } private void ResetPairState() { _handlerRegistry.ResetAllHandlers(); _pairManager.ClearAll(); _pendingCharacterData.Clear(); _mediator.Publish(new ClearProfileUserDataMessage()); _mediator.Publish(new ClearProfileGroupDataMessage()); PublishPairDataChanged(groupChanged: true); } }