233 lines
7.2 KiB
C#
233 lines
7.2 KiB
C#
using LightlessSync.LightlessConfiguration.Models;
|
|
using LightlessSync.PlayerData.Pairs;
|
|
using LightlessSync.Services.Mediator;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace LightlessSync.Services;
|
|
|
|
public sealed class PairRequestService : DisposableMediatorSubscriberBase
|
|
{
|
|
private readonly DalamudUtilService _dalamudUtil;
|
|
private readonly PairManager _pairManager;
|
|
private readonly Lazy<WebAPI.ApiController> _apiController;
|
|
private readonly Lock _syncRoot = new();
|
|
private readonly List<PairRequestEntry> _requests = [];
|
|
|
|
private static readonly TimeSpan _expiration = TimeSpan.FromMinutes(5);
|
|
|
|
public PairRequestService(
|
|
ILogger<PairRequestService> logger,
|
|
LightlessMediator mediator,
|
|
DalamudUtilService dalamudUtil,
|
|
PairManager pairManager,
|
|
Lazy<WebAPI.ApiController> apiController)
|
|
: base(logger, mediator)
|
|
{
|
|
_dalamudUtil = dalamudUtil;
|
|
_pairManager = pairManager;
|
|
_apiController = apiController;
|
|
|
|
Mediator.Subscribe<PriorityFrameworkUpdateMessage>(this, _ =>
|
|
{
|
|
bool removed;
|
|
lock (_syncRoot)
|
|
{
|
|
removed = CleanupExpiredUnsafe();
|
|
}
|
|
|
|
if (removed)
|
|
{
|
|
Mediator.Publish(new PairRequestsUpdatedMessage());
|
|
}
|
|
});
|
|
}
|
|
|
|
public PairRequestDisplay RegisterIncomingRequest(string hashedCid, string messageTemplate)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(hashedCid))
|
|
{
|
|
hashedCid = string.Empty;
|
|
}
|
|
|
|
messageTemplate ??= string.Empty;
|
|
|
|
PairRequestEntry entry = new(hashedCid, messageTemplate, DateTime.UtcNow);
|
|
lock (_syncRoot)
|
|
{
|
|
CleanupExpiredUnsafe();
|
|
var index = _requests.FindIndex(r => string.Equals(r.HashedCid, hashedCid, StringComparison.Ordinal));
|
|
if (index >= 0)
|
|
{
|
|
_requests[index] = entry;
|
|
}
|
|
else
|
|
{
|
|
_requests.Add(entry);
|
|
}
|
|
}
|
|
|
|
var display = _dalamudUtil.IsOnFrameworkThread
|
|
? ToDisplay(entry)
|
|
: _dalamudUtil.RunOnFrameworkThread(() => ToDisplay(entry)).GetAwaiter().GetResult();
|
|
|
|
Mediator.Publish(new PairRequestsUpdatedMessage());
|
|
return display;
|
|
}
|
|
|
|
public IReadOnlyList<PairRequestDisplay> GetActiveRequests()
|
|
{
|
|
List<PairRequestEntry> entries;
|
|
lock (_syncRoot)
|
|
{
|
|
CleanupExpiredUnsafe();
|
|
entries = _requests
|
|
.OrderByDescending(r => r.ReceivedAt)
|
|
.ToList();
|
|
}
|
|
|
|
return _dalamudUtil.IsOnFrameworkThread
|
|
? entries.Select(ToDisplay).ToList()
|
|
: _dalamudUtil.RunOnFrameworkThread(() => entries.Select(ToDisplay).ToList()).GetAwaiter().GetResult();
|
|
}
|
|
|
|
public bool RemoveRequest(string hashedCid)
|
|
{
|
|
bool removed;
|
|
lock (_syncRoot)
|
|
{
|
|
removed = _requests.RemoveAll(r => string.Equals(r.HashedCid, hashedCid, StringComparison.Ordinal)) > 0;
|
|
}
|
|
|
|
if (removed)
|
|
{
|
|
Mediator.Publish(new PairRequestsUpdatedMessage());
|
|
}
|
|
|
|
return removed;
|
|
}
|
|
|
|
public bool HasPendingRequests()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
CleanupExpiredUnsafe();
|
|
return _requests.Count > 0;
|
|
}
|
|
}
|
|
|
|
private PairRequestDisplay ToDisplay(PairRequestEntry entry)
|
|
{
|
|
var displayName = ResolveDisplayName(entry.HashedCid);
|
|
var message = FormatMessage(entry.MessageTemplate, displayName);
|
|
return new PairRequestDisplay(entry.HashedCid, displayName, message, entry.ReceivedAt);
|
|
}
|
|
|
|
private string ResolveDisplayName(string hashedCid)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(hashedCid))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var (name, address) = _dalamudUtil.FindPlayerByNameHash(hashedCid);
|
|
if (!string.IsNullOrWhiteSpace(name))
|
|
{
|
|
var worldName = _dalamudUtil.GetWorldNameFromPlayerAddress(address);
|
|
return !string.IsNullOrWhiteSpace(worldName)
|
|
? $"{name} @ {worldName}"
|
|
: name;
|
|
}
|
|
|
|
var pair = _pairManager
|
|
.GetOnlineUserPairs()
|
|
.FirstOrDefault(p => string.Equals(p.Ident, hashedCid, StringComparison.Ordinal));
|
|
|
|
if (pair != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(pair.PlayerName))
|
|
{
|
|
return pair.PlayerName;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(pair.UserData.AliasOrUID))
|
|
{
|
|
return pair.UserData.AliasOrUID;
|
|
}
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private static string FormatMessage(string template, string displayName)
|
|
{
|
|
var safeName = string.IsNullOrWhiteSpace(displayName) ? "Someone" : displayName;
|
|
template ??= string.Empty;
|
|
const string placeholder = "{DisplayName}";
|
|
|
|
if (!string.IsNullOrEmpty(template) && template.Contains(placeholder, StringComparison.Ordinal))
|
|
{
|
|
return template.Replace(placeholder, safeName, StringComparison.Ordinal);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(template))
|
|
{
|
|
return $"{safeName}: {template}";
|
|
}
|
|
|
|
return $"{safeName} sent you a pair request.";
|
|
}
|
|
|
|
private bool CleanupExpiredUnsafe()
|
|
{
|
|
if (_requests.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var now = DateTime.UtcNow;
|
|
return _requests.RemoveAll(r => now - r.ReceivedAt > _expiration) > 0;
|
|
}
|
|
|
|
public void AcceptPairRequest(string hashedCid, string displayName)
|
|
{
|
|
_ = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
await _apiController.Value.TryPairWithContentId(hashedCid).ConfigureAwait(false);
|
|
RemoveRequest(hashedCid);
|
|
|
|
var displayText = string.IsNullOrEmpty(displayName) ? hashedCid : displayName;
|
|
Mediator.Publish(new NotificationMessage(
|
|
"Pair request accepted",
|
|
$"Sent a pair request back to {displayText}.",
|
|
NotificationType.Info,
|
|
TimeSpan.FromSeconds(3)));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Failed to accept pair request for {HashedCid}", hashedCid);
|
|
Mediator.Publish(new NotificationMessage(
|
|
"Failed to Accept Pair Request",
|
|
ex.Message,
|
|
NotificationType.Error,
|
|
TimeSpan.FromSeconds(5)));
|
|
}
|
|
});
|
|
}
|
|
|
|
public void DeclinePairRequest(string hashedCid, string displayName)
|
|
{
|
|
RemoveRequest(hashedCid);
|
|
Mediator.Publish(new NotificationMessage("Pair request declined",
|
|
"Declined " + displayName + "'s pending pair request.",
|
|
NotificationType.Info,
|
|
TimeSpan.FromSeconds(3)));
|
|
Logger.LogDebug("Declined pair request from {HashedCid}", hashedCid);
|
|
}
|
|
|
|
private record struct PairRequestEntry(string HashedCid, string MessageTemplate, DateTime ReceivedAt);
|
|
|
|
public readonly record struct PairRequestDisplay(string HashedCid, string DisplayName, string Message, DateTime ReceivedAt);
|
|
}
|