async Task <SAFENetworkContext> RequireContextAsync(RootName root, string apiKey = null)
        {
            if (root == null)
            {
                throw new ArgumentNullException(nameof(root));
            }

            if (!_contextCache.TryGetValue(root, out SAFENetworkContext result))
            {
                var(stream, store) = await DbFactory.GetDriveDbsAsync(root, apiKey, _secretKey);

                _sequenceNr = new SequenceNr();

                var localState = new Memory.MemoryGateway();
                var driveCache = new Memory.SAFENetworkDriveCache(store, localState);
                var network    = new SAFENetworkEventService(stream, store, _secretKey);

                var materializer    = new DriveMaterializer(root, localState, _sequenceNr);
                var conflictHandler = new VersionConflictHandler(network, materializer);
                var driveWriter     = new DriveWriter(root, driveCache, _sequenceNr);

                var dbName     = Utils.Scrambler.Obfuscate(root.Value, _secretKey);
                var transactor = new EventTransactor(driveWriter,
                                                     new DiskWALTransactor(dbName, conflictHandler.Upload), _secretKey);
                _contextCache.Add(root, result = new SAFENetworkContext(transactor, new DriveReader(driveCache)));

                var _ = driveCache.GetDrive(root, apiKey, _parameters); // needs to be loaded

                // We need to wait for all events in local WAL to have been persisted to network
                // before we materialize new events from network.
                transactor.Start(_cancellation);             // start uploading to network
                while (DiskWALTransactor.AnyInQueue(dbName)) // wait until queue is empty
                {
                    await Task.Delay(500);                   // beware, this will - currently - spin eternally if there is an unresolved version conflict
                }
                // (todo: should load snapshot + all events since)
                var allEvents      = network.LoadAsync(fromVersion: 0);         // load all events from network (since we don't store it locally)
                var isMaterialized = await materializer.Materialize(allEvents); // recreate the filesystem locally in memory

                if (!isMaterialized)
                {
                    throw new InvalidDataException("Could not materialize network filesystem!");
                }
            }

            return(result);
        }
 public EventTransactor(DriveWriter driveWriter, DiskWALTransactor wal, string password)
 {
     _driveWriter = driveWriter;
     _wal         = wal;
     _password    = password;
 }