예제 #1
0
        protected override async Task OnMessageAsync(ConnectionDataMessage connectionDataMessage)
        {
            if (_clientConnectionManager.ClientConnections.TryGetValue(connectionDataMessage.ConnectionId, out var connection))
            {
                try
                {
                    var payload = connectionDataMessage.Payload;
                    Log.WriteMessageToApplication(_logger, payload.Length, connectionDataMessage.ConnectionId);

                    if (payload.IsSingleSegment)
                    {
                        // Write the raw connection payload to the pipe let the upstream handle it
                        await connection.Application.Output.WriteAsync(payload.First);
                    }
                    else
                    {
                        var position = payload.Start;
                        while (connectionDataMessage.Payload.TryGet(ref position, out var memory))
                        {
                            await connection.Application.Output.WriteAsync(memory);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.FailToWriteMessageToApplication(_logger, connectionDataMessage.ConnectionId, ex);
                }
            }
            else
            {
                // Unexpected error
                Log.ReceivedMessageForNonExistentConnection(_logger, connectionDataMessage.ConnectionId);
            }
        }
예제 #2
0
        public async Task WritingMultiSegmentMessageConnectionMessageWritesSingleMessage()
        {
            // 10 byte segment size
            var clientPipeOptions = new PipeOptions(minimumSegmentSize: 10);
            var proxy             = new ServiceConnectionProxy(clientPipeOptions: clientPipeOptions);

            var serverTask = proxy.WaitForServerConnectionAsync(1);

            _ = proxy.StartAsync();
            await serverTask.OrTimeout();

            var task = proxy.WaitForConnectionAsync("1");
            await proxy.WriteMessageAsync(new OpenConnectionMessage("1", null));

            var connection = await task.OrTimeout();

            var outputMessage = "This message should be more than 10 bytes";

            var dataMessageTask = proxy.WaitForApplicationMessageAsync(typeof(ConnectionDataMessage));
            await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes(outputMessage));

            ConnectionDataMessage message = (ConnectionDataMessage)await dataMessageTask.OrTimeout();

            Assert.Equal(message.ConnectionId, connection.ConnectionId);
            Assert.Equal(outputMessage, Encoding.ASCII.GetString(message.Payload.ToArray()));

            proxy.Stop();
        }
예제 #3
0
        protected override Task OnMessageAsync(ConnectionDataMessage connectionDataMessage)
        {
            if (_clientConnections.TryGetValue(connectionDataMessage.ConnectionId, out var transport))
            {
                try
                {
                    var payload = connectionDataMessage.Payload;
                    Log.WriteMessageToApplication(_logger, payload.Length, connectionDataMessage.ConnectionId);
                    var message = GetString(payload);
                    if (message == ReconnectMessage)
                    {
                        transport.Reconnected?.Invoke();
                    }
                    else
                    {
                        transport.OnReceived(message);
                    }
                }
                catch (Exception ex)
                {
                    Log.FailToWriteMessageToApplication(_logger, connectionDataMessage.ConnectionId, ex);
                }
            }
            else
            {
                // Unexpected error
                Log.ReceivedMessageForNonExistentConnection(_logger, connectionDataMessage.ConnectionId);
            }

            return(Task.CompletedTask);
        }
예제 #4
0
 protected override async Task OnClientMessageAsync(ConnectionDataMessage connectionDataMessage)
 {
     if (connectionDataMessage.TracingId != null)
     {
         MessageLog.ReceiveMessageFromService(Logger, connectionDataMessage);
     }
     if (_clientConnectionManager.ClientConnections.TryGetValue(connectionDataMessage.ConnectionId, out var connection))
     {
         try
         {
             var payload = connectionDataMessage.Payload;
             Log.WriteMessageToApplication(Logger, payload.Length, connectionDataMessage.ConnectionId);
             await connection.WriteMessageAsync(payload);
         }
         catch (Exception ex)
         {
             Log.FailToWriteMessageToApplication(Logger, connectionDataMessage, ex);
         }
     }
     else
     {
         // Unexpected error
         Log.ReceivedMessageForNonExistentConnection(Logger, connectionDataMessage);
     }
 }
예제 #5
0
        public static ReadOnlyMemory <byte> GenerateSingleFrameBuffer(this string message)
        {
            var inner = Encoding.UTF8.GetBytes(message);
            var singleFrameMessage = new ConnectionDataMessage(string.Empty, inner);

            return(DefaultServiceProtocol.GetMessageBytes(singleFrameMessage));
        }
 public static void RecieveMessageFromService(ILogger logger, ConnectionDataMessage message)
 {
     if (ClientConnectionScope.IsDiagnosticClient)
     {
         _receivedMessageFromService(logger, message.TracingId, message.ConnectionId, null);
     }
 }
예제 #7
0
        protected override async Task OnMessageAsync(ConnectionDataMessage connectionDataMessage)
        {
            await base.OnMessageAsync(connectionDataMessage);

            var tcs = _waitForApplicationMessage.GetOrAdd(connectionDataMessage.ConnectionId, i => new TaskCompletionSource <ServiceMessage>());

            tcs.TrySetResult(connectionDataMessage);
        }
예제 #8
0
 protected override Task OnClientMessageAsync(ConnectionDataMessage connectionDataMessage)
 {
     if (connectionDataMessage.TracingId != null)
     {
         MessageLog.ReceiveMessageFromService(Logger, connectionDataMessage);
     }
     return(ForwardMessageToApplication(connectionDataMessage.ConnectionId, connectionDataMessage));
 }
 public void WriteAndParseLargeData()
 {
     var protocol = new ServiceProtocol();
     var count = 70000;
     var str = new string(Enumerable.Range(0, count).Select(s => 'a').ToArray());
     var largeData = Encoding.UTF8.GetBytes(str);
     var message = new ConnectionDataMessage("abc", largeData);
     var bytes = protocol.GetMessageBytes(message);
     var seq = new ReadOnlySequence<byte>(bytes);
     var parsing = protocol.TryParseMessage(ref seq, out var result);
     Assert.Equal(count, (result as ConnectionDataMessage).Payload.Length);
 }
예제 #10
0
        public static Task WriteAsync(this IServiceConnection serviceConnection, string connectionId, object value, IServiceProtocol protocol, JsonSerializer serializer, IMemoryPool pool)
        {
            using (var writer = new MemoryPoolTextWriter(pool))
            {
                serializer.Serialize(writer, value);
                writer.Flush();

                // Reuse ConnectionDataMessage to wrap the payload
                var wrapped = new ConnectionDataMessage(string.Empty, writer.Buffer);
                return(serviceConnection.WriteAsync(new ConnectionDataMessage(connectionId, protocol.GetMessageBytes(wrapped))));
            }
        }
예제 #11
0
        public async Task SendMessage(string target, object[] args)
        {
            var callHubRequest        = new InvocationMessage(invocationId: _invId++.ToString(), target: target, arguments: args);
            var callHubServiceMessage = new ConnectionDataMessage(ConnectionId, _signalRPro.GetMessageBytes(callHubRequest));

            _servicePro.WriteMessage(callHubServiceMessage, ServiceSideConnection.MockServicePipe.Output);
            var flushResult = await ServiceSideConnection.MockServicePipe.Output.FlushAsync();

            if (flushResult.IsCanceled || flushResult.IsCompleted)
            {
                throw new InvalidOperationException($"Sending InvocationMessage {_invId} for client connection id {ConnectionId} resulted in FlushResult with IsCanceled {flushResult.IsCanceled} IsCompleted {flushResult.IsCompleted}");
            }
        }
        protected override async Task OnMessageAsync(ConnectionDataMessage connectionDataMessage)
        {
            var connectionId = connectionDataMessage.ConnectionId;

            if (_clientConnections.TryGetValue(connectionId, out var clientContext))
            {
                try
                {
                    await clientContext.Output.WriteAsync(connectionDataMessage);
                }
                catch (Exception e)
                {
                    Log.FailToWriteMessageToApplication(_logger, connectionId, e);
                }
            }
        }
예제 #13
0
        public async Task <MockServiceSideClientConnection> ConnectClientAsync()
        {
            if (!await _completedHandshake.Task)
            {
                throw new InvalidOperationException("Service connection has failed service connection handshake");
            }

            var clientConnId = SDKSideServiceConnection.ConnectionId + "_client_" + Interlocked.Increment(ref s_clientConnNum);
            MockServiceSideClientConnection clientConn = new MockServiceSideClientConnection(clientConnId, this);

            ClientConnections.Add(clientConn);

            var openClientConnMsg = new OpenConnectionMessage(clientConnId, new System.Security.Claims.Claim[] { });

            _servicePro.WriteMessage(openClientConnMsg, MockServicePipe.Output);
            var flushResult = _lastFlushResult = await MockServicePipe.Output.FlushAsync();

            if (flushResult.IsCanceled || flushResult.IsCompleted)
            {
                // any better way?
                throw new InvalidOperationException($"Sending OpenConnectionMessage for clientConnId {clientConnId} returned flush result: IsCanceled {flushResult.IsCanceled} IsCompleted {flushResult.IsCompleted}");
            }


            var clientHandshakeRequest = new AspNetCore.SignalR.Protocol.HandshakeRequestMessage("json", 1);
            var clientHandshake        = new ConnectionDataMessage(clientConnId, GetMessageBytes(clientHandshakeRequest));

            _servicePro.WriteMessage(clientHandshake, MockServicePipe.Output);
            flushResult = _lastFlushResult = await MockServicePipe.Output.FlushAsync();

            if (flushResult.IsCanceled || flushResult.IsCompleted)
            {
                throw new InvalidOperationException($"Sending HandshakeRequestMessage for clientConnId {clientConnId} returned flush result: IsCanceled {flushResult.IsCanceled} IsCompleted {flushResult.IsCompleted}");
            }

            string hsErr = await clientConn.HandshakeCompleted.Task;

            if (!string.IsNullOrEmpty(hsErr))
            {
                throw new InvalidOperationException($"client connection {clientConnId} handshake returned {hsErr}");
            }

            return(clientConn);
        }
 private ServiceMessage CreateMessage(string connectionId, string methodName, object[] args, ClientConnectionContext serviceConnectionContext)
 {
     if (serviceConnectionContext.Protocol != null)
     {
         var message = new ConnectionDataMessage(connectionId, SerializeProtocol(serviceConnectionContext.Protocol, methodName, args)).WithTracingId();
         if (message.TracingId != null)
         {
             MessageLog.StartToSendMessageToConnection(Logger, message);
         }
         return(message);
     }
     else
     {
         var message = new MultiConnectionDataMessage(new[] { connectionId }, SerializeAllProtocols(methodName, args)).WithTracingId();
         if (message.TracingId != null)
         {
             MessageLog.StartToSendMessageToConnections(Logger, message);
         }
         return(message);
     }
 }
예제 #15
0
        private void ProcessOutgoingMessages(ClientContext clientContext, ConnectionDataMessage connectionDataMessage)
        {
            var connectionId = connectionDataMessage.ConnectionId;

            try
            {
                var payload = connectionDataMessage.Payload;
                Log.WriteMessageToApplication(Logger, payload.Length, connectionId);
                var message = GetString(payload);
                if (message == ReconnectMessage)
                {
                    clientContext.Transport?.Reconnected?.Invoke();
                }
                else
                {
                    clientContext.Transport?.OnReceived(message);
                }
            }
            catch (Exception e)
            {
                Log.FailToWriteMessageToApplication(Logger, nameof(ConnectionDataMessage), connectionDataMessage.ConnectionId, e);
            }
        }
예제 #16
0
        public async Task WritingMessagesFromConnectionGetsSentAsConnectionData()
        {
            var proxy = new ServiceConnectionProxy();

            var serverTask = proxy.WaitForServerConnectionAsync(1);

            _ = proxy.StartAsync();
            await serverTask.OrTimeout();

            var task = proxy.WaitForConnectionAsync("1");
            await proxy.WriteMessageAsync(new OpenConnectionMessage("1", null));

            var connection = await task.OrTimeout();

            var dataMessageTask = proxy.WaitForApplicationMessageAsync(typeof(ConnectionDataMessage));
            await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes("Hello World"));

            ConnectionDataMessage message = (ConnectionDataMessage)await dataMessageTask.OrTimeout();

            Assert.Equal(message.ConnectionId, connection.ConnectionId);
            Assert.Equal("Hello World", Encoding.ASCII.GetString(message.Payload.ToArray()));

            proxy.Stop();
        }
 private bool ConnectionDataMessagesEqual(ConnectionDataMessage x, ConnectionDataMessage y)
 {
     return(StringEqual(x.ConnectionId, y.ConnectionId) && SequenceEqual(x.Payload.ToArray(), y.Payload.ToArray()));
 }
예제 #18
0
 public static void StartToSendMessageToConnection(ILogger logger, ConnectionDataMessage message)
 {
     _startToSendMessageToConnection(logger, message.TracingId, message.ConnectionId, null);
 }
 public async Task WriteMessageAsync(ConnectionDataMessage message)
 {
     await _serviceConnection.WriteAsync(message);
 }
예제 #20
0
 protected override Task OnMessageAsync(ConnectionDataMessage connectionDataMessage)
 {
     return(Task.CompletedTask);
 }
예제 #21
0
 public static void ReceiveMessageFromService(ILogger logger, ConnectionDataMessage message)
 {
     _receivedMessageFromService(logger, message.TracingId, message.ConnectionId, null);
 }
예제 #22
0
        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.");
            }
        }
예제 #23
0
 protected override Task OnClientMessageAsync(ConnectionDataMessage connectionDataMessage)
 {
     return(ForwardMessageToApplication(connectionDataMessage.ConnectionId, connectionDataMessage));
 }
예제 #24
0
 protected abstract Task OnMessageAsync(ConnectionDataMessage connectionDataMessage);
예제 #25
0
 public static void FailToWriteMessageToApplication(ILogger logger, ConnectionDataMessage message, Exception exception)
 {
     _failToWriteMessageToApplication(logger, message.TracingId, message.ConnectionId, exception);
 }
예제 #26
0
 public static void ReceivedMessageForNonExistentConnection(ILogger logger, ConnectionDataMessage message)
 {
     _receivedMessageForNonExistentConnection(logger, message.TracingId, message.ConnectionId, null);
 }