Update UI & Syncshell Public & MCDF Share
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
|
||||
using System.Text.RegularExpressions;
|
||||
using MareSynchronos.MareConfiguration.Models;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.Notifications;
|
||||
using MareSynchronos.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -14,17 +15,19 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
||||
private readonly MareMediator _mediator;
|
||||
private readonly ApiController _api;
|
||||
private readonly AutoDetectRequestService _requestService;
|
||||
private readonly NotificationTracker _notificationTracker;
|
||||
private readonly ConcurrentDictionary<string, string> _pending = new(StringComparer.Ordinal);
|
||||
private static readonly TimeSpan RegexTimeout = TimeSpan.FromSeconds(1);
|
||||
private static readonly Regex ReqRegex = new(@"^Nearby Request: .+ \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled | RegexOptions.ExplicitCapture, RegexTimeout);
|
||||
private static readonly Regex AcceptRegex = new(@"^Nearby Accept: .+ \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled | RegexOptions.ExplicitCapture, RegexTimeout);
|
||||
|
||||
public NearbyPendingService(ILogger<NearbyPendingService> logger, MareMediator mediator, ApiController api, AutoDetectRequestService requestService)
|
||||
public NearbyPendingService(ILogger<NearbyPendingService> logger, MareMediator mediator, ApiController api, AutoDetectRequestService requestService, NotificationTracker notificationTracker)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
_api = api;
|
||||
_requestService = requestService;
|
||||
_notificationTracker = notificationTracker;
|
||||
_mediator.Subscribe<NotificationMessage>(this, OnNotification);
|
||||
_mediator.Subscribe<ManualPairInviteMessage>(this, OnManualPairInvite);
|
||||
}
|
||||
@@ -46,6 +49,7 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
||||
_ = _api.UserAddPair(new MareSynchronos.API.Dto.User.UserDto(new MareSynchronos.API.Data.UserData(uidA)));
|
||||
_pending.TryRemove(uidA, out _);
|
||||
_requestService.RemovePendingRequestByUid(uidA);
|
||||
_notificationTracker.Remove(NotificationCategory.AutoDetect, uidA);
|
||||
_logger.LogInformation("NearbyPending: auto-accepted pairing with {uid}", uidA);
|
||||
}
|
||||
return;
|
||||
@@ -67,6 +71,7 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
||||
catch { name = uid; }
|
||||
_pending[uid] = name;
|
||||
_logger.LogInformation("NearbyPending: received request from {uid} ({name})", uid, name);
|
||||
_notificationTracker.Upsert(NotificationEntry.AutoDetect(uid, name));
|
||||
}
|
||||
|
||||
private void OnManualPairInvite(ManualPairInviteMessage msg)
|
||||
@@ -81,12 +86,14 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
||||
_pending[msg.SourceUid] = display;
|
||||
_logger.LogInformation("NearbyPending: received manual invite from {uid} ({name})", msg.SourceUid, display);
|
||||
_mediator.Publish(new NotificationMessage("Nearby request", $"{display} vous a envoyé une invitation de pair.", NotificationType.Info, TimeSpan.FromSeconds(5)));
|
||||
_notificationTracker.Upsert(NotificationEntry.AutoDetect(msg.SourceUid, display));
|
||||
}
|
||||
|
||||
public void Remove(string uid)
|
||||
{
|
||||
_pending.TryRemove(uid, out _);
|
||||
_requestService.RemovePendingRequestByUid(uid);
|
||||
_notificationTracker.Remove(NotificationCategory.AutoDetect, uid);
|
||||
}
|
||||
|
||||
public async Task<bool> AcceptAsync(string uid)
|
||||
@@ -97,6 +104,7 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
||||
_pending.TryRemove(uid, out _);
|
||||
_requestService.RemovePendingRequestByUid(uid);
|
||||
_ = _requestService.SendAcceptNotifyAsync(uid);
|
||||
_notificationTracker.Remove(NotificationCategory.AutoDetect, uid);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
146
MareSynchronos/Services/AutoDetect/SyncshellDiscoveryService.cs
Normal file
146
MareSynchronos/Services/AutoDetect/SyncshellDiscoveryService.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MareSynchronos.API.Data;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.WebAPI;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Services.AutoDetect;
|
||||
|
||||
public sealed class SyncshellDiscoveryService : IHostedService, IMediatorSubscriber
|
||||
{
|
||||
private readonly ILogger<SyncshellDiscoveryService> _logger;
|
||||
private readonly MareMediator _mediator;
|
||||
private readonly ApiController _apiController;
|
||||
private readonly SemaphoreSlim _refreshSemaphore = new(1, 1);
|
||||
private readonly object _entriesLock = new();
|
||||
private List<SyncshellDiscoveryEntryDto> _entries = [];
|
||||
private string? _lastError;
|
||||
private bool _isRefreshing;
|
||||
|
||||
public SyncshellDiscoveryService(ILogger<SyncshellDiscoveryService> logger, MareMediator mediator, ApiController apiController)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
_apiController = apiController;
|
||||
}
|
||||
|
||||
public MareMediator Mediator => _mediator;
|
||||
|
||||
public IReadOnlyList<SyncshellDiscoveryEntryDto> Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_entriesLock)
|
||||
{
|
||||
return _entries.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRefreshing => _isRefreshing;
|
||||
public string? LastError => _lastError;
|
||||
|
||||
public async Task<bool> JoinAsync(string gid, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _apiController.SyncshellDiscoveryJoin(new GroupDto(new GroupData(gid))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Join syncshell discovery failed for {gid}", gid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<SyncshellDiscoveryStateDto?> GetStateAsync(string gid, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _apiController.SyncshellDiscoveryGetState(new GroupDto(new GroupData(gid))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to fetch syncshell discovery state for {gid}", gid);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> SetVisibilityAsync(string gid, bool visible, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = new SyncshellDiscoveryVisibilityRequestDto
|
||||
{
|
||||
GID = gid,
|
||||
AutoDetectVisible = visible,
|
||||
};
|
||||
var success = await _apiController.SyncshellDiscoverySetVisibility(request).ConfigureAwait(false);
|
||||
if (!success) return false;
|
||||
|
||||
var state = await GetStateAsync(gid, ct).ConfigureAwait(false);
|
||||
if (state != null)
|
||||
{
|
||||
_mediator.Publish(new SyncshellAutoDetectStateChanged(state.GID, state.AutoDetectVisible, state.PasswordTemporarilyDisabled));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to set syncshell visibility for {gid}", gid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RefreshAsync(CancellationToken ct)
|
||||
{
|
||||
if (!await _refreshSemaphore.WaitAsync(0, ct).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_isRefreshing = true;
|
||||
var discovered = await _apiController.SyncshellDiscoveryList().ConfigureAwait(false);
|
||||
lock (_entriesLock)
|
||||
{
|
||||
_entries = discovered ?? [];
|
||||
}
|
||||
_lastError = null;
|
||||
_mediator.Publish(new SyncshellDiscoveryUpdated(Entries.ToList()));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to refresh syncshell discovery list");
|
||||
_lastError = ex.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isRefreshing = false;
|
||||
_refreshSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_mediator.Subscribe<ConnectedMessage>(this, msg =>
|
||||
{
|
||||
_ = RefreshAsync(CancellationToken.None);
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_mediator.UnsubscribeAll(this);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user