-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProcessService.cs
More file actions
154 lines (125 loc) · 6.9 KB
/
ProcessService.cs
File metadata and controls
154 lines (125 loc) · 6.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using Hackney.Core.JWT;
using Hackney.Core.Sns;
using Hackney.Shared.Processes.Domain;
using Hackney.Shared.Processes.Factories;
using ProcessesApi.V1.Services.Exceptions;
using ProcessesApi.V1.Services.Interfaces;
using Stateless;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Hackney.Shared.Processes.Domain.Constants;
using SharedPermittedTriggers = Hackney.Shared.Processes.Domain.Constants.SharedPermittedTriggers;
using Hackney.Shared.Processes.Sns;
namespace ProcessesApi.V1.Services
{
public class ProcessService : IProcessService
{
protected StateMachine<string, string> _machine;
protected ProcessState _currentState;
protected Process _process;
protected Type _permittedTriggersType;
protected List<string> GetPermittedTriggers()
{
var permittedTriggers = _permittedTriggersType?.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(string))
.Select(x => (string) x.GetRawConstantValue())
.ToList();
var sharedTriggers = typeof(SharedPermittedTriggers).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(string))
.Select(x => (string) x.GetRawConstantValue());
permittedTriggers.AddRange(sharedTriggers);
return permittedTriggers;
}
protected List<string> _ignoredTriggersForProcessUpdated;
protected Dictionary<string, object> _eventData;
protected ISnsGateway _snsGateway;
protected Token _token;
public ProcessService(ISnsGateway snsGateway)
{
_snsGateway = snsGateway;
}
protected async Task TransitionState(StateMachine<string, string>.Transition x)
{
var processRequest = x.Parameters[0] as ProcessTrigger;
var assignment = Assignment.Create("tenants"); // placeholder
var permittedTriggers = GetPermittedTriggers();
_currentState = ProcessState.Create(
_machine.State,
_machine.PermittedTriggers.Where(trigger => permittedTriggers.Contains(trigger)).ToList(),
assignment,
ProcessData.Create(processRequest.FormData, processRequest.Documents),
DateTime.UtcNow,
DateTime.UtcNow
);
await _process.AddState(_currentState);
await PublishProcessUpdatedEvent(x).ConfigureAwait(false);
}
private void ConfigureStateTransitions()
{
_machine.OnTransitionCompletedAsync(async x =>
{
await TransitionState(x).ConfigureAwait(false);
});
}
protected async Task PublishProcessStartedEvent(StateMachine<string, string>.Transition x, string additionalEvent = null)
{
await TransitionState(x).ConfigureAwait(false);
var processStartedSnsMessage = _process.CreateProcessStartedEvent(_token);
var processTopicArn = Environment.GetEnvironmentVariable("PROCESS_SNS_ARN");
await _snsGateway.Publish(processStartedSnsMessage, processTopicArn).ConfigureAwait(false);
if (additionalEvent is null) return;
var processEntityMessage = _process.CreateProcessStartedAgainstEntityEvent(_token, additionalEvent);
await _snsGateway.Publish(processEntityMessage, processTopicArn).ConfigureAwait(false);
}
protected async Task PublishProcessUpdatedEvent(StateMachine<string, string>.Transition transition)
{
if (!_ignoredTriggersForProcessUpdated.Contains(transition.Trigger))
{
var processTopicArn = Environment.GetEnvironmentVariable("PROCESS_SNS_ARN");
var processSnsMessage = transition.CreateProcessStateUpdatedEvent(_currentState.CreatedAt, _eventData, EventConstants.PROCESS_UPDATED_EVENT, _token);
await _snsGateway.Publish(processSnsMessage, processTopicArn).ConfigureAwait(false);
}
}
protected async Task PublishProcessClosedEvent(StateMachine<string, string>.Transition transition)
{
var processTopicArn = Environment.GetEnvironmentVariable("PROCESS_SNS_ARN");
var processSnsMessage = transition.CreateProcessStateUpdatedEvent(DateTime.UtcNow, _eventData, EventConstants.PROCESS_CLOSED_EVENT, _token);
await _snsGateway.Publish(processSnsMessage, processTopicArn).ConfigureAwait(false);
}
protected async Task PublishProcessCompletedEvent(StateMachine<string, string>.Transition transition)
{
var processTopicArn = Environment.GetEnvironmentVariable("PROCESS_SNS_ARN");
var processSnsMessage = transition.CreateProcessStateUpdatedEvent(DateTime.UtcNow, _eventData, EventConstants.PROCESS_COMPLETED_EVENT, _token);
await _snsGateway.Publish(processSnsMessage, processTopicArn).ConfigureAwait(false);
}
public async Task TriggerStateMachine(ProcessTrigger trigger)
{
var res = _machine.SetTriggerParameters<ProcessTrigger, Process>(trigger.Trigger);
await _machine.FireAsync(res, trigger, _process).ConfigureAwait(false);
}
protected virtual void SetUpStates()
{
// All services must implement the following lines to allow the first state to be initialised correctly:
// _machine.Configure(SharedStates.ApplicationInitialised)
// .Permit(SharedPermittedTriggers.StartApplication, SOME_STATE);
}
public async Task Process(ProcessTrigger processRequest, Process process, Token token)
{
_process = process;
_token = token;
var state = process.CurrentState is null ? SharedStates.ApplicationInitialised : process.CurrentState.State;
_machine = new StateMachine<string, string>(() => state, s => state = s);
var res = _machine.SetTriggerParameters<ProcessTrigger, Process>(processRequest.Trigger);
ConfigureStateTransitions();
SetUpStates();
var triggerIsPermitted = GetPermittedTriggers().Contains(processRequest.Trigger);
var canFire = triggerIsPermitted && _machine.CanFire(processRequest.Trigger);
if (!canFire)
throw new InvalidTriggerException(processRequest.Trigger, _machine.State);
await _machine.FireAsync(res, processRequest, process).ConfigureAwait(false);
}
}
}