using Elsa.Common; using Elsa.Common.Codecs; using Elsa.Workflows.LogPersistence; using Elsa.Workflows.Management.Options; using Elsa.Workflows.Runtime.Entities; using Elsa.Workflows.Runtime.Extensions; using Elsa.Workflows.State; using Microsoft.Extensions.Options; namespace Elsa.Workflows.Runtime; /// public class DefaultActivityExecutionMapper( ISafeSerializer safeSerializer, IPayloadSerializer payloadSerializer, ICompressionCodecResolver compressionCodecResolver, IOptions options) : IActivityExecutionMapper { /// public async Task MapAsync(ActivityExecutionContext source) { var outputs = source.GetOutputs(); var inputs = source.GetInputs(); var persistenceMap = source.GetLogPersistenceModeMap(); var persistableInputs = GetPersistableInputOutput(inputs, persistenceMap.Inputs); var persistableOutputs = GetPersistableInputOutput(outputs, persistenceMap.Outputs); var persistableProperties = GetPersistableDictionary(source.Properties!, persistenceMap.InternalState); var persistableJournalData = GetPersistableDictionary(source.JournalData!, persistenceMap.InternalState); var cancellationToken = source.CancellationToken; var record = new ActivityExecutionRecord { Id = source.Id, ActivityId = source.Activity.Id, ActivityNodeId = source.NodeId, WorkflowInstanceId = source.WorkflowExecutionContext.Id, ActivityType = source.Activity.Type, ActivityName = source.Activity.Name, ActivityState = persistableInputs, Outputs = persistableOutputs, Properties = persistableProperties!, Metadata = new Dictionary(source.Metadata), Payload = persistableJournalData!, Exception = ExceptionState.FromException(source.Exception), ActivityTypeVersion = source.Activity.Version, StartedAt = source.StartedAt, HasBookmarks = source.Bookmarks.Any(), Status = source.Status, AggregateFaultCount = source.AggregateFaultCount, CompletedAt = source.CompletedAt, SchedulingActivityExecutionId = source.SchedulingActivityExecutionId, SchedulingActivityId = source.SchedulingActivityId, SchedulingWorkflowInstanceId = source.SchedulingWorkflowInstanceId, CallStackDepth = source.CallStackDepth }; record = record.SanitizeLogMessage(); var compressionAlgorithm = options.Value.CompressionAlgorithm ?? nameof(None); var serializedActivityState = record.ActivityState?.Count > 0 ? safeSerializer.Serialize(record.ActivityState) : null; var compressedSerializedActivityState = serializedActivityState != null ? await compressionCodecResolver.Resolve(compressionAlgorithm).CompressAsync(serializedActivityState, cancellationToken) : null; var serializedProperties = record.Properties != null ? payloadSerializer.Serialize(record.Properties) : null; var serializedMetadata = record.Metadata != null ? payloadSerializer.Serialize(record.Metadata) : null; record.SerializedSnapshot = new() { Id = record.Id, TenantId = record.TenantId, WorkflowInstanceId = record.WorkflowInstanceId, ActivityId = record.ActivityId, ActivityNodeId = record.ActivityNodeId, ActivityType = record.ActivityType, ActivityTypeVersion = record.ActivityTypeVersion, ActivityName = record.ActivityName, StartedAt = record.StartedAt, HasBookmarks = record.HasBookmarks, Status = record.Status, AggregateFaultCount = record.AggregateFaultCount, CompletedAt = record.CompletedAt, SerializedActivityState = compressedSerializedActivityState, SerializedActivityStateCompressionAlgorithm = compressionAlgorithm, SerializedOutputs = record.Outputs?.Any() == true ? safeSerializer.Serialize(record.Outputs) : null, SerializedProperties = serializedProperties, SerializedMetadata = serializedMetadata, SerializedException = record.Exception != null ? payloadSerializer.Serialize(record.Exception) : null, SerializedPayload = record.Payload?.Any() == true ? payloadSerializer.Serialize(record.Payload) : null }; return record; } private IDictionary GetPersistableInputOutput(IDictionary state, IDictionary map, bool deepCopy = false) { var result = new Dictionary(); foreach (var stateEntry in state) { var mode = map.TryGetValue(stateEntry.Key, out var value) ? value : LogPersistenceMode.Include; if (mode == LogPersistenceMode.Include) result.Add(stateEntry.Key, stateEntry.Value); } return result; } private IDictionary? GetPersistableDictionary(IDictionary dictionary, LogPersistenceMode mode) { return mode == LogPersistenceMode.Include ? new Dictionary(dictionary) : null; } }