/// <summary>
        /// Processes the task state change.
        /// </summary>
        /// <param name="notificationMessage">MediaServicesV2NotificationMessage.</param>
        /// <param name="jobId">The id of the job.</param>
        /// <returns>Successfully published message.</returns>
        private async Task <string> ProcessTaskStateChangeAsync(MediaServicesV2NotificationMessage notificationMessage, string jobId)
        {
            _ = notificationMessage ?? throw new ArgumentNullException(nameof(notificationMessage));

            if (!notificationMessage.Properties.TryGetValue("newState", out string newState))
            {
                throw new Exception("Could not find NewState property in notification message");
            }

            if (newState.Equals("Scheduled", StringComparison.OrdinalIgnoreCase) ||
                newState.Equals("Processing", StringComparison.OrdinalIgnoreCase))
            {
                return(newState);
            }

            if (newState.Equals("Finished", StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    var destinationUris = await _mediaServicesV2EncodeOperations.CopyOutputAssetToOutputContainerAsync(jobId).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    throw new Exception("Failed while CopyOutputAssetToOutputContainerAsync", e);
                }

                try
                {
                    await _mediaServicesV2EncodeOperations.DeleteAssetsForJobAsync(jobId).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    throw new Exception("Failed while DeleteAssetsForV2JobAsync", e);
                }

                return(newState);
            }

            if (newState.Equals("Error", StringComparison.OrdinalIgnoreCase))
            {
                await _mediaServicesV2EncodeOperations.DeleteAssetsForJobAsync(jobId).ConfigureAwait(false);

                throw new Exception("Encode Job Failed");
            }

            if (newState.Equals("Canceled", StringComparison.OrdinalIgnoreCase))
            {
                await _mediaServicesV2EncodeOperations.DeleteAssetsForJobAsync(jobId).ConfigureAwait(false);

                return(newState);
            }

            throw new NotSupportedException($"Unknown newState:{newState}");
        }
Пример #2
0
        private static EventGridEvent GetEventFromNotificationMessage(MediaServicesV2NotificationMessage notificationMessage)
        {
            var eventGridEventId = System.Guid.NewGuid().ToString();

            return(new EventGridEvent
            {
                Id = eventGridEventId,
                Data = JsonConvert.SerializeObject(notificationMessage),
                EventTime = System.DateTime.UtcNow,
                EventType = CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback,
                Subject = $"/{CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback}/{eventGridEventId}",
                DataVersion = "1.0",
            });
        }
        /// <summary>
        /// Get the progress.
        /// </summary>
        /// <param name="notificationMessage">MediaServicesV2NotificationMessage.</param>
        /// <returns>Progress percentage.</returns>
        private static int GetEncodeProgress(MediaServicesV2NotificationMessage notificationMessage)
        {
            _ = notificationMessage ?? throw new ArgumentNullException(nameof(notificationMessage));

            if (!notificationMessage.Properties.TryGetValue("lastComputedProgress", out string progressString))
            {
                throw new Exception("Could not find LastComputedProgress property in notification message");
            }

            if (!int.TryParse(progressString, out int progress))
            {
                throw new Exception("Could not parse progress from message");
            }

            return(progress);
        }
Пример #4
0
        public async void HandleAsync_ShouldReturnTrue_WhenTaskStateChangePayloadIsValid(string oldState, string newState, string expectedEventType)
        {
            var mediaV2ServiceMock = Mock.Of <IMediaServicesV2EncodeService>();

            Mock.Get(mediaV2ServiceMock)
            .Setup(x => x.GetOperationContextForJobAsync(It.IsAny <string>()))
            .ReturnsAsync(new JObject());
            var egPublisherMock = Mock.Of <IEventGridPublisher>();

            dynamic opcontext = new JObject();

            opcontext.TestKey = "TestValue";

            Mock.Get(egPublisherMock)
            .Setup(x => x.PublishEventToTopic(It.IsAny <EventGridEvent>()))
            .ReturnsAsync(true);

            var handler = new MediaServicesV2CallbackHandler(log, mediaV2ServiceMock, egPublisherMock);

            var notificationMessage = new MediaServicesV2NotificationMessage()
            {
                ETag           = "random",
                EventType      = MediaServicesV2NotificationEventType.TaskStateChange,
                MessageVersion = "1.1",
                TimeStamp      = DateTime.UtcNow,
                Properties     = new Dictionary <string, string>()
                {
                    { "jobId", "nb:jid:UUID:91ab2b3a-0d00-a812-94e1-f1ea63c713e1" },
                    { "taskId", "nb:tid:UUID:4c1e6189-cb33-45ca-901a-46dcd3cc5f40" },
                    { "newState", newState },
                    { "oldState", oldState },
                    { "accountName", "justatest" },
                    { "accountId", "00000000-0000-0000-0000-000000000000" },
                    { "notificationEndPointId", "nb:nepid:UUID:738eb6b5-a18d-4b7f-961d-bc33e844da13" }
                }
            };

            var actual = await handler.HandleAsync(GetEventFromNotificationMessage(notificationMessage)).ConfigureAwait(false);

            actual.ShouldBeTrue();

            Mock.Get(egPublisherMock)
            .Verify(x => x.PublishEventToTopic(It.Is <EventGridEvent>(x => x.EventType == expectedEventType)),
                    Times.Once,
                    "publish should be called with the correct eventtype");
        }
        /// <inheritdoc/>
        public async Task <(string JobId, string Status)> HandleNotificationAsync(MediaServicesV2NotificationMessage notificationMessage)
        {
            _ = notificationMessage ?? throw new ArgumentNullException(nameof(notificationMessage));

            var jobId = notificationMessage.Properties["jobId"];

            if (string.IsNullOrWhiteSpace(jobId))
            {
                throw new ArgumentException("notificationMessage.jobId is invalid");
            }

            string newState;

            try
            {
                switch (notificationMessage.EventType)
                {
                case MediaServicesV2NotificationEventType.TaskStateChange:
                    newState = await ProcessTaskStateChangeAsync(notificationMessage, jobId).ConfigureAwait(false);

                    break;

                case MediaServicesV2NotificationEventType.TaskProgress:
                    newState = $"Progress:{GetEncodeProgress(notificationMessage)}";
                    break;

                default:
                    _log.LogInformation(notificationMessage.EventType.ToString());
                    throw new NotSupportedException($"Unsupported AMSv2 event type {notificationMessage.EventType}");
                }
            }
            catch (Exception e)
            {
                var msg = $"Failed while parsing notifiation message for {jobId}.";
                _log.LogError(msg, e);
                throw new Exception(msg, e);
            }

            return(jobId, newState);
        }
Пример #6
0
        public async void HandleAsync_ShouldPublishFailureEvent_WhenPayloadIsNotFormatedCorrectly()
        {
            var mediaV2ServiceMock = Mock.Of <IMediaServicesV2EncodeService>();
            var egPublisherMock    = Mock.Of <IEventGridPublisher>();

            dynamic opcontext = new JObject();

            opcontext.TestKey = "TestValue";

            Mock.Get(egPublisherMock)
            .Setup(x => x.PublishEventToTopic(It.IsAny <EventGridEvent>()))
            .ReturnsAsync(true);

            var handler = new MediaServicesV2CallbackHandler(log, mediaV2ServiceMock, egPublisherMock);

            var notificationMessage = new MediaServicesV2NotificationMessage()
            {
                ETag           = "random",
                EventType      = MediaServicesV2NotificationEventType.TaskStateChange,
                MessageVersion = "1.1",
                TimeStamp      = DateTime.UtcNow,
                Properties     = new Dictionary <string, string>()
                {
                    { "jobId", "nb:jid:UUID:91ab2b3a-0d00-a812-94e1-f1ea63c713e1" },
                    { "taskId", "nb:tid:UUID:4c1e6189-cb33-45ca-901a-46dcd3cc5f40" },
                    { "noState", "Wrong" },
                    { "oldState", "OldState" },
                    { "accountName", "justatest" },
                    { "accountId", "00000000-0000-0000-0000-000000000000" },
                    { "notificationEndPointId", "nb:nepid:UUID:738eb6b5-a18d-4b7f-961d-bc33e844da13" }
                }
            };

            await handler.HandleAsync(GetEventFromNotificationMessage(notificationMessage)).ConfigureAwait(false);

            Mock.Get(egPublisherMock)
            .Verify(x => x.PublishEventToTopic(It.Is <EventGridEvent>(e => e.EventType == CustomEventTypes.ResponseFailure)));
        }
Пример #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GridwichMediaServicesV2MessageProcessingException" /> class.
 /// </summary>
 /// <param name="notificationMessage">The notification message.</param>
 /// <param name="message">The base exception message you want to set.</param>
 /// <param name="logEventId">The last LogEventId that was logged relevant to this exception.</param>
 /// <param name="operationContext">The OperationContext for this exception.</param>
 /// <param name="innerException">The cause behind this exception.</param>
 public GridwichMediaServicesV2MessageProcessingException(MediaServicesV2NotificationMessage notificationMessage, string message, EventId logEventId, JObject operationContext, Exception innerException)
     : base(message, logEventId, operationContext, innerException)
 {
     SafeAddToData(MessageKey, notificationMessage);
 }
Пример #8
0
        public async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
            HttpRequest req,
            CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name);
                throw new OperationCanceledException("Function invoked with a canceled cancellation token.");
            }

            try
            {
                cancellationToken.Register(() =>
                {
                    _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name);
                });

                _logger.LogEvent(LogEventIds.CallbackFunctionTriggered, $"C# HTTP trigger function processed a request. Path={req?.Path}");

                // TODO: not sure why we have to get the byte array.. might be legacy code
                // MemoryStream stream = new MemoryStream();
                // await req.Body.CopyToAsync(stream);
                // byte[] bodyByteArray = stream.ToArray();

                string requestBody;
                using (var sr = new StreamReader(req.Body))
                {
                    requestBody = await sr.ReadToEndAsync().ConfigureAwait(false);
                }

                if (req.Headers.TryGetValue("ms-signature", out _))
                {
                    // TODO: need to verify headers here. However not sure how to get the signing key.
                    MediaServicesV2NotificationMessage notificationMessage = JsonConvert.DeserializeObject <MediaServicesV2NotificationMessage>(requestBody);

                    var eventGridEventId = System.Guid.NewGuid().ToString();
                    var eventToPublish   = new Microsoft.Azure.EventGrid.Models.EventGridEvent
                    {
                        Id          = eventGridEventId,
                        Data        = notificationMessage,
                        EventTime   = System.DateTime.UtcNow,
                        EventType   = CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback,
                        Subject     = $"/{CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback}/{eventGridEventId}",
                        DataVersion = "1.0",
                    };

                    await _publisher.PublishEventToTopic(eventToPublish).ConfigureAwait(false);

                    _logger.LogEvent(LogEventIds.CallbackFunctionNotificationMessageProcessed, "processed notification message");
                }
                else
                {
                    _logger.LogEvent(LogEventIds.RequestIsMissingVerifyWebHookRequestSignature, "VerifyWebHookRequestSignature failed.");
                    return(new BadRequestObjectResult("VerifyWebHookRequestSignature failed."));
                }

                return(new OkObjectResult("OK"));
            }
            catch (OperationCanceledException oce)
            {
                _logger.LogEventObject(LogEventIds.OperationCancelException, oce);
                throw;
            }
        }