예제 #1
0
        /// <inheritdoc/>
        public override async Task Handle(UpdateDailyOutflow command)
        {
            var root = await _repository.Find <Wallet>(command.Target);

            if (root == null)
            {
                throw new ArgumentNullException(nameof(command.Address));
            }

            var coin = await _repository.Find <Coin>(root.Coin);

            if (coin == null)
            {
                throw new ArgumentNullException(nameof(root.Coin));
            }

            var txResults = await GetTransactions(command);

            if (txResults == null)
            {
                return;
            }

            var outflows = new Dictionary <Instant, (Instant time, double amount)>();

            foreach (var tx in txResults)
            {
                var dateTime = Instant.FromUnixTimeMilliseconds(tx.ReceiveTime).InUtc().LocalDateTime;
                var date     = new LocalDate(dateTime.Year, dateTime.Month, dateTime.Day);
                var instant  = date.AtMidnight().InUtc().ToInstant();
                var amount   = tx.Amount;
                if (tx.To == command.Target)
                {
                    amount *= -1;
                }

                if (outflows.ContainsKey(instant))
                {
                    amount += outflows[instant].amount;
                }
                outflows[instant] = (Instant.FromUnixTimeMilliseconds(tx.ReceiveTime), amount);
            }

            ICommand changeBalanceCommand = null;
            var      idx = 0;

            foreach (var v in outflows)
            {
                changeBalanceCommand = new RetroactiveCommand <ChangeWalletBalance>(new ChangeWalletBalance(command.Address, new Quantity(-v.Value.amount, coin.Asset), $"Out{command.Index}_{idx}"), v.Value.time);
                await _balanceHandler.Handle(changeBalanceCommand);

                ++idx;
            }

            command.EventType = changeBalanceCommand?.EventType;
        }
        /// <inheritdoc/>
        public override async Task Handle(UpdateDailyMining command)
        {
            var root = await _repository.Find <Wallet>(command.Target);

            if (root == null)
            {
                throw new ArgumentNullException(nameof(command.Address));
            }

            var coin = await _repository.Find <Coin>(root.Coin);

            if (coin == null)
            {
                throw new ArgumentNullException(nameof(root.Coin));
            }

            var minedBlocks = await GetMinedBlocks(command);

            if (minedBlocks == null)
            {
                return;
            }

            var blocks = new Dictionary <Instant, (Instant time, double amount)>();

            foreach (var block in minedBlocks)
            {
                var dateTime = Instant.FromUnixTimeMilliseconds(block.Timestamp).InUtc().LocalDateTime;
                var date     = new LocalDate(dateTime.Year, dateTime.Month, dateTime.Day);
                var instant  = date.AtMidnight().InUtc().ToInstant();
                var amount   = block.Feereward;
                if (blocks.ContainsKey(instant))
                {
                    amount += blocks[instant].amount;
                }
                blocks[instant] = (Instant.FromUnixTimeMilliseconds(block.Timestamp), amount);
            }

            ICommand mineCommand = null;
            var      idx         = 0;

            foreach (var v in blocks)
            {
                mineCommand = new RetroactiveCommand <MineCoin>(new MineCoin(command.Address, new Quantity(v.Value.amount, coin.Asset), $"Mining{command.Index}_{idx}"), v.Value.time);
                await _mineHandler.Handle(mineCommand);

                ++idx;
            }

            command.EventType = mineCommand?.EventType;
        }
예제 #3
0
        /// <inheritdoc/>
        public override async Task Handle(UpdateQuote command)
        {
            var root = await _repository.Find <AssetPair>(command.Target);

            if (root == null)
            {
                throw new ArgumentNullException(nameof(AssetPair));
            }

            if (root.QuoteDates.Any(d =>
                                    d.InUtc().Year == command.Timestamp.InUtc().Year&& d.InUtc().Month == command.Timestamp.InUtc().Month&&
                                    d.InUtc().Day == command.Timestamp.InUtc().Day))
            {
                throw new InvalidOperationException(
                          $"Quote already added for {command.Timestamp.InUtc().ToString("yyyy-MM-dd", new DateTimeFormatInfo())}");
            }

            ICommandHandler handler  = null;
            ICommand        commandT = null;

            if (root.ForAsset.AssetType == Asset.Type.Currency && root.DomAsset.AssetType == Asset.Type.Currency)
            {
                commandT = new UpdateQuote <Api.Fx.JsonResult>(command.Target)
                {
                    MessageId = command.MessageId
                };
                handler = _handlers.SingleOrDefault(h => h.CanHandle(commandT));
            }
            else if (root.ForAsset.AssetType == Asset.Type.Coin && root.DomAsset.AssetType == Asset.Type.Currency)
            {
                commandT = new UpdateQuote <Api.Coin.JsonResult>(command.Target)
                {
                    MessageId = command.MessageId
                };
                handler = _handlers.SingleOrDefault(h => h.CanHandle(commandT));
            }

            if (handler == null)
            {
                throw new InvalidOperationException($"Automatic quote retrieval for {root.ForAsset.Ticker}{root.DomAsset.Ticker} not supported");
            }

            await handler.Handle(commandT);

            command.EventType = commandT.EventType;
        }
예제 #4
0
        /// <inheritdoc />
        public virtual async Task Handle(TCommand command)
        {
            if (command == null)
            {
                throw new ArgumentNullException(typeof(TCommand).GetFriendlyName());
            }

            var root = await _repository.Find <TRoot>(command.Target, ComputeHash);

            if (root == null)
            {
                throw new ArgumentNullException(typeof(TRoot).GetFriendlyName());
            }
            if (command.Timestamp < root.Timestamp)
            {
                throw new InvalidOperationException(
                          $"{typeof(TCommand).Name} command ({command.Timestamp}) updating the past of the aggregate {typeof(TRoot).Name}:{command.Target} ({root.Timestamp}) ");
            }

            Act(root, command);

            if (command.UseTimestamp)
            {
                root.TimestampEvents(command.Timestamp);
            }

            var events    = root.GetUncommittedEvents().OfType <Event>().ToList();
            var eventType = events.Select(e => e.MessageType).SingleOrDefault();

            if (eventType == null)
            {
                throw new InvalidOperationException("More than one event type produced by a command");
            }
            foreach (var e in events)
            {
                e.CommandId     = command.MessageId;
                e.AncestorId    = command.MessageId;
                e.CorrelationId = command.CorrelationId;
            }

            command.EventType = eventType;

            await _repository.Save(root);
        }
예제 #5
0
            private async Task Handle(IEvent e)
            {
                // _log.Trace($"{typeof(TSaga).Name}.When({e.EventType}[{e.Stream}])");
                _log.Trace($"{e.MessageType}", typeof(TSaga).GetFriendlyName());

                try
                {
                    var   emptySaga     = new TSaga();
                    var   id            = emptySaga.SagaId(e);
                    var   isInitializer = emptySaga.IsInitializer(e);
                    TSaga saga;
                    if (isInitializer)
                    {
                        saga = await _repository.GetOrAdd <TSaga>(id);
                    }
                    else
                    {
                        saga = await _repository.Find <TSaga>(id);
                    }

                    if (saga == null)
                    {
                        return;
                    }
                    var saveEvent = ((Event)e).Copy();

                    saga.When(saveEvent);

                    var commands = saga.GetUncommittedCommands().OfType <Command>();
                    foreach (var c in commands)
                    {
                        c.AncestorId    = e.MessageId;
                        c.CorrelationId = id;
                    }

                    await _repository.Save(saga);
                }
                catch (Exception exception)
                {
                    _log.Errors.Add(exception);
                }
            }
예제 #6
0
 /// <summary>
 /// Repeated repository access until the aggregate root is found or timeout is reached
 /// </summary>
 /// <param name="repository">Aggregate root repository</param>
 /// <param name="id">Aggregate root id</param>
 /// <param name="predicate">Stop condition</param>
 /// <param name="timeout">Execution timeout</param>
 /// <param name="delay">Delay between repeating the bus calls</param>
 /// <typeparam name="T">Aggregate root type</typeparam>
 /// <returns>Task representing the asynchronous repeated find</returns>
 public static async Task <T> FindUntil <T>(this IEsRepository <IAggregate> repository, string id, Func <T, bool> predicate = null, TimeSpan timeout = default(TimeSpan), TimeSpan delay = default(TimeSpan))
     where T : class, IAggregate, new()
 {
     return(await RetryUntil(async() => await repository.Find <T>(id)));
 }