// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Threading.Tasks; using StackExchange.Redis; namespace EpicGames.Redis { /// /// Subscription to a /// public sealed class RedisSubscription : IDisposable, IAsyncDisposable { ISubscriber? _subscriber; readonly RedisChannel _channel; readonly Action _handler; /// /// Accessor for the channel /// public RedisChannel Channel => _channel; /// /// Constructor /// /// The channel that is subscribed to /// Callback method public RedisSubscription(RedisChannel channel, Action handler) { _channel = channel; _handler = handler; } /// public void Dispose() { _ = UnsubscribeAsync(CommandFlags.FireAndForget); } /// public async ValueTask DisposeAsync() { await UnsubscribeAsync(); } /// /// Subscribes to the channel /// /// Connection to use for the subscription /// Flags for the operation public async Task SubscribeAsync(ISubscriber subscriber, CommandFlags flags = CommandFlags.None) { if (_subscriber != null) { throw new InvalidOperationException("Cannot subscribe to a connection while a subscription is already active"); } _subscriber = subscriber; await subscriber.SubscribeAsync(_channel, _handler, flags); } /// /// Unsubscribe from the channel /// /// Flags for the operation public async Task UnsubscribeAsync(CommandFlags flags = CommandFlags.None) { if (_subscriber != null) { await _subscriber.UnsubscribeAsync(_channel, _handler, flags); _subscriber = null; } } } /// /// Extension methods for typed lists /// public static class RedisSubscriptionExtensions { #region SubscribeAsync /// public static Task SubscribeAsync(this IConnectionMultiplexer connection, RedisChannel channel, Action handler, CommandFlags flags = CommandFlags.None) { return SubscribeAsync(connection, channel, (_, v) => handler(v), flags); } /// public static async Task SubscribeAsync(this IConnectionMultiplexer connection, RedisChannel channel, Action handler, CommandFlags flags = CommandFlags.None) { RedisSubscription subscription = new RedisSubscription(channel, handler); await subscription.SubscribeAsync(connection.GetSubscriber(), flags); return subscription; } /// public static Task SubscribeAsync(this IConnectionMultiplexer connection, RedisChannel channel, Action handler, CommandFlags flags = CommandFlags.None) { void Action(RedisChannel _, RedisValue v) => handler(RedisSerializer.Deserialize(v)); return SubscribeAsync(connection, channel.Channel, Action, flags); } /// public static Task SubscribeAsync(this IConnectionMultiplexer connection, RedisChannel channel, Action, T> handler, CommandFlags flags = CommandFlags.None) { void Action(RedisChannel _, RedisValue v) => handler(channel, RedisSerializer.Deserialize(v)); return SubscribeAsync(connection, channel.Channel, Action, flags); } #endregion } }