/// <summary> /// Creates a streaming specific connector client. /// </summary> private IConnectorClient CreateStreamingConnectorClient(Activity activity, StreamingRequestHandler requestHandler) { var emptyCredentials = (ChannelProvider != null && ChannelProvider.IsGovernment()) ? MicrosoftGovernmentAppCredentials.Empty : MicrosoftAppCredentials.Empty; var streamingClient = new StreamingHttpClient(requestHandler, Logger); var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), emptyCredentials, customHttpClient: streamingClient); return(connectorClient); }
/// <summary> /// Creates a streaming specific connector client. /// </summary> private IConnectorClient CreateStreamingConnectorClient(Activity activity, StreamingRequestHandler requestHandler) { var emptyCredentials = (ChannelProvider != null && ChannelProvider.IsGovernment()) ? MicrosoftGovernmentAppCredentials.Empty : MicrosoftAppCredentials.Empty; #pragma warning disable CA2000 // Dispose objects before losing scope (We need to make ConnectorClient disposable to fix this, ignoring it for now) var streamingClient = new StreamingHttpClient(requestHandler, Logger); #pragma warning restore CA2000 // Dispose objects before losing scope var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), emptyCredentials, customHttpClient: streamingClient); return(connectorClient); }
/// <summary> /// Sends an activity. /// </summary> /// <param name="activity">>The <see cref="Activity"/> to send.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task representing the asynchronous operation.</returns> /// <remarks>If the task completes successfully, the result contains a the resource response object.</remarks> public async Task <ResourceResponse> SendStreamingActivityAsync(Activity activity, CancellationToken cancellationToken = default) { // Check to see if any of this adapter's StreamingRequestHandlers is associated with this conversation. var possibleHandlers = RequestHandlers.Where(x => x.ServiceUrl == activity.ServiceUrl).Where(y => y.HasConversation(activity.Conversation.Id)); if (possibleHandlers.Any()) { if (possibleHandlers.Count() > 1) { // The conversation has moved to a new connection and the former StreamingRequestHandler needs to be told to forget about it. var correctHandler = possibleHandlers.OrderBy(x => x.ConversationAddedTime(activity.Conversation.Id)).Last(); foreach (var handler in possibleHandlers) { if (handler != correctHandler) { handler.ForgetConversation(activity.Conversation.Id); } } return(await correctHandler.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false)); } return(await possibleHandlers.First().SendActivityAsync(activity, cancellationToken).ConfigureAwait(false)); } if (ConnectedBot != null) { // This is a proactive message that will need a new streaming connection opened. // The ServiceUrl of a streaming connection follows the pattern "urn:[ChannelName]:[Protocol]:[Host]". #pragma warning disable CA2000 // Dispose objects before losing scope (we can't fix this without closing the socket connection, this should be addressed after we make StreamingRequestHandler disposable and we dispose the connector ) var connection = new ClientWebSocket(); #pragma warning restore CA2000 // Dispose objects before losing scope var uri = activity.ServiceUrl.Split(':'); var protocol = uri[uri.Length - 2]; var host = uri[uri.Length - 1]; await connection.ConnectAsync(new Uri(protocol + host + "/api/messages"), cancellationToken).ConfigureAwait(false); #pragma warning disable CA2000 // Dispose objects before losing scope (We'll dispose this when the adapter gets disposed or when elements are removed) var handler = new StreamingRequestHandler(ConnectedBot, this, connection, Logger); #pragma warning restore CA2000 // Dispose objects before losing scope if (RequestHandlers == null) { RequestHandlers = new List <StreamingRequestHandler>(); } RequestHandlers.Add(handler); return(await handler.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false)); } return(null); }
/// <summary> /// Creates a new StreamingRequestHandler to listen to the specififed Named Pipe /// and pass requests to this adapter. /// </summary> /// <param name="pipeName">The name of the Named Pipe to connect to.</param> /// <param name="bot">The bot to use when processing activities received over the Named Pipe.</param> /// <returns>A task that completes only once the StreamingRequestHandler has stopped listening /// for incoming requests on the Named Pipe.</returns> public async Task ConnectNamedPipeAsync(string pipeName, IBot bot) { if (string.IsNullOrEmpty(pipeName)) { throw new ArgumentNullException(nameof(pipeName)); } ConnectedBot = bot ?? throw new ArgumentNullException(nameof(bot)); ClaimsIdentity = ClaimsIdentity ?? new ClaimsIdentity(); if (RequestHandlers == null) { RequestHandlers = new List <StreamingRequestHandler>(); } var requestHandler = new StreamingRequestHandler(bot, this, pipeName, Logger); RequestHandlers.Add(requestHandler); await requestHandler.ListenAsync().ConfigureAwait(false); }
/// <summary> /// Creates a new StreamingRequestHandler to listen to the specified Named Pipe /// and pass requests to this adapter. /// </summary> /// <param name="pipeName">The name of the Named Pipe to connect to.</param> /// <param name="bot">The bot to use when processing activities received over the Named Pipe.</param> /// <param name="audience">The specified recipient of all outgoing activities.</param> /// <returns>A task that completes only once the StreamingRequestHandler has stopped listening /// for incoming requests on the Named Pipe.</returns> public async Task ConnectNamedPipeAsync(string pipeName, IBot bot, string audience = null) { if (string.IsNullOrEmpty(pipeName)) { throw new ArgumentNullException(nameof(pipeName)); } ConnectedBot = bot ?? throw new ArgumentNullException(nameof(bot)); ClaimsIdentity = ClaimsIdentity ?? new ClaimsIdentity(); if (RequestHandlers == null) { RequestHandlers = new List <StreamingRequestHandler>(); } #pragma warning disable CA2000 // Dispose objects before losing scope (We'll dispose this when the adapter gets disposed or when elements are removed) var requestHandler = new StreamingRequestHandler(bot, this, pipeName, audience, Logger); #pragma warning restore CA2000 // Dispose objects before losing scope RequestHandlers.Add(requestHandler); await requestHandler.ListenAsync().ConfigureAwait(false); }
/// <summary> /// Initializes a new instance of the <see cref="StreamingHttpClient"/> class. /// An implementation of <see cref="HttpClient"/> that adds compatibility with streaming connections. /// </summary> /// <param name="requestHandler">The <see cref="StreamingRequestHandler"/> to send requests through.</param> /// <param name="logger">A logger.</param> public StreamingHttpClient(StreamingRequestHandler requestHandler, ILogger logger = null) { _requestHandler = requestHandler ?? throw new ArgumentNullException(nameof(requestHandler)); _logger = logger ?? NullLogger.Instance; }