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); } }
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(); }
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); }
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); } }
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); } }
protected override async Task OnMessageAsync(ConnectionDataMessage connectionDataMessage) { await base.OnMessageAsync(connectionDataMessage); var tcs = _waitForApplicationMessage.GetOrAdd(connectionDataMessage.ConnectionId, i => new TaskCompletionSource <ServiceMessage>()); tcs.TrySetResult(connectionDataMessage); }
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); }
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)))); } }
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); } } }
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); } }
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); } }
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())); }
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); }
protected override Task OnMessageAsync(ConnectionDataMessage connectionDataMessage) { return(Task.CompletedTask); }
public static void ReceiveMessageFromService(ILogger logger, ConnectionDataMessage message) { _receivedMessageFromService(logger, message.TracingId, message.ConnectionId, null); }
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."); } }
protected override Task OnClientMessageAsync(ConnectionDataMessage connectionDataMessage) { return(ForwardMessageToApplication(connectionDataMessage.ConnectionId, connectionDataMessage)); }
protected abstract Task OnMessageAsync(ConnectionDataMessage connectionDataMessage);
public static void FailToWriteMessageToApplication(ILogger logger, ConnectionDataMessage message, Exception exception) { _failToWriteMessageToApplication(logger, message.TracingId, message.ConnectionId, exception); }
public static void ReceivedMessageForNonExistentConnection(ILogger logger, ConnectionDataMessage message) { _receivedMessageForNonExistentConnection(logger, message.TracingId, message.ConnectionId, null); }