Ejemplo n.º 1
0
        private static async Task <Transition> ResolveEventTransitionAsync(this State state, StateMachineContext context, JToken data)
        {
            Debug.Assert(state != null);
            Debug.Assert(context != null);
            Debug.Assert(data != null);

            var eventSubscriptions = state.Transitions
                                     .Where(t => (t.EventGroups != null && t.EventGroups.Count > 0) &&
                                            string.IsNullOrWhiteSpace(t.Condition) &&
                                            t.Timeout == null)
                                     .Select(t => new EventSubscription {
                TargetTransition = t
            })
                                     .ToArray();

            Func <CancellationToken, Task <Transition> > getTransitionFunc =
                async token =>
            {
                var matches = await EventSubscription.WaitForFirstMatchedSubscriptionAsync(eventSubscriptions, context, data, token);

                Debug.Assert(matches != null);
                Debug.Assert(matches.Length > 0);

                foreach (var match in matches)
                {
                    var json = match.EventInstance.ToJson();

                    Debug.Assert(json != null);

                    json.Merge(context.Data, match.Group.ResultHandler, context);
                }

                return(matches.First().Transition);
            };

            var timeoutTransition = state.Transitions.SingleOrDefault(t => (!string.IsNullOrWhiteSpace(t.NextState) || t.Action != null) &&
                                                                      string.IsNullOrWhiteSpace(t.Condition) &&
                                                                      (t.EventGroups == null || t.EventGroups.Count == 0) &&
                                                                      t.Timeout != null);

            Transition next;

            if (timeoutTransition != null)
            {
                using var localTimeoutCancelTokenSource = new CancellationTokenSource();

                using var combined = CancellationTokenSource.CreateLinkedTokenSource(
                          localTimeoutCancelTokenSource.Token, context.CancelToken);

                Task <Transition> timeoutTask = context.Host.DelayAsync(timeoutTransition.Timeout.Value, combined.Token)
                                                .ContinueWith(_ => timeoutTransition);

                Debug.Assert(timeoutTask != null);

                next = await Task.WhenAny(timeoutTask, getTransitionFunc(combined.Token)).Unwrap();

                if (!timeoutTask.IsCompleted)
                {
                    localTimeoutCancelTokenSource.Cancel();
                }
            }
            else
            {
                next = await getTransitionFunc(context.CancelToken);
            }

            Debug.Assert(next != null);

            return(next);
        }