Пример #1
0
        private EventMatch FindGroupMatch(EventGroup group,
                                          ICollection <IEvent> events,
                                          StateMachineContext context,
                                          JToken data)
        {
            Debug.Assert(group != null);
            Debug.Assert(events != null);
            Debug.Assert(context != null);
            Debug.Assert(data != null);

            foreach (var evt in events)
            {
                Debug.Assert(evt != null);

                bool isDefinedAndNotAMatch(string eventDefAttribute, string incomingEventAttribute)
                {
                    return(!(string.IsNullOrWhiteSpace(eventDefAttribute)) &&
                           !(eventDefAttribute.IsEqualTo(incomingEventAttribute)));
                }

                var matchedEventName = group.Events.FirstOrDefault(e => e.IsEqualTo(evt.EventName));

                if (string.IsNullOrWhiteSpace(matchedEventName))
                {
                    continue;
                }

                var targetEvent = context.Workflow.Events.Single(e => e.Name.IsEqualTo(evt.EventName));

                if (isDefinedAndNotAMatch(targetEvent.Source, evt.EventSource))
                {
                    continue;
                }

                if (isDefinedAndNotAMatch(targetEvent.Type, evt.EventType))
                {
                    continue;
                }

                if (!string.IsNullOrWhiteSpace(group.Condition) && !group.Condition.EvalPredicateExpr(data, context))
                {
                    continue;
                }

                return(new EventMatch
                {
                    EventDefinition = targetEvent,
                    EventInstance = evt,
                    Transition = this.TargetTransition,
                    Group = group
                });
            }

            return(null);
        }
Пример #2
0
        private EventMatch[] FindMatches(ICollection <IEvent> events, StateMachineContext context, JToken data)
        {
            var matches = new List <EventMatch>();

            foreach (var group in this.TargetTransition.EventGroups)
            {
                var match = FindGroupMatch(group, events, context, data);

                if (match == null)
                {
                    return(null);
                }

                matches.Add(match);
            }

            return(matches.ToArray());
        }
Пример #3
0
        private static async Task <JToken> RunAsync(StateMachineContext context)
        {
            Debug.Assert(context != null);

            var state = context.Workflow.States.SingleOrDefault(s => s.Start);

            if (state == null)
            {
                throw new InvalidOperationException("Unable to resolve single start state in workflow.");
            }

            while (state != null)
            {
                state = await state.ExecuteAsync(context);
            }

            return(context.Data);
        }
Пример #4
0
        public static async Task <EventMatch[]> WaitForFirstMatchedSubscriptionAsync(
            IEnumerable <EventSubscription> subscriptions, StateMachineContext context, JToken data, CancellationToken cancelToken)
        {
            subscriptions.CheckArgNull(nameof(subscriptions));
            context.CheckArgNull(nameof(context));

            Func <ICollection <IEvent>, EventMatch[]> matchFinder = accumulated =>
            {
                foreach (var subscription in subscriptions)
                {
                    EventMatch[] matches = subscription.FindMatches(accumulated, context, data);

                    if (matches?.Length > 0)
                    {
                        return(matches);
                    }
                }

                return(null);
            };

            var accumulated = new List <IEvent>();

            EventMatch[] matches = null;

            while (matches == null && !cancelToken.IsCancellationRequested)
            {
                var evt = await context.Host.WaitForEventAsync(cancelToken);

                Debug.Assert(evt != null);

                accumulated.Add(evt);

                matches = matchFinder(accumulated);
            }

            return(matches);
        }
Пример #5
0
        public static async Task <JToken> RunAsync(StateMachine workflow,
                                                   IStateMachineHost host,
                                                   JObject?input = null,
                                                   ObservableAction[]?targetActions = null,
                                                   CancellationToken cancelToken    = default)
        {
            workflow.CheckArgNull(nameof(workflow));
            host.CheckArgNull(nameof(host));

            StateMachineContext?context = null;

            Func <CancellationToken, Task <JToken> > runTask = async token =>
            {
                context = new StateMachineContext(workflow, host, input, targetActions, token);

                await context.RecordObservableActionAsync(ObservableAction.EnterStateMachine);

                try
                {
                    return(await RunAsync(context));
                }
                finally
                {
                    await context.RecordObservableActionAsync(ObservableAction.ExitStateMachine);
                }
            };

            JToken output;

            if (workflow.Timeout != null)
            {
                using var localTimeoutCancelTokenSource = new CancellationTokenSource();

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

                Task <JToken> timeoutTask = host.DelayAsync(workflow.Timeout.Duration, combined.Token)
                                            .ContinueWith(_ =>
                {
                    return((JToken)JValue.CreateNull());
                });

                Debug.Assert(timeoutTask != null);

                output = await Task.WhenAny(timeoutTask, runTask(combined.Token)).Unwrap();

                if (!timeoutTask.IsCompleted)
                {
                    localTimeoutCancelTokenSource.Cancel();
                }
                else if (workflow.Timeout.Action != null)
                {
                    Debug.Assert(context != null);

                    await workflow.Timeout.Action.ExecuteAsync(context, context.Data);
                }
            }
            else
            {
                output = await runTask(cancelToken);
            }

            Debug.Assert(output != null);

            return(output);
        }