Пример #1
0
        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);
                }
            }));
        }
Пример #3
0
        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);
                }
            });
        }
Пример #4
0
        /// <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));
        }
Пример #5
0
        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);
                }
            });
        }
Пример #9
0
        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);
        }
Пример #11
0
        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();
                }
            }
        }
Пример #12
0
        /// <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));
            });
Пример #13
0
        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);
            }));
        }
Пример #14
0
 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);
            }));
        }
Пример #17
0
        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());
            });
        }
Пример #18
0
        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();
                }
            }
        }
Пример #20
0
        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();
        }
Пример #21
0
        /// <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);
                }
            }
        }
Пример #23
0
        /// <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();
        }
Пример #24
0
        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();
            }
        }
Пример #25
0
 public override void WriteLine(string value)
 {
     RedisLog.ConnectionMultiplexerMessage(_logger, value);
 }