public async Task CreateFoo(FooDto item)
        {
            var doc = _mapper.Map <FooDoc>(item);

            using (var session = await _client.StartSessionAsync())
            {
                await _collection.InsertOneAsync(session, doc);
            }
        }
Beispiel #2
0
        public UnitOfWorkTest()
        {
            transactionOptions = new TransactionOptions(readPreference: ReadPreference.Primary, readConcern: ReadConcern.Local, writeConcern: WriteConcern.WMajority);
            cancellationToken  = CancellationToken.None;

            clientSessionHandle = Substitute.For <IClientSessionHandle>();
            clientSessionHandle
            .WithTransactionAsync(
                Arg.Any <Func <IClientSessionHandle, CancellationToken, Task <bool> > >(),
                Arg.Any <TransactionOptions>(),
                Arg.Any <CancellationToken>())
            .Returns(true);

            clientSessionHandle
            .WithTransaction(
                Arg.Any <Func <IClientSessionHandle, CancellationToken, bool> >(),
                Arg.Any <TransactionOptions>(),
                Arg.Any <CancellationToken>())
            .Returns(true);

            mongoClient = Substitute.For <IMongoClient>();
            mongoClient.StartSessionAsync().Returns(clientSessionHandle);
            mongoClient.StartSession().Returns(clientSessionHandle);

            unitOfWork = new UnitOfWorkMongo.UnitOfWork(mongoClient, transactionOptions);
        }
 private static Task <IClientSessionHandle> GetSessionAsync(
     IMongoClient client,
     ClientSessionOptions options,
     CancellationToken ctok = default)
 {
     return(client.StartSessionAsync(options, ctok));
 }
Beispiel #4
0
        public async Task <ITransaction> StartTransaction(CancellationToken token)
        {
            var session = await _mongoClient.StartSessionAsync(null, token);

            session.StartTransaction();
            return(new MongoDbTransaction(session));
        }
Beispiel #5
0
        public override async Task <IList <TransactionLog> > PerformTransactions(
            IEnumerable <Transaction <T> > transactions,
            CancellationToken token = default)
        {
            List <Action> adjustBalanceActions = new List <Action>();

            using IClientSessionHandle session = await _mongoClient.StartSessionAsync(cancellationToken : token);

            var transactionLogEntries = await session.WithTransactionAsync(async (sessionInner, tokenInner) =>
            {
                IList <TransactionLog> logEntries = new List <TransactionLog>();
                foreach (Transaction <T> transaction in transactions)
                {
                    TransactionLog log = await PerformSingleTransaction(transaction, sessionInner, tokenInner);
                    // defer all in-memory adjustments until the end in case any of the transactions failed.
                    adjustBalanceActions.Add(() => _currencyFieldSetter(transaction.User, log.NewBalance));
                    logEntries.Add(log);
                }
                return(logEntries);
            },
                                                                           new TransactionOptions(), token);

            await session.CommitTransactionAsync(token);

            adjustBalanceActions.ForEach(action => action());
            return(transactionLogEntries);
        }
Beispiel #6
0
        public async Task <IClientSessionHandle> StartSession(CancellationToken cancellactionToken = default(CancellationToken))
        {
            var session = await _client.StartSessionAsync(cancellationToken : cancellactionToken);

            Session = session;
            return(session);
        }
        public async Task <IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
        {
            var session = await _mongoClient.StartSessionAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

            CurrentTransaction = new MongoDbContextTransaction(session);
            return(CurrentTransaction);
        }
Beispiel #8
0
        public async Task <ITransaction> StartTransactionAsync()
        {
            IClientSessionHandle session = await _client.StartSessionAsync();

            session.StartTransaction();
            return(new MongoTransaction(session));
        }
Beispiel #9
0
        /// <summary>
        /// Start Transaction
        /// </summary>
        public async Task StartTransaction()
        {
            _transactionStartDateTime = DateTime.Now;

            _session = await _client.StartSessionAsync();

            _session.StartTransaction();
        }
        public async Task EnsureSessionCreatedAsync()
        {
            if (SessionHandle != null)
            {
                return;
            }

            SessionHandle = await Client.StartSessionAsync(new ClientSessionOptions { CausalConsistency = false });
        }
Beispiel #11
0
        public async Task <IEnumerable <TodoReadDTO> > GetTodoList()
        {
            _logger.LogInformation("Call to GetTodo function was made");
            using (var session = await _client.StartSessionAsync())
            {
                try
                {
                    List <TodoReadDTO> models = new List <TodoReadDTO>();
                    //var results = await this.Todos.Find<TodoModel>(session, new BsonDocument()).ToListAsync();
                    var results = await this.Todos.Find <TodoModel>(session, x => true).ToListAsync();

                    foreach (var item in results)
                    {
                        var modelDTO = _mapper.Map <TodoReadDTO>(item);
                        models.Add(modelDTO);
                    }

                    _logger.LogInformation("Call to GetTodo function completed.");

                    return(models);
                }
                catch (Exception ex)
                {
                    _logger.LogInformation("Call to GetTodo function was terminated.");
                    throw new Exception("Call to GetTodo function was terminated.");
                }
            }
        }
        public async Task <ITransaction> StartTransaction(CancellationToken token)
        {
            if (_options.SupportTransaction)
            {
                _session = await _mongoClient.StartSessionAsync(null, token);

                _session.StartTransaction();
                return(new MongoDbTransaction(_session));
            }

            _session = null;
            return(new MongoDbTransaction());
        }
Beispiel #13
0
        public async Task <int> SaveChanges()
        {
            using (Session = await _client.StartSessionAsync())
            {
                Session.StartTransaction();
                var commandTasks = _commands.Select(x => x());
                await Task.WhenAll(commandTasks);

                await Session.CommitTransactionAsync();
            }

            return(_commands.Count);
        }
Beispiel #14
0
        public async Task <T> ExecuteInTransaction <T>(Func <IClientSessionHandle, CancellationToken, Task <T> > execute,
                                                       CancellationToken cancellationToken)
        {
            using (var session = await _client.StartSessionAsync(new ClientSessionOptions(), cancellationToken))
            {
                var transactionOptions = new TransactionOptions(
                    readPreference: ReadPreference.Primary,
                    readConcern: ReadConcern.Majority,
                    writeConcern: WriteConcern.W1);

                return(await session.WithTransactionAsync(
                           execute,
                           transactionOptions,
                           cancellationToken));
            }
        }
        public async Task <bool> CommitTransactionAsync()
        {
            using (var session = await _mongoClient.StartSessionAsync())
            {
                session.StartTransaction();
                var commandTasks = _commands.Select(c => c());
                await Task.WhenAll(commandTasks);

                await session.CommitTransactionAsync();

                _commands.Clear();
                IsInTransaction = false;
            }


            return(_commands.Count > 0);
        }
Beispiel #16
0
        private async Task <IClientSessionHandle> CreateSessionAsync(IMongoClient client, CancellationToken cancellationToken = default)
        {
            var stopwatch = Logger.StartStopwatch();

            Logger.LogInformation($"Start CreateSessionAsync");

            var session = await client.StartSessionAsync(cancellationToken : cancellationToken);

            if (_dbContextOptions.Timeout.HasValue)
            {
                session.AdvanceOperationTime(new BsonTimestamp(_dbContextOptions.Timeout.Value));
            }

            session.StartTransaction();

            stopwatch?.Stop();
            Logger.LogInformation("End CreateSessionAsync, elapsed time: {elapsedTime}", Logger.GetElapsedTime(stopwatch));
            stopwatch = null;

            return(session);
        }
Beispiel #17
0
        private static async Task MakeSureDatabaseCreated(IMongoClient mongoDbClient)
        {
            try
            {
                var database = mongoDbClient.GetDatabase("BookStoreDB");

                using (var session = await mongoDbClient.StartSessionAsync())
                {
                    var collections = DbCollection.All();

                    foreach (var collectionName in collections)
                    {
                        if (await database.ExistsCollection(collectionName))
                        {
                            continue;
                        }

                        await database.CreateCollectionAsync(session, collectionName);
                    }

                    //var bookCollection = database.GetCollection<Book>("Book");

                    //bookCollection.InsertOne(new Book
                    //{
                    //	Name = "First book",
                    //	Author = "Tan Nguyen",
                    //	Category = "No name",
                    //	CreatedAt = DateTime.Now,
                    //	CreatedBy = "Tan"
                    //});
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                //
                // TODO: Handle can't make sure database created
                throw;
            }
        }
        public async Task StoreAsync(AuditTrailRecord record, CancellationToken cancellationToken)
        {
            var hash = new byte[Sha256.Sha256HashSize];

            Sha256.Shared.ComputeHash(record.Raw.Span, hash);
            SignedTreeHead?signedTreeHead = null;

            if (_tree != null)
            {
                signedTreeHead = await _tree.AppendAsync(hash);
            }

            var payload = record.Token.Payload !;

            // Is it posible to fail here ?
            MemoryMarshal.TryGetArray(record.Raw, out var segment);
            var block = new AuditTrailBlock
                        (
                iss: payload[JwtClaimNames.Iss.EncodedUtf8Bytes].GetString() !,
                jti: payload[JwtClaimNames.Jti.EncodedUtf8Bytes].GetString() !,
                iat: payload[JwtClaimNames.Iat.EncodedUtf8Bytes].GetInt64(),
                aud: payload[JwtClaimNames.Aud.EncodedUtf8Bytes].GetStringArray() !,
                txn: payload[SecEventClaimNames.Txn].GetString(),
                toe: payload[SecEventClaimNames.Toe].GetInt64(),
                events: payload[SecEventClaimNames.Events.EncodedUtf8Bytes].GetJsonDocument(),
                raw: segment.Array !,
                hash: hash,
                rootHash: signedTreeHead?.Hash
                        );

            using var session = await _client.StartSessionAsync(cancellationToken : cancellationToken);

            try
            {
                session.StartTransaction();
                await _auditTrails.InsertOneAsync(block, cancellationToken : cancellationToken);

                //var kid = record.Token.Header[JwtHeaderParameterNames.Kid.EncodedUtf8Bytes].GetString()!;
                //if (!_keyringInMemory.HasKey(kid))
                //{
                //    var filter = Builders<Keyring>.Filter.Eq("keys.kid", kid);
                //    var storedKey = await _keyring.Find(filter).FirstOrDefaultAsync(cancellationToken);
                //    if (storedKey is null)
                //    {
                //        var key = SerializeKey(record.Token.SigningKey!);
                //        var jwksFilter = Builders<Keyring>.Filter.Eq("iss", record.Issuer);
                //        var push = Builders<Keyring>.Update.Push("keys", key)
                //            .SetOnInsert("iss", record.Issuer);
                //        await _keyring.UpdateOneAsync(jwksFilter, push, new UpdateOptions { IsUpsert = true }, cancellationToken);
                //    }
                //}

                await session.CommitTransactionAsync(cancellationToken);
            }
            catch (MongoWriteException e) when(e.WriteError.Category == ServerErrorCategory.DuplicateKey)
            {
                _logger.LogWarning("Duplicate document. The document will be ignored.");
                await session.AbortTransactionAsync();
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Failed to store the document.");
                await session.AbortTransactionAsync();
            }

            _logger.LogInformation("'{Jti}' has been recorded.", block.Jti);
        }
Beispiel #19
0
 public Task <IClientSessionHandle> StartSessionAsync(ClientSessionOptions?clientSessionOptions = null, CancellationToken cancellationToken = default)
 => _client.StartSessionAsync(clientSessionOptions, cancellationToken);
 public Task <IClientSessionHandle> CreateAsync()
 {
     return(_client.StartSessionAsync());
 }
Beispiel #21
0
 public virtual Task <IClientSessionHandle> StartSessionAsync(CancellationToken cancellationToken)
 {
     return(Client.StartSessionAsync(cancellationToken: cancellationToken));
 }
Beispiel #22
0
 public Task <IClientSessionHandle> StartSessionAsync(
     ClientSessionOptions?options        = null,
     CancellationToken cancellationToken = default)
 {
     return(_client.StartSessionAsync(options, cancellationToken));
 }
        /// <inheritdoc />
        public async Task <string[]> Delete(string requestingUserId, string directoryId)
        {
            using var session = await client.StartSessionAsync();

            session.StartTransaction();

            try
            {
                var deleteResult = await directoryCollection.FindOneAndDeleteAsync(session, x =>
                                                                                   x.Id == directoryId &&
                                                                                   x.IsRootDirectory == false &&
                                                                                   x.Permissions.Any(y =>
                                                                                                     y.Permission.HasFlag(Permission.ReadWrite) &&
                                                                                                     y.UserId == requestingUserId
                                                                                                     ));

                // If the result is null permissions are not granted or directory does not exists or is not
                // deletable in the case of the root directory
                if (deleteResult == null)
                {
                    throw new ObjectNotResolvableException(
                              $"Deletion of directory {directoryId} could not be performed by user {requestingUserId}");
                }

                // Find subdirectories and get a list of all files
                var subDirectories = await directoryCollection
                                     .AsQueryable()
                                     .Where(x => x.PathIds.Contains(directoryId))
                                     .Select(x => new
                {
                    Id    = x.Id,
                    Files = x.FileIds
                })
                                     .ToListAsync();

                // Delete subdirectories
                var directoryIds        = subDirectories.Select(x => x.Id);
                var deleteDirectoryTask = directoryCollection.DeleteManyAsync(session, x => directoryIds.Contains(x.Id));

                // Delete files
                var fileIds = subDirectories.SelectMany(x => x.Files).ToArray();

                var deleteFilesTask = filesCollection.DeleteManyAsync(session, x => fileIds.Contains(x.Id));

                // Get all revisions (in order to remove bucket blobs later on)
                var revisionIds = await fileRevisionCollection
                                  .AsQueryable()
                                  .Where(x => fileIds.Contains(x.File))
                                  .Select(x => x.Id)
                                  .ToListAsync();

                // Delete file revisions
                var deleteRevisionsTask = fileRevisionCollection.DeleteManyAsync(session, x => fileIds.Contains(x.File));

                await Task.WhenAll(deleteDirectoryTask, deleteFilesTask, deleteRevisionsTask);

                await session.CommitTransactionAsync();

                return(revisionIds.ToArray());
            }
            catch (ObjectNotResolvableException)
            {
                await session.AbortTransactionAsync();

                throw;
            }
            catch (InvalidParameterException)
            {
                await session.AbortTransactionAsync();

                throw;
            }
            catch (MongoException e)
            {
                await session.AbortTransactionAsync();

                throw new DatabaseException("Database error during file inserting. See inner exception.", e);
            }
            catch (Exception e)
            {
                await session.AbortTransactionAsync();

                throw new Exception("Unknown error during file inserting. See inner exception.", e);
            }
        }
Beispiel #24
0
        public async Task BeginTransactionAsync()
        {
            _session = await _mongoClient.StartSessionAsync();

            _session.StartTransaction();
        }
        /// <inheritdoc />
        public async Task <string[]> Delete(string requestingUserId, string fileId)
        {
            using var session = await client.StartSessionAsync();

            try
            {
                session.StartTransaction();

                var directoryUpdate = Builders <DirectoryDto> .Update.Pull(x => x.FileIds, fileId);

                var updatedDirectoryTask = await directoryCollection.UpdateOneAsync(session,
                                                                                    x =>
                                                                                    x.FileIds.Contains(fileId) &&
                                                                                    (x.OwnerId == requestingUserId ||
                                                                                     x.Permissions.Any(y =>
                                                                                                       y.Permission.HasFlag(Permission.ReadWrite) &&
                                                                                                       y.UserId == requestingUserId
                                                                                                       )),
                                                                                    directoryUpdate);


                if (updatedDirectoryTask.ModifiedCount == 0)
                {
                    throw new ObjectNotResolvableException(
                              $"Parent directory of file {fileId} could not be found or accessed by user {requestingUserId} during file delete");
                }

                if (updatedDirectoryTask.ModifiedCount > 1)
                {
                    throw new UnexpectedBehaviourException(
                              $"Delete of file {fileId} by user {requestingUserId} changed {updatedDirectoryTask.ModifiedCount} parent directories but must exactly change 1");
                }

                var revisionsTask  = fileRevisionCollection.DeleteManyAsync(session, x => x.File == fileId);
                var deleteFileTask = filesCollection.FindOneAndDeleteAsync(
                    session,
                    x => x.Id == fileId, new FindOneAndDeleteOptions <FileDto, TempRevisionView>
                {
                    Projection = Builders <FileDto> .Projection.Include(x => x.RevisionIds)
                });

                await Task.WhenAll(deleteFileTask, revisionsTask);

                await session.CommitTransactionAsync();

                return(deleteFileTask.Result.RevisionIds.ToArray());
            }
            catch (ObjectNotResolvableException)
            {
                await session.AbortTransactionAsync();

                throw;
            }
            catch (UnexpectedBehaviourException)
            {
                await session.AbortTransactionAsync();

                throw;
            }
            catch (MongoException e)
            {
                await session.AbortTransactionAsync();

                throw new DatabaseException("Database error during file delete. See inner exception.", e);
            }
            catch (Exception e)
            {
                await session.AbortTransactionAsync();

                throw new Exception("Unknown error during file delete. See inner exception.", e);
            }
        }
        public async Task <SignedTreeHead> AppendAsync(byte[] hash)
        {
            MerkleNode leafNode = new MerkleNode(_hasher.HashLeaf(hash));
            var        session  = await _client.StartSessionAsync();

            try
            {
                //session.StartTransaction();
                var root = await _roots.Find(session, _ => true)
                           .Sort(new SortDefinitionBuilder <MerkleRoot>()
                                 .Descending(r => r.TreeSize)).Limit(1).SingleOrDefaultAsync();

                if (root is null)
                {
                    MerkleLeaf leaf = new MerkleLeaf(0, _hasher.HashLeaf(hash));
                    await _leaves.InsertOneAsync(session, leaf);

                    await _nodes.InsertOneAsync(session, leafNode);

                    root = new MerkleRoot(leafNode.Level, leafNode.Hash, 1ul, _signer.Sign(leafNode.Hash), "");
                    await _roots.InsertOneAsync(session, root);
                }
                else
                {
                    var existingLeaf = await _leaves.Find(session, n => n.Hash == leafNode.Hash).AnyAsync();

                    if (existingLeaf)
                    {
                        _logger.LogInformation("The leaf {leafHash} already exist in the tree {treeHash}. Nothing was appended.", hash.ByteToHex(), root.Hash.ByteToHex());
                        return(CreateSignedTreeHead(root));
                    }
                    else
                    {
                        var nodesToInsert = new List <MerkleNode>(root.Level + 1)
                        {
                            leafNode
                        };
                        var stack       = new Stack <MerkleNode>(root.Level + 1);
                        var currentNode = await _nodes.Find(session, n => n.Hash == root.Hash).SingleAsync();

                        MerkleNode node;
                        if (currentNode.IsFull)
                        {
                            bool isFullNode = currentNode.Level == leafNode.Level && leafNode.IsFull;
                            node = new MerkleNode(new[] { currentNode.Hash, leafNode.Hash }, currentNode.Level + 1, _hasher.HashNode(currentNode.Hash, leafNode.Hash), isFullNode);
                            nodesToInsert.Add(node);
                        }
                        else
                        {
                            do
                            {
                                var left = await _nodes.Find(session, n => n.Hash == currentNode.Left).SingleAsync();

                                stack.Push(left);
                                var right = await _nodes.Find(session, n => n.Hash == currentNode.Right).SingleAsync();

                                currentNode = right;
                            } while (!currentNode.IsFull);

                            stack.Push(currentNode);
                            stack.Push(leafNode);
                            do
                            {
                                var  right      = stack.Pop();
                                var  left       = stack.Pop();
                                bool isFullNode = left.Level == right.Level && left.IsFull && right.IsFull;
                                node = new MerkleNode(new[] { left.Hash, right.Hash }, left.Level + 1, _hasher.HashNode(left.Hash, right.Hash), isFullNode);

                                nodesToInsert.Add(node);
                                stack.Push(node);
                            } while (stack.Count != 1);
                        }

                        MerkleLeaf leaf = new MerkleLeaf(root.TreeSize, _hasher.HashLeaf(hash));
                        await _leaves.InsertOneAsync(session, leaf);

                        await _nodes.InsertManyAsync(session, nodesToInsert);

                        root = new MerkleRoot(node.Level, node.Hash, root.TreeSize + 1, _signer.Sign(node.Hash), "");
                        await _roots.InsertOneAsync(session, root);
                    }
                }

                //session.CommitTransaction();
                _logger.LogInformation("The leaf {leafHash} was appended to tree {treeHash}.", hash.ByteToHex(), root.Hash.ByteToHex());
                return(CreateSignedTreeHead(root));
            }
            catch (Exception e)
            {
                //session.AbortTransaction();
                _logger.LogError(e, "An error occurred while appending the leaf {leaf}.", hash.ByteToHex());
                throw new MerkleTreeException($"An error occurred while appending the leaf {hash.ByteToHex()}.", e);
            }
        }
 public Task <IClientSessionHandle> CreateAsync()
 => _client.StartSessionAsync();
Beispiel #28
0
        public async Task <TResult> WithTransactionAsync <TResult>(Func <IClientSessionHandle, CancellationToken, Task <TResult> > callbackAsync, CancellationToken cancellationToken = default)
        {
            using var session = await mongoClient.StartSessionAsync();

            return(await session.WithTransactionAsync(callbackAsync, transactionOptions, cancellationToken));
        }
Beispiel #29
0
 public Task <IClientSessionHandle> StartSessionAsync(ClientSessionOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
 {
     return(wrapped.StartSessionAsync(options, cancellationToken));
 }
Beispiel #30
0
        /// <inheritdoc />
        public async Task <bool> InsertUser(string userId, string rootDirectoryId, string email, string hashedPassword, string salt,
                                            string publicKey, string encryptedPrivateKey)
        {
            using (var session = await client.StartSessionAsync())
            {
                // Begin transaction
                session.StartTransaction();

                try
                {
                    var newRootDirectory = new DirectoryDto
                    {
                        Id = rootDirectoryId,
                        IsRootDirectory = true,
                        OwnerId         = userId,
                        ObjectName      = "__root_dir__",
                        DirectoryIds    = new List <string>(),
                        FileIds         = new List <string>(),
                        PathIds         = new[] { rootDirectoryId },
                        Permissions     = new[]
                        {
                            new BasicPermissionDto
                            {
                                UserId     = userId,
                                Permission = Permission.Read | Permission.ReadWrite | Permission.ReadPermissions | Permission.ReadWritePermissions
                            }
                        },
                    };
                    var insertRootDirectoryTask = directoryCollection.InsertOneAsync(session, newRootDirectory);

                    var newUser = new UserDto
                    {
                        Id                  = userId,
                        RootDirectory       = newRootDirectory.Id,
                        Email               = email,
                        PasswordHash        = hashedPassword,
                        Salt                = salt,
                        PublicKey           = publicKey,
                        EncryptedPrivateKey = encryptedPrivateKey
                    };
                    var insertUserTask = userCollection.InsertOneAsync(session, newUser);

                    await Task.WhenAll(insertRootDirectoryTask, insertUserTask);

                    await session.CommitTransactionAsync();
                }
                catch (MongoException e)
                {
                    await session.AbortTransactionAsync();

                    throw new DatabaseException("Database error during user creating. See inner exception.", e);
                }
                catch (Exception e)
                {
                    await session.AbortTransactionAsync();

                    throw new Exception("Unknown error during file inserting. See inner exception.", e);
                }
            }

            return(true);
        }