private bool LeaveGroupWithAckMessageEqual(LeaveGroupWithAckMessage x, LeaveGroupWithAckMessage y)
 {
     return(StringEqual(x.ConnectionId, y.ConnectionId) &&
            StringEqual(x.GroupName, y.GroupName) &&
            x.AckId == y.AckId &&
            x.TracingId == y.TracingId);
 }
Example #2
0
 public static void StartToRemoveConnectionFromGroup(ILogger logger, LeaveGroupWithAckMessage message)
 {
     if (!Enabled())
     {
         return;
     }
     _startToRemoveConnectionFromGroup(logger, message.TracingId, message.ConnectionId, message.GroupName, null);
 }
Example #3
0
        public override Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default)
        {
            if (IsInvalidArgument(connectionId))
            {
                throw new ArgumentException(NullOrEmptyStringErrorMessage, nameof(connectionId));
            }

            if (IsInvalidArgument(groupName))
            {
                throw new ArgumentException(NullOrEmptyStringErrorMessage, nameof(groupName));
            }

            var message = new LeaveGroupWithAckMessage(connectionId, groupName);

            return(ServiceConnectionContainer.WriteAckableMessageAsync(message, cancellationToken));
        }
Example #4
0
        public override Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default)
        {
            if (IsInvalidArgument(connectionId))
            {
                throw new ArgumentException(NullOrEmptyStringErrorMessage, nameof(connectionId));
            }

            if (IsInvalidArgument(groupName))
            {
                throw new ArgumentException(NullOrEmptyStringErrorMessage, nameof(groupName));
            }

            var message = new LeaveGroupWithAckMessage(connectionId, groupName).WithTracingId();

            Log.StartToRemoveConnectionFromGroup(Logger, message);
            return(WriteAckableMessageAsync(message));
        }
        public IEnumerable <AppMessage> GetMessages(Message message)
        {
            if (message.IsCommand)
            {
                var command = _serializer.Parse <Command>(message.Value, message.Encoding);
                switch (command.CommandType)
                {
                case CommandType.AddToGroup:
                {
                    // name is hg-{HubName}.{GroupName}, consider the whole as the actual group name
                    // this message always goes through the appName-connection
                    var groupName               = command.Value;
                    var connectionId            = GetName(message.Key, PrefixHelper.ConnectionIdPrefix);
                    var joinGroupWithAckMessage = new JoinGroupWithAckMessage(connectionId, groupName).WithTracingId();
                    if (joinGroupWithAckMessage.TracingId != null)
                    {
                        MessageLog.StartToAddConnectionToGroup(_logger, joinGroupWithAckMessage);
                    }

                    // go through the app connection
                    // use groupName as the partitionkey so that commands towards the same group always goes into the same service connection
                    yield return(new AppMessage(joinGroupWithAckMessage, message));

                    yield break;
                }

                case CommandType.RemoveFromGroup:
                {
                    // this message always goes through the appName-connection
                    var groupName                = command.Value;
                    var connectionId             = GetName(message.Key, PrefixHelper.ConnectionIdPrefix);
                    var leaveGroupWithAckMessage = new LeaveGroupWithAckMessage(connectionId, groupName).WithTracingId();
                    if (leaveGroupWithAckMessage.TracingId != null)
                    {
                        MessageLog.StartToRemoveConnectionFromGroup(_logger, leaveGroupWithAckMessage);
                    }

                    // go through the app connection
                    // use groupName as the partitionkey so that commands towards the same group always goes into the same service connection
                    yield return(new AppMessage(leaveGroupWithAckMessage, message));

                    yield break;
                }

                case CommandType.Initializing:
                    yield break;

                case CommandType.Abort:
                    yield break;
                }
            }

            var segment = GetPayload(message);

            // broadcast case
            if (TryGetName(message.Key, PrefixHelper.HubPrefix, out var hubName))
            {
                var broadcastDataMessage = new BroadcastDataMessage(excludedList: GetExcludedIds(message.Filter), payloads: GetPayloads(segment)).WithTracingId();
                if (broadcastDataMessage.TracingId != null)
                {
                    MessageLog.StartToBroadcastMessage(_logger, broadcastDataMessage);
                }
                yield return(new HubMessage(hubName, broadcastDataMessage, message));
            }
            // echo case
            else if (TryGetName(message.Key, PrefixHelper.HubConnectionIdPrefix, out _))
            {
                // naming: hc-{HubName}.{ConnectionId}
                // ConnectionId can NEVER contain .
                var index = message.Key.LastIndexOf('.');
                if (index < 0 || index == message.Key.Length - 1)
                {
                    throw new ArgumentException($"Key must contain '.' in between but it is not: {message.Key}");
                }

                var connectionId = message.Key.Substring(index + 1);

                var connectionDataMessage = new ConnectionDataMessage(connectionId, segment).WithTracingId();
                if (connectionDataMessage.TracingId != null)
                {
                    MessageLog.StartToSendMessageToConnection(_logger, connectionDataMessage);
                }

                // Go through the app connection
                yield return(new AppMessage(connectionDataMessage, message));
            }
            // group broadcast case
            else if (TryGetName(message.Key, PrefixHelper.HubGroupPrefix, out _))
            {
                // naming: hg-{HubName}.{GroupName}, it as a whole is the group name per the JoinGroup implementation
                // go through the app connection
                // use groupName as the partitionkey so that commands towards the same group always goes into the same service connection
                var groupName = message.Key;
                var groupBroadcastDataMessage = new GroupBroadcastDataMessage(groupName, excludedList: GetExcludedIds(message.Filter), payloads: GetPayloads(segment)).WithTracingId();
                if (groupBroadcastDataMessage.TracingId != null)
                {
                    MessageLog.StartToBroadcastMessageToGroup(_logger, groupBroadcastDataMessage);
                }
                yield return(new AppMessage(groupBroadcastDataMessage, message));
            }
            // user case
            else if (TryGetName(message.Key, PrefixHelper.HubUserPrefix, out var userWithHubPrefix))
            {
                // naming: hu-{HubName}.{UserName}, HubName can contain '.' and UserName can contain '.'
                // Go through all the possibilities
                foreach (var(hub, user) in GetPossibleNames(userWithHubPrefix))
                {
                    var userDataMessage = new UserDataMessage(user, GetPayloads(segment)).WithTracingId();
                    if (userDataMessage.TracingId != null)
                    {
                        MessageLog.StartToSendMessageToUser(_logger, userDataMessage);
                    }
                    // For old protocol, it is always single user per message https://github.com/SignalR/SignalR/blob/dev/src/Microsoft.AspNet.SignalR.Core/Infrastructure/Connection.cs#L162
                    yield return(new HubMessage(hub, userDataMessage, message));
                }
            }
            else
            {
                throw new NotSupportedException($"Message {message.Key} is not supported.");
            }
        }