using Nexus.Core; using Serilog; namespace Nexus.Bot; public class TradeQueue { private readonly Queue _queue = new(); private readonly TradeExecutor _executor; private readonly SavedSettings _config; private bool _processing; public TradeQueue(TradeExecutor executor, SavedSettings config) { _executor = executor; _config = config; } public int Length => _queue.Count; public bool IsProcessing => _processing; public void Clear() { _queue.Clear(); Log.Information("Trade queue cleared"); } public event Action? TradeCompleted; public event Action? TradeFailed; public void Enqueue(TradeInfo trade) { var existingIds = _queue.SelectMany(t => t.Items.Select(i => i.Id)).ToHashSet(); var newItems = trade.Items.Where(i => !existingIds.Contains(i.Id)).ToList(); if (newItems.Count == 0) { Log.Information("Skipping duplicate trade: {ItemIds}", string.Join(",", trade.Items.Select(i => i.Id))); return; } var deduped = trade with { Items = newItems }; _queue.Enqueue(deduped); Log.Information("Trade enqueued: {Count} items, queue={QueueLen}", newItems.Count, _queue.Count); _ = ProcessNext(); } private async Task ProcessNext() { if (_processing || _queue.Count == 0) return; _processing = true; var trade = _queue.Dequeue(); try { Log.Information("Processing trade: {SearchId} ({Count} items)", trade.SearchId, trade.Items.Count); var success = await _executor.ExecuteTrade(trade); if (success) { Log.Information("Trade completed"); TradeCompleted?.Invoke(); } else { Log.Information("Trade failed"); TradeFailed?.Invoke(); } } catch (Exception ex) { Log.Error(ex, "Trade execution error"); } _processing = false; await Helpers.RandomDelay(_config.BetweenTradesDelayMs, _config.BetweenTradesDelayMs + 3000); _ = ProcessNext(); } }