- Set up Tor container for SOCKS proxy (port 9050) - Configured Monero wallet with remote onion node - Bitcoin node continues syncing in background (60% complete) - Created documentation for wallet configuration steps - All external connections routed through Tor for privacy BTCPay requires manual wallet configuration through web interface: - Bitcoin: Need to add xpub/zpub for watch-only wallet - Monero: Need to add address and view key System ready for payment acceptance once wallets configured.
225 lines
8.7 KiB
C#
225 lines
8.7 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Telegram.Bot;
|
|
using Telegram.Bot.Polling;
|
|
using Telegram.Bot.Types;
|
|
using Telegram.Bot.Exceptions;
|
|
using Telegram.Bot.Types.Enums;
|
|
using TeleBot.Handlers;
|
|
using TeleBot.Services;
|
|
|
|
namespace TeleBot
|
|
{
|
|
public class TelegramBotService : IHostedService
|
|
{
|
|
private readonly IConfiguration _configuration;
|
|
private readonly ILogger<TelegramBotService> _logger;
|
|
private readonly IServiceProvider _serviceProvider;
|
|
private readonly ICommandHandler _commandHandler;
|
|
private readonly ICallbackHandler _callbackHandler;
|
|
private readonly IMessageHandler _messageHandler;
|
|
private readonly IMessageDeliveryService _messageDeliveryService;
|
|
private readonly BotManagerService _botManagerService;
|
|
private ITelegramBotClient? _botClient;
|
|
private CancellationTokenSource? _cancellationTokenSource;
|
|
private string? _currentBotToken;
|
|
|
|
public TelegramBotService(
|
|
IConfiguration configuration,
|
|
ILogger<TelegramBotService> logger,
|
|
IServiceProvider serviceProvider,
|
|
ICommandHandler commandHandler,
|
|
ICallbackHandler callbackHandler,
|
|
IMessageHandler messageHandler,
|
|
IMessageDeliveryService messageDeliveryService,
|
|
BotManagerService botManagerService)
|
|
{
|
|
_configuration = configuration;
|
|
_logger = logger;
|
|
_serviceProvider = serviceProvider;
|
|
_commandHandler = commandHandler;
|
|
_callbackHandler = callbackHandler;
|
|
_messageHandler = messageHandler;
|
|
_messageDeliveryService = messageDeliveryService;
|
|
_botManagerService = botManagerService;
|
|
}
|
|
|
|
public async Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
// Try to get bot token from API first via BotManagerService
|
|
var botToken = await GetBotTokenAsync();
|
|
|
|
// Fallback to configuration if API doesn't provide token
|
|
if (string.IsNullOrEmpty(botToken))
|
|
{
|
|
botToken = _configuration["Telegram:BotToken"];
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(botToken) || botToken == "YOUR_BOT_TOKEN_HERE")
|
|
{
|
|
_logger.LogError("Bot token not configured. Please either register via admin panel or set Telegram:BotToken in appsettings.json");
|
|
return;
|
|
}
|
|
|
|
_currentBotToken = botToken;
|
|
|
|
_botClient = new TelegramBotClient(botToken);
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
var receiverOptions = new ReceiverOptions
|
|
{
|
|
AllowedUpdates = Array.Empty<UpdateType>(),
|
|
ThrowPendingUpdates = true
|
|
};
|
|
|
|
_botClient.StartReceiving(
|
|
HandleUpdateAsync,
|
|
HandleErrorAsync,
|
|
receiverOptions,
|
|
cancellationToken: _cancellationTokenSource.Token
|
|
);
|
|
|
|
var me = await _botClient.GetMeAsync(cancellationToken);
|
|
_logger.LogInformation("Bot started: @{Username} ({Id})", me.Username, me.Id);
|
|
|
|
// Set bot client for message delivery service
|
|
if (_messageDeliveryService is MessageDeliveryService deliveryService)
|
|
{
|
|
deliveryService.SetBotClient(_botClient);
|
|
}
|
|
}
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
_cancellationTokenSource?.Cancel();
|
|
_logger.LogInformation("Bot stopped");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
if (update.Type == UpdateType.Message && update.Message != null)
|
|
{
|
|
var message = update.Message;
|
|
|
|
// Handle commands
|
|
if (message.Text != null && message.Text.StartsWith("/"))
|
|
{
|
|
var parts = message.Text.Split(' ', 2);
|
|
var command = parts[0].ToLower();
|
|
var args = parts.Length > 1 ? parts[1] : null;
|
|
|
|
await _commandHandler.HandleCommandAsync(botClient, message, command, args);
|
|
}
|
|
else
|
|
{
|
|
// Handle regular messages (for checkout flow, etc.)
|
|
await _messageHandler.HandleMessageAsync(botClient, message);
|
|
}
|
|
}
|
|
else if (update.Type == UpdateType.CallbackQuery && update.CallbackQuery != null)
|
|
{
|
|
await _callbackHandler.HandleCallbackAsync(botClient, update.CallbackQuery);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error handling update {UpdateId}", update.Id);
|
|
}
|
|
}
|
|
|
|
private Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
|
|
{
|
|
var errorMessage = exception switch
|
|
{
|
|
ApiRequestException apiException => $"Telegram API Error: [{apiException.ErrorCode}] {apiException.Message}",
|
|
_ => exception.ToString()
|
|
};
|
|
|
|
_logger.LogError(exception, "Bot error: {ErrorMessage}", errorMessage);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task<string?> GetBotTokenAsync()
|
|
{
|
|
try
|
|
{
|
|
// Check if we have a bot key stored
|
|
var botKey = _configuration["BotManager:ApiKey"];
|
|
if (string.IsNullOrEmpty(botKey))
|
|
{
|
|
_logger.LogInformation("No bot key configured. Bot will need to register first or use local token.");
|
|
return null;
|
|
}
|
|
|
|
// Fetch settings from API
|
|
var settings = await _botManagerService.GetSettingsAsync();
|
|
if (settings != null && settings.ContainsKey("telegram"))
|
|
{
|
|
if (settings["telegram"] is JsonElement telegramElement)
|
|
{
|
|
var telegramSettings = telegramElement.EnumerateObject().ToDictionary(p => p.Name, p => p.Value.ToString());
|
|
if (telegramSettings.TryGetValue("botToken", out var token))
|
|
{
|
|
_logger.LogInformation("Bot token fetched from admin panel successfully");
|
|
return token;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to fetch bot token from API. Will use local configuration.");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task UpdateBotTokenAsync(string newToken)
|
|
{
|
|
if (_botClient != null && _currentBotToken != newToken)
|
|
{
|
|
_logger.LogInformation("Updating bot token and restarting bot...");
|
|
|
|
// Stop current bot
|
|
_cancellationTokenSource?.Cancel();
|
|
|
|
// Create new bot client with new token
|
|
_currentBotToken = newToken;
|
|
_botClient = new TelegramBotClient(newToken);
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
var receiverOptions = new ReceiverOptions
|
|
{
|
|
AllowedUpdates = Array.Empty<UpdateType>(),
|
|
ThrowPendingUpdates = true
|
|
};
|
|
|
|
_botClient.StartReceiving(
|
|
HandleUpdateAsync,
|
|
HandleErrorAsync,
|
|
receiverOptions,
|
|
cancellationToken: _cancellationTokenSource.Token
|
|
);
|
|
|
|
var me = await _botClient.GetMeAsync();
|
|
_logger.LogInformation("Bot restarted with new token: @{Username} ({Id})", me.Username, me.Id);
|
|
|
|
// Update message delivery service
|
|
if (_messageDeliveryService is MessageDeliveryService deliveryService)
|
|
{
|
|
deliveryService.SetBotClient(_botClient);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |