public async Task ServiceConnectionWithNormalClientConnection() { using (StartVerifiableLog(out var loggerFactory, LogLevel.Warning, expectedErrors: c => true, logChecker: logs => { Assert.Single(logs); Assert.Equal("ConnectedStartingFailed", logs[0].Write.EventId.Name); Assert.Equal("Unable to authorize request", logs[0].Write.Exception.Message); return(true); })) { var hubConfig = new HubConfiguration(); var ccm = new ClientConnectionManager(hubConfig, loggerFactory); hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm); using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory)) { // start the server connection await proxy.StartServiceAsync().OrTimeout(); var connectionId = Guid.NewGuid().ToString("N"); var connectTask = proxy.WaitForOutgoingMessageAsync(connectionId).OrTimeout(); // Application layer sends OpenConnectionMessage to an authorized hub from anonymous user var openConnectionMessage = new OpenConnectionMessage(connectionId, new Claim[0], null, "?transport=webSockets&connectionData=%5B%7B%22name%22%3A%22authchat%22%7D%5D"); await proxy.WriteMessageAsync(openConnectionMessage); var message = await connectTask; Assert.True(message is CloseConnectionMessage); // Verify client connection is not created due to authorized failure. Assert.False(ccm.ClientConnections.TryGetValue(connectionId, out var connection)); } } }
public void ParseMessageWithExtraData() { // Legacy protocol var expectedMessage = new OpenConnectionMessage("id", null); var bytes = new byte[] { ArrayBytes(3), // Array Length 4, // Message Type: OpenConnectionMessage StringBytes(2), (byte)'i', (byte)'d', // OpenConnectionMessage.ConnectionId MapBytes(0), // OpenConnectionMessage.Claims StringBytes(2), (byte)'e', (byte)'x' // Extra trailing data }; bytes = Frame(bytes); var message = ParseServiceMessage(bytes); var openConnectionMessage = Assert.IsType<OpenConnectionMessage>(message); Assert.Equal(expectedMessage, openConnectionMessage, ServiceMessageEqualityComparer.Instance); // Current protocol expectedMessage = new OpenConnectionMessage("id", null, new Dictionary<string, StringValues>(), "?k=v"); bytes = new byte[] { ArrayBytes(5), // Array Length 4, // Message Type: OpenConnectionMessage StringBytes(2), (byte)'i', (byte)'d', // OpenConnectionMessage.ConnectionId MapBytes(0), // OpenConnectionMessage.Claims MapBytes(0), // OpenConnectionMessage.Headers StringBytes(4), (byte)'?', (byte)'k', (byte)'=', (byte)'v', // OpenConnectionMessage.QueryString StringBytes(2), (byte)'e', (byte)'x' // Extra trailing data }; bytes = Frame(bytes); message = ParseServiceMessage(bytes); openConnectionMessage = Assert.IsType<OpenConnectionMessage>(message); Assert.Equal(expectedMessage, openConnectionMessage, ServiceMessageEqualityComparer.Instance); }
public Task OnClientConnectedAsyncForTest(OpenConnectionMessage message) { return(base.OnClientConnectedAsync(message)); }
public async Task TestCreateConnectionWithInvalidQueryStringThrows(string queryString) { var message = new OpenConnectionMessage(Guid.NewGuid().ToString("N"), new Claim[0], null, queryString); await Assert.ThrowsAsync <InvalidOperationException>(() => _clientConnectionManager.CreateConnection(message)); }
protected override Task OnConnectedAsync(OpenConnectionMessage openConnectionMessage) { return(Task.CompletedTask); }
public ClientConnectionContext CreateConnection(OpenConnectionMessage message, Action <HttpContext> configureContext = null) { return(new ClientConnectionContext(message, configureContext, _clientPipeOptions, _clientPipeOptions)); }
public ServiceConnectionContext CreateConnection(OpenConnectionMessage message) { return(new ServiceConnectionContext(message, _clientPipeOptions, _clientPipeOptions)); }
protected override async Task OnClientConnectedAsync(OpenConnectionMessage message) { await base.OnClientConnectedAsync(message); _clientConnectedTcs.TrySetResult(); }
protected abstract Task OnConnectedAsync(OpenConnectionMessage openConnectionMessage);
private async Task OnConnectedAsyncCore(ClientConnectionContext clientContext, OpenConnectionMessage message) { var connectionId = message.ConnectionId; try { clientContext.Transport = await _clientConnectionManager.CreateConnection(message); Log.ConnectedStarting(Logger, connectionId); } catch (Exception e) { Log.ConnectedStartingFailed(Logger, connectionId, e); // Should not wait for application task inside the application task _ = PerformDisconnectCore(connectionId, false); _ = SafeWriteAsync(new CloseConnectionMessage(connectionId, e.Message)); } }
public async Task ServiceConnectionDispatchGroupMessagesTest() { using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetActualHubConfig(loggerFactory); var appName = "app1"; var hub = "chat"; var scm = new TestServiceConnectionHandler(); hubConfig.Resolver.Register(typeof(IServiceConnectionManager), () => scm); var ccm = new ClientConnectionManager(hubConfig, loggerFactory); hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm); DispatcherHelper.PrepareAndGetDispatcher(new TestAppBuilder(), hubConfig, new ServiceOptions { ConnectionString = ConnectionString }, appName, loggerFactory); using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory)) { // start the server connection await proxy.StartServiceAsync().OrTimeout(); var clientConnection = Guid.NewGuid().ToString("N"); var connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); // Application layer sends OpenConnectionMessage var openConnectionMessage = new OpenConnectionMessage(clientConnection, new Claim[0], null, $"?transport=webSockets&connectionToken=conn1&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D"); await proxy.WriteMessageAsync(openConnectionMessage); var connectMessage = (await connectTask)as GroupBroadcastDataMessage; Assert.NotNull(connectMessage); Assert.Equal($"hg-{hub}.note", connectMessage.GroupName); var message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>(); Assert.Equal("Connected", message.A[0]); // group message goes into the manager // make sure the tcs is called before writing message var jgTask = scm.WaitForTransportOutputMessageAsync(typeof(JoinGroupWithAckMessage)).OrTimeout(); var gbTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); await proxy.WriteMessageAsync(new ConnectionDataMessage(clientConnection, Encoding.UTF8.GetBytes($"{{\"H\":\"{hub}\",\"M\":\"JoinGroup\",\"A\":[\"user1\",\"group1\"],\"I\":1}}"))); var groupMessage = (await jgTask)as JoinGroupWithAckMessage; Assert.NotNull(groupMessage); Assert.Equal($"hg-{hub}.group1", groupMessage.GroupName); var broadcastMessage = (await gbTask)as GroupBroadcastDataMessage; Assert.NotNull(broadcastMessage); Assert.Equal($"hg-{hub}.group1", broadcastMessage.GroupName); var lgTask = scm.WaitForTransportOutputMessageAsync(typeof(LeaveGroupWithAckMessage)).OrTimeout(); gbTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); await proxy.WriteMessageAsync(new ConnectionDataMessage(clientConnection, Encoding.UTF8.GetBytes($"{{\"H\":\"{hub}\",\"M\":\"LeaveGroup\",\"A\":[\"user1\",\"group1\"],\"I\":1}}"))); var leaveGroupMessage = (await lgTask)as LeaveGroupWithAckMessage; Assert.NotNull(leaveGroupMessage); Assert.Equal($"hg-{hub}.group1", leaveGroupMessage.GroupName); broadcastMessage = (await gbTask)as GroupBroadcastDataMessage; Assert.NotNull(broadcastMessage); Assert.Equal($"hg-{hub}.group1", broadcastMessage.GroupName); var disconnectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)) .OrTimeout(); await proxy.WriteMessageAsync(new CloseConnectionMessage(clientConnection)); var disconnectMessage = (await disconnectTask)as GroupBroadcastDataMessage; Assert.NotNull(disconnectMessage); Assert.Equal($"hg-{hub}.note", disconnectMessage.GroupName); message = disconnectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>(); Assert.Equal("Disconnected", message.A[0]); // cleaned up clearly Assert.Empty(ccm.ClientConnections); } } }
public async Task ServiceConnectionWithOfflinePingWillTriggerDisconnectClients() { using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetActualHubConfig(loggerFactory); var appName = "app1"; var hub = "chat"; var scm = new TestServiceConnectionHandler(); hubConfig.Resolver.Register(typeof(IServiceConnectionManager), () => scm); var ccm = new ClientConnectionManager(hubConfig, loggerFactory); hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm); DispatcherHelper.PrepareAndGetDispatcher(new TestAppBuilder(), hubConfig, new ServiceOptions { ConnectionString = ConnectionString }, appName, loggerFactory); using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory)) { // prepare 2 clients with different instancesId connected var instanceId1 = Guid.NewGuid().ToString(); var connectionId1 = Guid.NewGuid().ToString("N"); var header1 = new Dictionary <string, StringValues>() { { Constants.AsrsInstanceId, instanceId1 } }; var instanceId2 = Guid.NewGuid().ToString(); var connectionId2 = Guid.NewGuid().ToString("N"); var header2 = new Dictionary <string, StringValues>() { { Constants.AsrsInstanceId, instanceId2 } }; // start the server connection await proxy.StartServiceAsync().OrTimeout(); // Application layer sends OpenConnectionMessage for client1 var connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); var openConnectionMessage = new OpenConnectionMessage(connectionId1, new Claim[0], header1, $"?transport=webSockets&connectionToken=conn1&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D"); await proxy.WriteMessageAsync(openConnectionMessage); // client1 is connected var connectMessage = (await connectTask)as GroupBroadcastDataMessage; Assert.NotNull(connectMessage); Assert.Equal($"hg-{hub}.note", connectMessage.GroupName); var message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>(); Assert.Equal("Connected", message.A[0]); ccm.ClientConnections.TryGetValue(connectionId1, out var transport1); Assert.NotNull(transport1); // Application layer sends OpenConnectionMessage for client2 connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); openConnectionMessage = new OpenConnectionMessage(connectionId2, new Claim[0], header2, $"?transport=webSockets&connectionToken=conn2&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D"); await proxy.WriteMessageAsync(openConnectionMessage); // client2 is connected connectMessage = (await connectTask)as GroupBroadcastDataMessage; Assert.NotNull(connectMessage); Assert.Equal($"hg-{hub}.note", connectMessage.GroupName); message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>(); Assert.Equal("Connected", message.A[0]); ccm.ClientConnections.TryGetValue(connectionId2, out var transport2); Assert.NotNull(transport2); // Send ServerOfflinePing on instance1 and will trigger cleanup related client1 connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout(); await proxy.WriteMessageAsync(new PingMessage() { Messages = new[] { "offline", instanceId1 } }); // Validate client1 disconnect connectMessage = (await connectTask)as GroupBroadcastDataMessage; Assert.NotNull(connectMessage); Assert.Equal($"hg-{hub}.note", connectMessage.GroupName); message = connectMessage.Payloads["json"] .GetJsonMessageFromSingleFramePayload <HubResponseItem>(); Assert.Equal("Disconnected", message.A[0]); // Validate client2 is still connected Assert.Single(ccm.ClientConnections); Assert.Equal(connectionId2, ccm.ClientConnections.FirstOrDefault().Key); } } }
public ServiceConnectionContext CreateConnection(OpenConnectionMessage message, Action <HttpContext> configureContext = null) { return(new ServiceConnectionContext(message, configureContext)); }
public IServiceTransport CreateConnection(OpenConnectionMessage message, IServiceConnection serviceConnection) { throw new NotImplementedException(); }
public ServiceConnectionContext CreateConnection(OpenConnectionMessage message) { return(new ServiceConnectionContext(message)); }
public void TestCreateConnectionWithCustomQueryStringSucceeds(string queryString) { var message = new OpenConnectionMessage(Guid.NewGuid().ToString("N"), new Claim[0], null, queryString); var connection = _clientConnectionManager.CreateConnection(message, null); }