Beispiel #1
0
        private static async Task DownloadChunk(RecordingMetadata metadata, CloudBlobContainer container, ILogger log)
        {
            var acsEndpoint  = new Uri(Environment.GetEnvironmentVariable("AcsEndpoint", EnvironmentVariableTarget.Process));
            var acsAccessKey = Environment.GetEnvironmentVariable("CUSTOMCONNSTR_AcsAccessKey", EnvironmentVariableTarget.Process);

            var downloadUrlForChunk  = string.Format("recording/download/{0}?api-version=2021-04-15-preview1", metadata.ChunkDocumentId);
            var downloadRecordingUrl = new Uri(acsEndpoint, downloadUrlForChunk);

            using (var request = new HttpRequestMessage(HttpMethod.Get, downloadRecordingUrl))
            {
                request.Content = null; // content required for POST methods

                AddHmacHeaders(request, CreateContentHash(string.Empty), acsAccessKey);

                using (var response = await client.SendAsync(request).ConfigureAwait(false))
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        log.LogError($"Failed to download document. StatusCode: {response.StatusCode}");
                        return;
                    }

                    var recordingStream = await response.Content.ReadAsStreamAsync();

                    var recordingFile = string.Format("{0}.{1}", metadata.CallId, metadata.RecordingInfo.Format);
                    var recordingBlob = container.GetBlockBlobReference(recordingFile);
                    await recordingBlob.UploadFromStreamAsync(recordingStream).ConfigureAwait(false);

                    log.LogInformation("Saved recording successfully");
                }
            }
        }
Beispiel #2
0
        private static async Task <Stream> DownloadChunk(RecordingMetadata metadata, ILogger log)
        {
            string downloadRecordingUrl = "https://{0}/recording/download/{1}?api-version=2021-04-15-preview1";
            string acsEndPoint          = Environment.GetEnvironmentVariable("AcsEndpoint", EnvironmentVariableTarget.Process);
            string acsAccessKey         = Environment.GetEnvironmentVariable("CUSTOMCONNSTR_AcsAccessKey", EnvironmentVariableTarget.Process);

            var downloadUrlForChunk = String.Format(downloadRecordingUrl, acsEndPoint, metadata.ChunkDocumentId);
            var request             = new HttpRequestMessage
            {
                Method     = HttpMethod.Get,
                RequestUri = new Uri(downloadUrlForChunk),
                Content    = null // content if required for POST methods
            };

            // Hash the content of the request.
            var contentHashed = CreateContentHash(string.Empty);

            // Add HMAC headers.
            AddHmacHeaders(request, contentHashed, acsAccessKey, HttpMethod.Get);

            // Make a request to the ACS apis mentioned above
            var response = await client.SendAsync(request).ConfigureAwait(false);

            log.LogInformation("Download recording statusCode: {0}", response.StatusCode);

            if (!response.IsSuccessStatusCode)
            {
                log.LogError("Failed to download document. StatusCode: " + response.StatusCode);
                return(null);
            }

            var contentStream = await response.Content.ReadAsStreamAsync();

            return(contentStream);
        }
Beispiel #3
0
        public static async void Run(
            [EventGridTrigger] EventGridEvent eventGridEvent,
            ILogger log)
        {
            try
            {
                log.LogInformation("Received event : {0}", eventGridEvent.EventType);

                string json = JsonConvert.SerializeObject(eventGridEvent, Formatting.Indented);
                log.LogInformation(json);

                if (eventGridEvent.EventType == "Microsoft.Communication.RecordingFileStatusUpdated")
                {
                    if (eventGridEvent.Data == null)
                    {
                        log.LogInformation("Received invalid event data");
                        return;
                    }

                    RecordingFileStatusUpdatedEventData eventData = ((JObject)(eventGridEvent.Data)).ToObject <RecordingFileStatusUpdatedEventData>();

                    foreach (var chunk in eventData.RecordingStorageInfo.RecordingChunks)
                    {
                        // Download metadata for chunk
                        var metadataString = await GetDownloadMetadata(chunk.DocumentId, log).ConfigureAwait(false);

                        if (metadataString == null)
                        {
                            log.LogInformation("Invalid metadata");
                            return;
                        }

                        RecordingMetadata metadata = JsonConvert.DeserializeObject <RecordingMetadata>(metadataString);

                        var recordingStream = await DownloadChunk(metadata, log).ConfigureAwait(false);

                        if (recordingStream == null)
                        {
                            log.LogInformation("Invalid recording stream");
                            return;
                        }

                        // Save to storage blob
                        string connStr = Environment.GetEnvironmentVariable("CUSTOMCONNSTR_RecordingStorageBlob", EnvironmentVariableTarget.Process);
                        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connStr);

                        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

                        CloudBlobContainer container = blobClient.GetContainerReference("recordings");

                        string         recordingMetadataFileName = String.Format("{0}_metadata.json", metadata.CallId);
                        CloudBlockBlob metadataBlob = container.GetBlockBlobReference(recordingMetadataFileName);
                        await metadataBlob.UploadTextAsync(metadataString).ConfigureAwait(false);

                        string         recordingFileName = String.Format("{0}.{1}", metadata.CallId, metadata.RecordingInfo.Format);
                        CloudBlockBlob downloadBlob      = container.GetBlockBlobReference(recordingFileName);
                        await downloadBlob.UploadFromStreamAsync(recordingStream).ConfigureAwait(false);

                        log.LogInformation("Saved recording successfully");

                        // Create a new record in Redis for this recording

                        string lastIDKey   = "LastID";
                        string lastIDValue = "";

                        string cacheConnection = Environment.GetEnvironmentVariable("CUSTOMCONNSTR_cacheConnection", EnvironmentVariableTarget.Process);
                        if (string.IsNullOrEmpty(cacheConnection))
                        {
                            log.LogInformation($"Missing Redis connection string '{cacheConnection}'");
                        }
                        else
                        {
                            ConnectionMultiplexer cm    = ConnectionMultiplexer.Connect(cacheConnection);
                            IDatabase             cache = cm.GetDatabase();

                            lastIDValue = cache.StringGet("LastID");
                            log.LogInformation($"{lastIDKey}={lastIDValue}");

                            var trans = cache.CreateTransaction();
                            var task  = trans.StringIncrementAsync(lastIDKey);
                            if (await trans.ExecuteAsync().ConfigureAwait(false))
                            {
                                await task.ConfigureAwait(false);

                                log.LogInformation($"transaction completed");
                                lastIDValue = cache.StringGet(lastIDKey);
                                log.LogInformation($"After change: {lastIDKey}={lastIDValue}");

                                cache.StringSet(lastIDValue, recordingFileName);

                                log.LogInformation($"Mapping '{lastIDValue}' --> '{recordingFileName}' created");

                                var message = $"Your call record is available here: https://arturlcallrecordingdownloader.azurewebsites.net/api/Get?id={lastIDValue}";

                                string phoneNumberTo = "";
                                foreach (var participant in metadata.Participants)
                                {
                                    if (participant.ParticipantId.Contains("acs:"))
                                    {
                                        continue;                                             // this is not a human
                                    }
                                    if (participant.ParticipantId.Length >= 12)
                                    {
                                        phoneNumberTo = participant.ParticipantId.Substring(participant.ParticipantId.Length - 12, 12);
                                        log.LogInformation($"Found target phone number: {phoneNumberTo}");
                                    }
                                }

                                if (string.IsNullOrEmpty(phoneNumberTo))
                                {
                                    log.LogError("Cannot extract target phone number");
                                }
                                else
                                {
                                    var    acsParams           = GetACSConnectionParameters(log);
                                    string acsconnectionString = $"endpoint=https://{acsParams.AcsEndPoint}/;accesskey={acsParams.AcsAccessKey}";

                                    string SMSSenderPhoneNumber = Environment.GetEnvironmentVariable("SMSSenderPhoneNumber", EnvironmentVariableTarget.Process);
                                    if (string.IsNullOrEmpty(SMSSenderPhoneNumber))
                                    {
                                        log.LogError($"SMSSenderPhoneNumber application setting not set, cannot send SMS");
                                    }
                                    else
                                    {
                                        var smsResponse = SendSMSAsync(acsconnectionString, SMSSenderPhoneNumber, phoneNumberTo, message); // TBD: parametrize phone number
                                        log.LogInformation($"Sent SMS to {phoneNumberTo}. Message: '{message}'");

                                        string QAOperatorPhoneNumber = Environment.GetEnvironmentVariable("QAOperatorPhoneNumber", EnvironmentVariableTarget.Process);
                                        if (!string.IsNullOrEmpty(QAOperatorPhoneNumber))
                                        {
                                            // Text a copy to QA operator for quality assurance purposes
                                            if (phoneNumberTo != QAOperatorPhoneNumber)
                                            {
                                                var smsResponse2 = SendSMSAsync(acsconnectionString, SMSSenderPhoneNumber, QAOperatorPhoneNumber, message);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                log.LogError($"transaction failed");
                            }
                            log.LogInformation($"Done");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.LogError("Failed with {0}", ex.Message);
                log.LogError("Failed with {0}", ex.InnerException.Message);
            }
        }