protected ExecutionContext PrepareExecutionContext(string param, ExecutionContext parentContext) { var output = new OutputChangedDelegates(); output.Add(val => SetCurrentValue(val, SystemActionSource)); var tokenSource = PrepareCancellationTokenSource(); ExecutionContext context; var prevValue = GetCurrentValue(); if (parentContext == null) { context = new ExecutionContext(this, param, prevValue, output, tokenSource); } else { context = new ExecutionContext(this, param, prevValue, output, parentContext, tokenSource); parentContext.CancellationTokenSource.RegisterCallback(tokenSource.Cancel); CheckContext(context); } return(context); }
protected override void RunInternal() { if (GetScenario() == null) { return; } //удаляем старую подписку, если имеется if (_lastSubscribe != null) { GetScenario().RemoveOnStateChanged(_lastSubscribe); } //выполнение по подписке на изменение значения var executeBySubscription = true; //если сценарий это одиночное действие и нельзя подписаться на изменение целевого действия //то не выполняем по подписке, а выполняем просто через цикл if (GetScenario() is SingleActionScenario singleActionScen && !singleActionScen.ActionHolder.Action.IsSupportsEvent) { executeBySubscription = false; } var contextCancellationToken = new SafeCancellationToken(); CancellationToken.RegisterCallback(contextCancellationToken.Cancel); if (executeBySubscription) { _lastSubscribe = (sender, args) => { if (CancellationToken.IsCancellationRequested) { //crutch; scenario can be changed before initializing, then we need to remove //current subscribe from previous scenario. CancellationToken.IsCancellationRequested //can be setted in true only when trigger stopped; args.Value.Scenario.RemoveOnStateChanged(_lastSubscribe); } else { if (!args.Value.OnlyIntent) { var action = TargetAction; var outputChanged = new OutputChangedDelegates(); outputChanged.Add((value) => GetScenario().SetCurrentValue(value, ExecuteActionSource)); contextCancellationToken.Cancel(); contextCancellationToken = new SafeCancellationToken(); var executionContext = new ExecutionContext(this, args.Value.Value, args.Value.PreviousValue, outputChanged, contextCancellationToken); TaskUtils.StartLongRunning( () => action.SetValue(executionContext, string.Empty), (exception) => Log.ErrorFormat(exception, "Ошибка выполнения триггера [{0}][{1}]", Name, Id)); } } }; GetScenario().SetOnStateChanged(_lastSubscribe); } else { var lastVal = string.Empty; var timerCancellationToken = SystemUtils.StartTimer( (token) => { try { var curVal = GetScenario().CalculateCurrentValue(ViewActionSource, null); if (!lastVal.Equals(curVal)) { var prevVal = GetScenario().GetPreviousValue(); lastVal = curVal; contextCancellationToken.Cancel(); contextCancellationToken = new SafeCancellationToken(); var executionContext = new ExecutionContext(this, curVal, prevVal, new OutputChangedDelegates(), contextCancellationToken); try { TargetAction.SetValue(executionContext, string.Empty); } catch (Exception exception) { Log.ErrorFormat(exception, "Ошибка выполнения триггера [{0}][{1}]", Name, Id); } } } catch (Exception e) { Log.ErrorFormat(e, "Ошибка выполнения триггера [{0}][{1}]", Name, Id); } }, () => TriggerChangesListenInterval, true, ticksSuperposition: true /*наложение тиков*/); CancellationToken.RegisterCallback(timerCancellationToken.Cancel); } }