ProcessEvents(IReadOnlyList <string> serializedEvents) { lock (process) { var responses = serializedEvents.Select(serializedEvent => process.ProcessEvent(serializedEvent)) .ToImmutableList(); var compositionRecord = new CompositionRecordInFile { ParentHashBase16 = CommonConversion.StringBase16FromByteArray(lastStateHash), AppendedEvents = serializedEvents.Select(@event => new ValueInFile { LiteralString = @event }).ToImmutableList(), }; var serializedCompositionRecord = Encoding.UTF8.GetBytes(Serialize(compositionRecord)); var compositionHash = CompositionRecordInFile.HashFromSerialRepresentation(serializedCompositionRecord); lastStateHash = compositionHash; return(responses, (serializedCompositionRecord, compositionHash)); } }
public (byte[] serializedCompositionRecord, byte[] serializedCompositionRecordHash) SetState(string state) { lock (process) { process.SetSerializedState(state); var compositionRecord = new CompositionRecordInFile { ParentHashBase16 = CommonConversion.StringBase16FromByteArray(lastStateHash), SetState = new ValueInFile { LiteralString = state }, }; var serializedCompositionRecord = Encoding.UTF8.GetBytes(Serialize(compositionRecord)); var compositionHash = CompositionRecordInFile.HashFromSerialRepresentation(serializedCompositionRecord); lastStateHash = compositionHash; return(serializedCompositionRecord, compositionHash); } }
public PersistentProcessWithHistoryOnFileFromElm019Code( IProcessStoreReader storeReader, IImmutableDictionary <IImmutableList <string>, IImmutableList <byte> > elmAppFiles, Action <string> logger, ElmAppInterfaceConfig?overrideElmAppInterfaceConfig = null) { (process, (JavascriptFromElmMake, JavascriptPreparedToRun)) = ProcessFromElm019Code.ProcessFromElmCodeFiles(elmAppFiles, overrideElmAppInterfaceConfig); var restoreStopwatch = System.Diagnostics.Stopwatch.StartNew(); logger?.Invoke("Begin to restore the process state using the storeReader."); var emptyInitHash = CompositionRecordInFile.HashFromSerialRepresentation(new byte[0]); string dictKeyForHash(byte[] hash) => Convert.ToBase64String(hash); var compositionRecords = new Dictionary <string, (byte[] compositionRecordHash, CompositionRecord compositionRecord)>(); var compositionChain = new Stack <(byte[] hash, CompositionRecord composition)>(); foreach (var serializedCompositionRecord in storeReader.EnumerateSerializedCompositionsRecordsReverse()) { { var compositionRecordFromFile = JsonConvert.DeserializeObject <CompositionRecordInFile>( System.Text.Encoding.UTF8.GetString(serializedCompositionRecord)); var compositionRecordHash = CompositionRecordInFile.HashFromSerialRepresentation(serializedCompositionRecord); var compositionRecord = new CompositionRecord { ParentHash = CommonConversion.ByteArrayFromStringBase16(compositionRecordFromFile.ParentHashBase16), SetStateLiteralString = compositionRecordFromFile.SetState?.LiteralString, AppendedEventsLiteralString = compositionRecordFromFile.AppendedEvents?.Select(@event => @event.LiteralString)?.ToImmutableList(), }; var compositionChainElement = (compositionRecordHash, compositionRecord); if (!compositionChain.Any()) { compositionChain.Push(compositionChainElement); } else { compositionRecords[dictKeyForHash(compositionRecordHash)] = compositionChainElement; } } while (true) { var(compositionRecordHash, compositionRecord) = compositionChain.Peek(); var reduction = storeReader.GetReduction(compositionRecordHash); if (reduction != null || emptyInitHash.SequenceEqual(compositionRecord.ParentHash)) { if (reduction != null) { compositionChain.Pop(); process.SetSerializedState(reduction.ReducedValueLiteralString); lastStateHash = reduction.ReducedCompositionHash; } foreach (var followingComposition in compositionChain) { if (followingComposition.composition.SetStateLiteralString != null) { process.SetSerializedState(followingComposition.composition.SetStateLiteralString); } foreach (var appendedEvent in followingComposition.composition.AppendedEventsLiteralString.EmptyIfNull()) { process.ProcessEvent(appendedEvent); } lastStateHash = followingComposition.hash; } logger?.Invoke("Restored the process state in " + ((int)restoreStopwatch.Elapsed.TotalSeconds) + " seconds."); return; } var parentKey = dictKeyForHash(compositionRecord.ParentHash); if (!compositionRecords.TryGetValue(parentKey, out var compositionChainElementFromPool)) { break; } compositionChain.Push(compositionChainElementFromPool); compositionRecords.Remove(parentKey); } } if (compositionChain.Any()) { throw new NotImplementedException( "I did not find a reduction for any composition on the chain to the last composition (" + CommonConversion.StringBase16FromByteArray(compositionChain.Last().hash) + ")."); } logger?.Invoke("Found no composition record, default to initial state."); lastStateHash = emptyInitHash; }