/// <summary> /// Initialize the instance. /// </summary> /// <param name="service">Service instance.</param> /// <param name="logger">Graph logger.</param> internal void Initialize(Service service, IGraphLogger logger) { Validator.IsNull(this.Logger, "Multiple initializations are not allowed."); this.Logger = logger; this.Observer = new SampleObserver(logger); var name = this.GetType().Assembly.GetName().Name; var builder = new CommunicationsClientBuilder( name, service.Configuration.AadAppId, this.Logger); var authProvider = new AuthenticationProvider( name, service.Configuration.AadAppId, service.Configuration.AadAppSecret, this.Logger); builder.SetAuthenticationProvider(authProvider); builder.SetNotificationUrl(service.Configuration.CallControlBaseUrl); builder.SetMediaPlatformSettings(service.Configuration.MediaPlatformSettings); builder.SetServiceBaseUrl(service.Configuration.PlaceCallEndpointUrl); this.Client = builder.Build(); this.Client.Calls().OnIncoming += this.CallsOnIncoming; this.Client.Calls().OnUpdated += this.CallsOnUpdated; }
/// <inheritdoc /> public void Dispose() { this.Observer?.Dispose(); this.Observer = null; this.Logger = null; this.Client?.Dispose(); this.Client = null; }
/// <summary> /// Rehydrates and validates the group call. /// </summary> /// <param name="client">The communications client.</param> /// <param name="call">The call to validate.</param> /// <returns>The rehydrated call.</returns> private async Task <ICall> RehydrateAndValidateGroupCallAsync(ICommunicationsClient client, ICall call) { // Wait for roster so we ensure that events were already raised. await call.Participants.WaitForParticipantAsync(call.Resource.MyParticipantId).ConfigureAwait(false); // Remove call from memory. this.Client.Calls().TryForceRemove(call.Id, out ICall removedCall); this.graphLogger.Info($"Check whether the removed call is desired: {call == removedCall}"); this.graphLogger.Info($"Check whether the call get removed: {this.Client.Calls()[removedCall.Id] == null}"); // Rehydrate here... after this point all the data should be rebuilt // This calls: // GET /communications/calls/{id} // GET /communications/calls/{id}/participants // GET /communications/calls/{id}/audioRoutingGroups var tenantId = call.TenantId; var scenarioId = call.ScenarioId; await client.RehydrateAsync(removedCall.ResourcePath, tenantId, scenarioId).ConfigureAwait(false); var rehydratedCall = client.Calls()[removedCall.Id]; this.graphLogger.Info($"Check whether the call get rehydrated: {rehydratedCall != null}"); this.graphLogger.Info($"Check whether the rehydrated call is a new object: {removedCall == rehydratedCall}"); // deployments and Graph is stripping out some parameters. // E2EAssert.IsContentEqual(removedCall.Resource, rehydratedCall.Resource); var myParticipant = rehydratedCall.Participants[removedCall.Resource.MyParticipantId]; this.graphLogger.Info($"Check whether myParticipant get rehydrated: {myParticipant != null}"); // Remove participant from memory. rehydratedCall.Participants.TryForceRemove(call.Resource.MyParticipantId, out IParticipant removedParticipant); this.graphLogger.Info($"Check whether participant get removed from memory: {rehydratedCall.Participants[call.Resource.MyParticipantId] == null}"); // Rehydrate here... after this point the participant should be rebuilt. // This calls: // GET /communications/calls/{id}/participants/{id} var rehydratedParticipant = await rehydratedCall.Participants.GetAsync(call.Resource.MyParticipantId).ConfigureAwait(false); this.graphLogger.Info($"Check whether participant get rehydrated: {rehydratedParticipant != null}"); this.graphLogger.Info($"Check whether the rehydrated participant is a new object: {removedParticipant != rehydratedParticipant}"); return(rehydratedCall); }
/// <summary> /// Initialize the instance. /// </summary> public void Initialize() { var name = this.GetType().Assembly.GetName().Name; var builder = new CommunicationsClientBuilder( name, _settings.AadAppId, _logger); var authProvider = new AuthenticationProvider( name, _settings.AadAppId, _settings.AadAppSecret, _logger); builder.SetAuthenticationProvider(authProvider); builder.SetNotificationUrl(_settings.CallControlBaseUrl); builder.SetMediaPlatformSettings(_settings.MediaPlatformSettings); builder.SetServiceBaseUrl(_settings.PlaceCallEndpointUrl); this.Client = builder.Build(); this.Client.Calls().OnIncoming += this.CallsOnIncoming; this.Client.Calls().OnUpdated += this.CallsOnUpdated; }
/// <summary> /// Processes the notifications and raises the required callbacks. /// This function should be called in order for the SDK to raise /// any required events and process state changes. /// </summary> /// <param name="client">The stateful client.</param> /// <param name="request">The http request that is incoming from service.</param> /// <returns>Http Response Message after processed by the SDK. This has to /// be returned to the server.</returns> private static async Task <HttpResponseMessage> ProcessNotificationAsync(ICommunicationsClient client, HttpRequestMessage request) { client.NotNull(nameof(client)); request.NotNull(nameof(request)); var stopwatch = Stopwatch.StartNew(); var scenarioId = client.GraphLogger.ParseScenarioId(request); var requestId = client.GraphLogger.ParseRequestId(request); CommsNotifications notifications = null; try { // Parse out the notification content. var content = await request.Content.ReadAsStringAsync().ConfigureAwait(false); var serializer = client.Serializer; notifications = NotificationProcessor.ExtractNotifications(content, serializer); } catch (ServiceException ex) { var statusCode = (int)ex.StatusCode >= 200 ? ex.StatusCode : HttpStatusCode.BadRequest; return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, statusCode, stopwatch, ex)); } catch (Exception ex) { var statusCode = HttpStatusCode.BadRequest; return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, statusCode, stopwatch, ex)); } RequestValidationResult result; try { // Autenticate the incoming request. result = await client.AuthenticationProvider .ValidateInboundRequestAsync(request) .ConfigureAwait(false); } catch (Exception ex) { var clientEx = new ClientException( new Error { Code = ErrorConstants.Codes.ClientCallbackError, Message = ErrorConstants.Messages.ClientErrorAuthenticatingRequest, }, ex); throw clientEx; } if (!result.IsValid) { var statusCode = HttpStatusCode.Unauthorized; return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, statusCode, stopwatch)); } // The request is valid. Let's evaluate any policies on the // incoming call before sending it off to the SDK for processing. var call = notifications?.Value?.FirstOrDefault()?.GetResourceData() as Call; var response = await EvaluateAndHandleIncomingCallPoliciesAsync(call).ConfigureAwait(false); if (response != null) { var level = client.GraphLogger.LogHttpRequest(request, response.StatusCode, notifications); client.GraphLogger.LogHttpResponse(level, request, response, stopwatch.ElapsedMilliseconds); stopwatch.Stop(); return(response); } try { var additionalData = request.GetHttpAndContentHeaders().ToDictionary( pair => pair.Key, pair => (object)string.Join(",", pair.Value), StringComparer.OrdinalIgnoreCase); client.ProcessNotifications(request.RequestUri, notifications, result.TenantId, requestId, scenarioId, additionalData); } catch (ServiceException ex) { var statusCode = (int)ex.StatusCode >= 200 ? ex.StatusCode : HttpStatusCode.InternalServerError; return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, statusCode, stopwatch, ex)); } catch (Exception ex) { var statusCode = HttpStatusCode.InternalServerError; return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, statusCode, stopwatch, ex)); } return(client.LogAndCreateResponse(request, requestId, scenarioId, notifications, HttpStatusCode.Accepted, stopwatch)); }
/// <inheritdoc /> public void Dispose() { this.Client?.Dispose(); this.Client = null; }