The most idiomatic way to consume LCU event messages would probably be trough event though they might be too advanced so a backup solution by still providing ReceiveAsync?
Current working code:
internal delegate void LeagueClientEventHandler<in T>(LcuClient sender, T args);
internal class LcuClient : LeagueClient
{
private readonly ConcurrentDictionary<string, Action<JsonElement>> _subscriptions = new();
private readonly SemaphoreSlim _connectionLock = new(1, 1);
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly JsonSerializerOptions _jsonSerializerOptions = new() {PropertyNameCaseInsensitive = true};
protected void Subscribe<T>(string topic, Action<T> handler) => Task.Run(async () =>
{
await _connectionLock.WaitAsync();
try
{
if (_subscriptions.IsEmpty) // Then the connection is closed.
{
_cancellationTokenSource.TryReset();
await WampClient.ConnectAsync(); // TODO: CancellationToken
_ = Task.Run(async () =>
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
var response = await this.WampClient.ReceiveAsync(_cancellationTokenSource.Token);
if (!_subscriptions.TryGetValue(response.Topic, out var subscriber)) continue;
subscriber?.Invoke(response.Data);
}
}, _cancellationTokenSource.Token).ConfigureAwait(false);
}
}
finally
{
_connectionLock.Release();
}
if (_subscriptions.TryAdd(topic,
data => handler.Invoke(data.Deserialize<T>(_jsonSerializerOptions) ??
throw new LeagueClientException("Couldn't deserialize the event payload."))))
await WampClient.SubscribeAsync(topic);
}).ConfigureAwait(false);
protected void Unsubscribe(string topic) => Task.Run(async () =>
{
await WampClient.UnsubscribeAsync("OnJsonApiEvent_lol-champ-select_v1_session");
_subscriptions.Remove(topic, out _);
await _connectionLock.WaitAsync();
try
{
if (_subscriptions.IsEmpty) // Then the connection should be closed.
{
_cancellationTokenSource.Cancel();
await WampClient.CloseAsync();
}
}
finally
{
_connectionLock.Release();
}
}).ConfigureAwait(false);
private event LeagueClientEventHandler<LolChampSelectChampSelectSession>? _onChampSelectSessionChanged;
public event LeagueClientEventHandler<LolChampSelectChampSelectSession>? OnChampSelectSessionChanged
{
add
{
if (_onChampSelectSessionChanged == null)
Subscribe("OnJsonApiEvent_lol-champ-select_v1_session",
(LolChampSelectChampSelectSession args) => _onChampSelectSessionChanged?.Invoke(this, args));
_onChampSelectSessionChanged += value;
}
remove
{
_onChampSelectSessionChanged -= value;
if (_onChampSelectSessionChanged == null)
Unsubscribe("OnJsonApiEvent_lol-champ-select_v1_session");
}
}
}
The most idiomatic way to consume LCU event messages would probably be trough
event
though they might be too advanced so a backup solution by still providingReceiveAsync
?Current working code:
with a test app: