159 lines
5.1 KiB
C#
159 lines
5.1 KiB
C#
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)
|
|
{
|
|
return await SetVisibilityAsync(gid, visible, null, null, null, null, null, ct).ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<bool> SetVisibilityAsync(string gid, bool visible, int? displayDurationHours,
|
|
int[]? activeWeekdays, TimeSpan? timeStartLocal, TimeSpan? timeEndLocal, string? timeZone,
|
|
CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var request = new SyncshellDiscoveryVisibilityRequestDto
|
|
{
|
|
GID = gid,
|
|
AutoDetectVisible = visible,
|
|
DisplayDurationHours = displayDurationHours,
|
|
ActiveWeekdays = activeWeekdays,
|
|
TimeStartLocal = timeStartLocal.HasValue ? new DateTime(timeStartLocal.Value.Ticks).ToString("HH:mm") : null,
|
|
TimeEndLocal = timeEndLocal.HasValue ? new DateTime(timeEndLocal.Value.Ticks).ToString("HH:mm") : null,
|
|
TimeZone = timeZone,
|
|
};
|
|
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;
|
|
}
|
|
}
|