Ejemplo n.º 1
0
        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;
        }