private Task SubscribeToUser(HubConnectionContext connection) { var userChannel = _channels.User(connection.UserIdentifier); return(_users.AddSubscriptionAsync(userChannel, connection, async(channelName, subscriptions) => { RedisLog.Subscribing(_logger, channelName); var channel = await _bus.SubscribeAsync(channelName); channel.OnMessage(async channelMessage => { try { var invocation = _protocol.ReadInvocation((byte[])channelMessage.Message); var tasks = new List <Task>(); foreach (var userConnection in subscriptions) { tasks.Add(userConnection.WriteAsync(invocation.Message).AsTask()); } await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } }); })); }
private Task SubscribeToGroupAsync(string groupChannel, HubConnectionStore groupConnections) { RedisLog.Subscribing(_logger, groupChannel); var server = _options.ServerResovler.Resolve(_shardingServers, groupChannel); return(server.Subscriber.SubscribeAsync(groupChannel, async(_, data) => { try { var invocation = _protocol.ReadInvocation((byte[])data); var tasks = groupConnections.AsEnumerable() .Where(connection => { if (invocation.ExcludedConnectionIds == null) { return true; } return !invocation.ExcludedConnectionIds.Contains(connection.ConnectionId); }) .Select(connection => { var task = connection.WriteAsync(invocation.Message); return task.AsTask(); }); await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } })); }
private async Task SubscribeToGroupAsync(string groupChannel, HubConnectionStore groupConnections) { RedisLog.Subscribing(_logger, groupChannel); var channel = await _bus.SubscribeAsync(groupChannel); channel.OnMessage(async(channelMessage) => { try { var invocation = _protocol.ReadInvocation((byte[])channelMessage.Message); var tasks = new List <Task>(); foreach (var groupConnection in groupConnections) { if (invocation.ExcludedConnectionIds?.Contains(groupConnection.ConnectionId) == true) { continue; } tasks.Add(groupConnection.WriteAsync(invocation.Message).AsTask()); } await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } }); }
/// <inheritdoc /> public override Task OnDisconnectedAsync(HubConnectionContext connection) { _connections.Remove(connection); var tasks = new List <Task>(); var connectionChannel = _channels.Connection(connection.ConnectionId); RedisLog.Unsubscribe(_logger, connectionChannel); tasks.Add(_bus !.UnsubscribeAsync(connectionChannel)); var feature = connection.Features.Get <IRedisFeature>() !; var groupNames = feature.Groups; if (groupNames != null) { // Copy the groups to an array here because they get removed from this collection // in RemoveFromGroupAsync foreach (var group in groupNames.ToArray()) { // Use RemoveGroupAsyncCore because the connection is local and we don't want to // accidentally go to other servers with our remove request. tasks.Add(RemoveGroupAsyncCore(connection, group)); } } if (!string.IsNullOrEmpty(connection.UserIdentifier)) { tasks.Add(RemoveUserAsync(connection)); } return(Task.WhenAll(tasks)); }
private async Task PublishAsync(string channel, byte[] payload) { await EnsureRedisServerConnection(); RedisLog.PublishToChannel(_logger, channel); await _bus !.PublishAsync(channel, payload); }
private Task SubscribeToUser(HubConnectionContext connection) { if (string.IsNullOrEmpty(connection.UserIdentifier)) { return(Task.CompletedTask); } var userChannel = _channels.User(connection.UserIdentifier); return(_users.AddSubscriptionAsync(userChannel, connection, async(channelName, subscriptions) => { var server = _options.ServerResovler.Resolve(_shardingServers, channelName); await server.Subscriber.SubscribeAsync(channelName, async(_, data) => { try { var invocation = _protocol.ReadInvocation((byte[])data); var tasks = subscriptions.AsEnumerable().Select(connectionContext => { var task = connectionContext.WriteAsync(invocation.Message); return task.AsTask(); }); await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } }); })); }
private void SubscribeToGroupManagementChannel(IRedisServer server) => server.Subscriber.Subscribe(_channels.GroupManagement, async(_, data) => { try { var groupMessage = _protocol.ReadGroupCommand((byte[])data); var connection = _connections[groupMessage.ConnectionId]; if (connection == null) { // user not on this server return; } if (groupMessage.Action == GroupAction.Remove) { await RemoveGroupAsyncCore(connection, groupMessage.GroupName); } if (groupMessage.Action == GroupAction.Add) { await AddGroupAsyncCore(connection, groupMessage.GroupName); } // Send an ack to the server that sent the original command. await PublishAsync(server, _channels.Ack(groupMessage.ServerName), _protocol.WriteAck(groupMessage.Id)); } catch (Exception ex) { RedisLog.InternalMessageFailed(_logger, ex); } });
private void SubscribeToAll(IRedisServer server) { if (!server.IsDedicatedForAllChannel) { return; } RedisLog.Subscribing(_logger, _channels.All); server.Subscriber.Subscribe(_channels.All, async(_, data) => { try { RedisLog.ReceivedFromChannel(_logger, _channels.All); var invocation = _protocol.ReadInvocation((byte[])data); var tasks = _connections.AsEnumerable() .Where(connectionContext => { if (invocation.ExcludedConnectionIds == null) { return(true); } return(!invocation.ExcludedConnectionIds.Contains(connectionContext.ConnectionId)); }) .Select(connectionContext => connectionContext.WriteAsync(invocation.Message).AsTask()); await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } }); }
private async Task SubscribeToAll() { RedisLog.Subscribing(_logger, _channels.All); var channel = await _bus.SubscribeAsync(_channels.All); channel.OnMessage(async channelMessage => { try { RedisLog.ReceivedFromChannel(_logger, _channels.All); var invocation = _protocol.ReadInvocation((byte[])channelMessage.Message); var tasks = new List <Task>(_connections.Count); foreach (var connection in _connections) { if (invocation.ExcludedConnectionIds == null || !invocation.ExcludedConnectionIds.Contains(connection.ConnectionId)) { tasks.Add(connection.WriteAsync(invocation.Message).AsTask()); } } await Task.WhenAll(tasks); } catch (Exception ex) { RedisLog.FailedWritingMessage(_logger, ex); } }); }
private async Task PublishAsync(IRedisServer server, string channel, byte[] payload) { await EnsureRedisServerConnection(); RedisLog.PublishToChannel(_logger, channel); await server.Subscriber.PublishAsync(channel, payload); }
private async Task EnsureRedisServerConnection() { if (_redisServerConnection == null) { await _connectionLock.WaitAsync(); try { if (_redisServerConnection == null) { var writer = new LoggerTextWriter(_logger); _redisServerConnection = await _options.ConnectAsync(writer); _bus = _redisServerConnection.GetSubscriber(); _redisServerConnection.ConnectionRestored += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionRestored(_logger); }; _redisServerConnection.ConnectionFailed += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionFailed(_logger, e.Exception); }; if (_redisServerConnection.IsConnected) { RedisLog.Connected(_logger); } else { RedisLog.NotConnected(_logger); } await SubscribeToAll(); await SubscribeToGroupManagementChannel(); await SubscribeToAckChannel(); } } finally { _connectionLock.Release(); } } }
/// <summary> /// This takes <see cref="HubConnectionContext"/> because we want to remove the connection from the /// _connections list in OnDisconnectedAsync and still be able to remove groups with this method. /// </summary> private async Task RemoveGroupAsyncCore(HubConnectionContext connection, string groupName) { var groupChannel = _channels.Group(groupName); await _groups.RemoveSubscriptionAsync(groupChannel, connection, channelName => { RedisLog.Unsubscribe(_logger, channelName); return(_bus !.UnsubscribeAsync(channelName)); });
private Task RemoveUserAsync(HubConnectionContext connection) { var userChannel = _channels.User(connection.UserIdentifier); return(_users.RemoveSubscriptionAsync(userChannel, connection, channelName => { RedisLog.Unsubscribe(_logger, channelName); return _bus.UnsubscribeAsync(channelName); })); }
public static string JsonSerialize(RedisLog obj) { try { /*if (isWindows) return Jil.JSON.Serialize(obj, options); else*/ return JsonConvert.SerializeObject(obj); } catch { return JsonConvert.SerializeObject(obj); } }
private Task RemoveUserAsync(HubConnectionContext connection) { var userChannel = _channels.User(connection.UserIdentifier); return(_users.RemoveSubscriptionAsync(userChannel, connection, async channelName => { RedisLog.Unsubscribe(_logger, channelName); var server = _options.ServerResovler.Resolve(_shardingServers, channelName); await server.Subscriber.UnsubscribeAsync(channelName); })); }
private Task SubscribeToConnection(HubConnectionContext connection) { var channel = _channels.Connection(connection.ConnectionId); RedisLog.Subscribing(_logger, channel); var server = _options.ServerResovler.Resolve(_shardingServers, channel); return(server.Subscriber.SubscribeAsync(channel, async(c, data) => { var invocation = _protocol.ReadInvocation((byte[])data); await connection.WriteAsync(invocation.Message); })); }
private async Task SubscribeToConnection(HubConnectionContext connection) { var connectionChannel = _channels.Connection(connection.ConnectionId); RedisLog.Subscribing(_logger, connectionChannel); var channel = await _bus.SubscribeAsync(connectionChannel); channel.OnMessage(channelMessage => { var invocation = _protocol.ReadInvocation((byte[])channelMessage.Message); return(connection.WriteAsync(invocation.Message).AsTask()); }); }
public RedisHubLifetimeManager(ILogger <RedisHubLifetimeManager <THub> > logger, IOptions <RedisOptions> options, IHubProtocolResolver hubProtocolResolver) { _logger = logger; _options = options.Value; _ackHandler = new AckHandler(); _channels = new RedisChannels(typeof(THub).FullName); _protocol = new RedisProtocol(hubProtocolResolver.AllProtocols); RedisLog.ConnectingToEndpoints(_logger, options.Value.Configuration.EndPoints, _serverName); _ = EnsureRedisServerConnection(); }
private async Task EnsureRedisServerConnection() { if (_defaultServer == null || _shardingServers == null) { await _connectionLock.WaitAsync(); try { if (_defaultServer == null || _shardingServers == null) { var writer = new LoggerTextWriter(_logger); var tasks = _options.Configurations.Select(async configuration => { var serverName = _options.ServerNameGenerator.GenerateServerName(); RedisLog.ConnectingToEndpoints(_logger, configuration.Options.EndPoints, serverName); var redisConnection = await _options.ConnectAsync(configuration.Options, writer); var server = new ShardingRedisServer(serverName, configuration.IsDedicatedForAllChannel, redisConnection, _logger); SubscribeToGroupManagementChannel(server); SubscribeToAckChannel(server); return(server); }).ToArray(); var redisServers = await Task.WhenAll(tasks); _defaultServer = redisServers.FirstOrDefault(server => server.IsDedicatedForAllChannel) ?? redisServers.First(); SubscribeToAll(_defaultServer); var shardingServers = redisServers.Where(server => !server.IsDedicatedForAllChannel); _shardingServers = shardingServers.ToArray(); } } finally { _connectionLock.Release(); } } }
public ShardingRedisServer(string serverName, bool isDedicatedForAllChannel, IConnectionMultiplexer serverConnection, ILogger logger) { ServerName = serverName; IsDedicatedForAllChannel = isDedicatedForAllChannel; Connection = serverConnection; Connection.ConnectionRestored += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionRestored(logger); }; Connection.ConnectionFailed += (_, e) => { // We use the subscription connection type // Ignore messages from the interactive connection (avoids duplicates) if (e.ConnectionType == ConnectionType.Interactive) { return; } RedisLog.ConnectionFailed(logger, e.Exception); }; if (Connection.IsConnected) { RedisLog.Connected(logger); } else { RedisLog.NotConnected(logger); } Subscriber = Connection.GetSubscriber(); }
/// <summary> /// This takes <see cref="HubConnectionContext"/> because we want to remove the connection from the /// _connections list in OnDisconnectedAsync and still be able to remove groups with this method. /// </summary> private async Task RemoveGroupAsyncCore(HubConnectionContext connection, string groupName) { var groupChannel = _channels.Group(groupName); await _groups.RemoveSubscriptionAsync(groupChannel, connection, channelName => { RedisLog.Unsubscribe(_logger, channelName); return(_bus.UnsubscribeAsync(channelName)); }); var feature = connection.Features.Get <IRedisFeature>(); var groupNames = feature.Groups; if (groupNames != null) { lock (groupNames) { groupNames.Remove(groupName); } } }
/// <summary> /// This takes <see cref="HubConnectionContext"/> because we want to remove the connection from the /// _connections list in OnDisconnectedAsync and still be able to remove groups with this method. /// </summary> private async Task RemoveGroupAsyncCore(HubConnectionContext connection, string groupName) { var groupChannel = _channels.Group(groupName); await _groups.RemoveSubscriptionAsync(groupChannel, connection, async channelName => { RedisLog.Unsubscribe(_logger, channelName); var server = _options.ServerResovler.Resolve(_shardingServers, groupName); await server.Subscriber.UnsubscribeAsync(channelName); }); var feature = connection.Features.Get <IRedisFeature>(); var groupNames = feature.Groups; if (groupNames != null) { lock (groupNames) { groupNames.Remove(groupName); } } }
/// <summary> /// Constructs the <see cref="RedisHubLifetimeManager{THub}"/> with types from Dependency Injection. /// </summary> /// <param name="logger">The logger to write information about what the class is doing.</param> /// <param name="options">The <see cref="RedisOptions"/> that influence behavior of the Redis connection.</param> /// <param name="hubProtocolResolver">The <see cref="IHubProtocolResolver"/> to get an <see cref="IHubProtocol"/> instance when writing to connections.</param> /// <param name="globalHubOptions">The global <see cref="HubOptions"/>.</param> /// <param name="hubOptions">The <typeparamref name="THub"/> specific options.</param> public RedisHubLifetimeManager(ILogger <RedisHubLifetimeManager <THub> > logger, IOptions <RedisOptions> options, IHubProtocolResolver hubProtocolResolver, IOptions <HubOptions>?globalHubOptions, IOptions <HubOptions <THub> >?hubOptions) { _logger = logger; _options = options.Value; _ackHandler = new AckHandler(); _channels = new RedisChannels(typeof(THub).FullName !); if (globalHubOptions != null && hubOptions != null) { _protocol = new RedisProtocol(new DefaultHubMessageSerializer(hubProtocolResolver, globalHubOptions.Value.SupportedProtocols, hubOptions.Value.SupportedProtocols)); } else { var supportedProtocols = hubProtocolResolver.AllProtocols.Select(p => p.Name).ToList(); _protocol = new RedisProtocol(new DefaultHubMessageSerializer(hubProtocolResolver, supportedProtocols, null)); } RedisLog.ConnectingToEndpoints(_logger, options.Value.Configuration.EndPoints, _serverName); _ = EnsureRedisServerConnection(); }
protected override async void OnWriteLog(DateTime time, string assembly, string runningClass, string runningMethod, LogType type, string msg, Exception exception) { try { var obj = new RedisLog() { time = time, assembly = assembly, obj = runningClass, method = runningMethod, type = type.ToString(), msg = msg, exception = GetExceptionDetailMessage(exception) }; var json = JsonSerialize(obj); provider.ListLeftPushAsync("fastlog", json); provider.ListTrimForget("fastlog", 0, mMaxCount); } catch (Exception ex) { mLogWriter?.WriteLine(GetExceptionDetailMessage(ex)); mLogWriter?.Flush(); this.OnPrepare(); } }
public override void WriteLine(string value) { RedisLog.ConnectionMultiplexerMessage(_logger, value); }