- BTCPay Server integration - TeleBot Telegram bot - Review system - Admin area - Docker deployment configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
325 lines
12 KiB
C#
325 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Bogus;
|
|
using LittleShop.Client;
|
|
using LittleShop.Client.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace TeleBotClient
|
|
{
|
|
public class BotSimulator
|
|
{
|
|
private readonly ILittleShopClient _client;
|
|
private readonly ILogger<BotSimulator> _logger;
|
|
private readonly Random _random;
|
|
private readonly Faker _faker;
|
|
private List<Category> _categories = new();
|
|
private List<Product> _products = new();
|
|
|
|
public BotSimulator(ILittleShopClient client, ILogger<BotSimulator> logger)
|
|
{
|
|
_client = client;
|
|
_logger = logger;
|
|
_random = new Random();
|
|
_faker = new Faker();
|
|
}
|
|
|
|
public async Task<SimulationResult> SimulateUserSession()
|
|
{
|
|
var result = new SimulationResult
|
|
{
|
|
SessionId = Guid.NewGuid().ToString(),
|
|
StartTime = DateTime.UtcNow
|
|
};
|
|
|
|
try
|
|
{
|
|
_logger.LogInformation("🤖 Starting bot simulation session {SessionId}", result.SessionId);
|
|
|
|
// Step 1: Authenticate
|
|
_logger.LogInformation("📝 Authenticating with API...");
|
|
if (!await Authenticate())
|
|
{
|
|
result.Success = false;
|
|
result.ErrorMessage = "Authentication failed";
|
|
return result;
|
|
}
|
|
result.Steps.Add("✅ Authentication successful");
|
|
|
|
// Step 2: Browse categories
|
|
_logger.LogInformation("📁 Browsing categories...");
|
|
await BrowseCategories();
|
|
result.Steps.Add($"✅ Found {_categories.Count} categories");
|
|
|
|
// Step 3: Select random category and browse products
|
|
if (_categories.Any())
|
|
{
|
|
var selectedCategory = _categories[_random.Next(_categories.Count)];
|
|
_logger.LogInformation("🔍 Selected category: {Category}", selectedCategory.Name);
|
|
result.Steps.Add($"✅ Selected category: {selectedCategory.Name}");
|
|
|
|
await BrowseProducts(selectedCategory.Id);
|
|
result.Steps.Add($"✅ Found {_products.Count} products in category");
|
|
}
|
|
else
|
|
{
|
|
// Browse all products if no categories
|
|
await BrowseProducts(null);
|
|
result.Steps.Add($"✅ Found {_products.Count} total products");
|
|
}
|
|
|
|
// Step 4: Build shopping cart
|
|
_logger.LogInformation("🛒 Building shopping cart...");
|
|
var cart = BuildRandomCart();
|
|
result.Cart = cart;
|
|
result.Steps.Add($"✅ Added {cart.Items.Count} items to cart (Total: ${cart.TotalAmount:F2})");
|
|
|
|
// Step 5: Generate shipping information
|
|
_logger.LogInformation("📦 Generating shipping information...");
|
|
var shippingInfo = GenerateShippingInfo();
|
|
result.ShippingInfo = shippingInfo;
|
|
result.Steps.Add($"✅ Generated shipping to {shippingInfo.City}, {shippingInfo.Country}");
|
|
|
|
// Step 6: Create order
|
|
_logger.LogInformation("📝 Creating order...");
|
|
var order = await CreateOrder(cart, shippingInfo);
|
|
if (order != null)
|
|
{
|
|
result.OrderId = order.Id;
|
|
result.OrderTotal = order.TotalAmount;
|
|
result.Steps.Add($"✅ Order created: {order.Id}");
|
|
|
|
// Step 7: Select payment method
|
|
var currency = SelectRandomCurrency();
|
|
_logger.LogInformation("💰 Selected payment method: {Currency}", currency);
|
|
result.PaymentCurrency = currency;
|
|
result.Steps.Add($"✅ Selected payment: {currency}");
|
|
|
|
// Step 8: Create payment
|
|
var payment = await CreatePayment(order.Id, currency);
|
|
if (payment != null)
|
|
{
|
|
result.PaymentId = payment.Id;
|
|
result.PaymentAddress = payment.WalletAddress;
|
|
result.PaymentAmount = payment.RequiredAmount;
|
|
result.Steps.Add($"✅ Payment created: {payment.RequiredAmount} {currency}");
|
|
}
|
|
}
|
|
|
|
result.Success = true;
|
|
result.EndTime = DateTime.UtcNow;
|
|
result.Duration = result.EndTime - result.StartTime;
|
|
|
|
_logger.LogInformation("✅ Simulation completed successfully in {Duration}", result.Duration);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "❌ Simulation failed");
|
|
result.Success = false;
|
|
result.ErrorMessage = ex.Message;
|
|
result.EndTime = DateTime.UtcNow;
|
|
result.Duration = result.EndTime - result.StartTime;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task<bool> Authenticate()
|
|
{
|
|
var result = await _client.Authentication.LoginAsync("admin", "admin");
|
|
if (result.IsSuccess && result.Data != null && !string.IsNullOrEmpty(result.Data.Token))
|
|
{
|
|
_client.Authentication.SetToken(result.Data.Token);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private async Task BrowseCategories()
|
|
{
|
|
var result = await _client.Catalog.GetCategoriesAsync();
|
|
if (result.IsSuccess && result.Data != null)
|
|
{
|
|
_categories = result.Data;
|
|
}
|
|
}
|
|
|
|
private async Task BrowseProducts(Guid? categoryId)
|
|
{
|
|
var result = await _client.Catalog.GetProductsAsync(
|
|
pageNumber: 1,
|
|
pageSize: 50,
|
|
categoryId: categoryId
|
|
);
|
|
|
|
if (result.IsSuccess && result.Data != null)
|
|
{
|
|
_products = result.Data.Items;
|
|
}
|
|
}
|
|
|
|
private ShoppingCart BuildRandomCart()
|
|
{
|
|
var cart = new ShoppingCart();
|
|
|
|
if (!_products.Any())
|
|
return cart;
|
|
|
|
// Random number of items (1-5)
|
|
var itemCount = _random.Next(1, Math.Min(6, _products.Count + 1));
|
|
var selectedProducts = _products.OrderBy(x => _random.Next()).Take(itemCount).ToList();
|
|
|
|
foreach (var product in selectedProducts)
|
|
{
|
|
var quantity = _random.Next(1, 4); // 1-3 items
|
|
cart.AddItem(product.Id, product.Name, product.Price, quantity);
|
|
_logger.LogDebug("Added {Quantity}x {Product} @ ${Price}",
|
|
quantity, product.Name, product.Price);
|
|
}
|
|
|
|
return cart;
|
|
}
|
|
|
|
private ShippingInfo GenerateShippingInfo()
|
|
{
|
|
return new ShippingInfo
|
|
{
|
|
IdentityReference = $"SIM-{Guid.NewGuid().ToString().Substring(0, 8).ToUpper()}",
|
|
Name = _faker.Name.FullName(),
|
|
Address = _faker.Address.StreetAddress(),
|
|
City = _faker.Address.City(),
|
|
PostCode = _faker.Address.ZipCode(),
|
|
Country = _faker.PickRandom(new[] { "United Kingdom", "Ireland", "France", "Germany", "Netherlands" }),
|
|
Notes = _faker.Lorem.Sentence()
|
|
};
|
|
}
|
|
|
|
private async Task<Order?> CreateOrder(ShoppingCart cart, ShippingInfo shipping)
|
|
{
|
|
var request = new CreateOrderRequest
|
|
{
|
|
IdentityReference = shipping.IdentityReference,
|
|
ShippingName = shipping.Name,
|
|
ShippingAddress = shipping.Address,
|
|
ShippingCity = shipping.City,
|
|
ShippingPostCode = shipping.PostCode,
|
|
ShippingCountry = shipping.Country,
|
|
Notes = shipping.Notes,
|
|
Items = cart.Items.Select(i => new CreateOrderItem
|
|
{
|
|
ProductId = i.ProductId,
|
|
Quantity = i.Quantity
|
|
}).ToList()
|
|
};
|
|
|
|
var result = await _client.Orders.CreateOrderAsync(request);
|
|
return result.IsSuccess ? result.Data : null;
|
|
}
|
|
|
|
private string SelectRandomCurrency()
|
|
{
|
|
var currencies = new[] { "BTC", "XMR", "USDT", "LTC", "ETH", "ZEC", "DASH", "DOGE" };
|
|
|
|
// Weight towards BTC and XMR
|
|
var weights = new[] { 30, 25, 15, 10, 10, 5, 3, 2 };
|
|
var totalWeight = weights.Sum();
|
|
var randomValue = _random.Next(totalWeight);
|
|
|
|
var currentWeight = 0;
|
|
for (int i = 0; i < currencies.Length; i++)
|
|
{
|
|
currentWeight += weights[i];
|
|
if (randomValue < currentWeight)
|
|
return currencies[i];
|
|
}
|
|
|
|
return "BTC";
|
|
}
|
|
|
|
private async Task<CryptoPayment?> CreatePayment(Guid orderId, string currency)
|
|
{
|
|
var currencyInt = ConvertCurrencyToEnum(currency);
|
|
var result = await _client.Orders.CreatePaymentAsync(orderId, currencyInt);
|
|
return result.IsSuccess ? result.Data : null;
|
|
}
|
|
|
|
private static int ConvertCurrencyToEnum(string currency)
|
|
{
|
|
return currency.ToUpper() switch
|
|
{
|
|
"BTC" => 0,
|
|
"XMR" => 1,
|
|
"USDT" => 2,
|
|
"LTC" => 3,
|
|
"ETH" => 4,
|
|
"ZEC" => 5,
|
|
"DASH" => 6,
|
|
"DOGE" => 7,
|
|
_ => 0 // Default to BTC
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SimulationResult
|
|
{
|
|
public string SessionId { get; set; } = string.Empty;
|
|
public bool Success { get; set; }
|
|
public string? ErrorMessage { get; set; }
|
|
public DateTime StartTime { get; set; }
|
|
public DateTime EndTime { get; set; }
|
|
public TimeSpan Duration { get; set; }
|
|
public List<string> Steps { get; set; } = new();
|
|
|
|
// Order details
|
|
public Guid? OrderId { get; set; }
|
|
public decimal OrderTotal { get; set; }
|
|
public ShoppingCart? Cart { get; set; }
|
|
public ShippingInfo? ShippingInfo { get; set; }
|
|
|
|
// Payment details
|
|
public Guid? PaymentId { get; set; }
|
|
public string? PaymentCurrency { get; set; }
|
|
public string? PaymentAddress { get; set; }
|
|
public decimal PaymentAmount { get; set; }
|
|
}
|
|
|
|
public class ShoppingCart
|
|
{
|
|
public List<CartItem> Items { get; set; } = new();
|
|
public decimal TotalAmount => Items.Sum(i => i.TotalPrice);
|
|
|
|
public void AddItem(Guid productId, string name, decimal price, int quantity)
|
|
{
|
|
Items.Add(new CartItem
|
|
{
|
|
ProductId = productId,
|
|
ProductName = name,
|
|
UnitPrice = price,
|
|
Quantity = quantity,
|
|
TotalPrice = price * quantity
|
|
});
|
|
}
|
|
}
|
|
|
|
public class CartItem
|
|
{
|
|
public Guid ProductId { get; set; }
|
|
public string ProductName { get; set; } = string.Empty;
|
|
public decimal UnitPrice { get; set; }
|
|
public int Quantity { get; set; }
|
|
public decimal TotalPrice { get; set; }
|
|
}
|
|
|
|
public class ShippingInfo
|
|
{
|
|
public string IdentityReference { get; set; } = string.Empty;
|
|
public string Name { get; set; } = string.Empty;
|
|
public string Address { get; set; } = string.Empty;
|
|
public string City { get; set; } = string.Empty;
|
|
public string PostCode { get; set; } = string.Empty;
|
|
public string Country { get; set; } = string.Empty;
|
|
public string? Notes { get; set; }
|
|
}
|
|
} |