feat(logging): replace 207 console.log/error/warn with pino structured logger (#58)

- Add pino + pino-pretty dependencies
- Create src/utils/logger.js with env-based LOG_LEVEL
- Replace all 207 console.log/error/warn calls across 46 source files
- Remove [DEBUG], [ERROR] string prefixes (levels convey this)
- Add pino redact for sensitive fields (mnemonic, privateKey, token, etc.)
- Structured logging with context objects instead of string interpolation
- NODE_ENV=production disables pino-pretty transport

49 files changed, 5601 insertions, 6056 deletions
This commit is contained in:
NW
2026-06-22 01:42:47 +01:00
parent ba80784ae7
commit ce1b6003cb
49 changed files with 5624 additions and 6079 deletions

11197
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,15 +11,16 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"bip39": "^3.1.0", "bip39": "^3.1.0",
"bitcoinjs-lib": "^6.1.6", "bitcoinjs-lib": "^6.1.6",
"csv-writer": "^1.6.0",
"decompress": "^4.2.1", "decompress": "^4.2.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"ecpair": "^2.1.0", "ecpair": "^2.1.0",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"hdkey": "^2.1.0", "hdkey": "^2.1.0",
"node-telegram-bot-api": "^0.64.0", "node-telegram-bot-api": "^0.64.0",
"pino": "^8.21.0",
"sqlite3": "^5.1.6", "sqlite3": "^5.1.6",
"tiny-secp256k1": "^2.2.3", "tiny-secp256k1": "^2.2.3"
"csv-writer": "^1.6.0"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.0.2" "nodemon": "^3.0.2"

View File

@@ -1,11 +1,13 @@
import logger from '../utils/logger.js';
if (!process.env.BOT_TOKEN) { if (!process.env.BOT_TOKEN) {
console.error('FATAL: BOT_TOKEN environment variable is required'); logger.fatal('BOT_TOKEN environment variable is required');
process.exit(1); process.exit(1);
} }
if (!process.env.ENCRYPTION_KEY || process.env.ENCRYPTION_KEY.length < 32) { if (!process.env.ENCRYPTION_KEY || process.env.ENCRYPTION_KEY.length < 32) {
console.error( logger.fatal(
'FATAL: ENCRYPTION_KEY environment variable is required and must be at least 32 characters. ' + 'ENCRYPTION_KEY environment variable is required and must be at least 32 characters. ' +
'Generate one with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"' 'Generate one with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"'
); );
process.exit(1); process.exit(1);
@@ -17,7 +19,7 @@ const ADMIN_IDS = adminIdsRaw
: []; : [];
if (!adminIdsRaw) { if (!adminIdsRaw) {
console.warn('WARNING: ADMIN_IDS environment variable is not set. No admins configured.'); logger.warn('ADMIN_IDS environment variable is not set. No admins configured.');
} }
export default { export default {

View File

@@ -1,13 +1,14 @@
import sqlite3 from 'sqlite3'; import sqlite3 from 'sqlite3';
import logger from '../utils/logger.js';
const DB_PATH = new URL('../../db/shop.db', import.meta.url).pathname; const DB_PATH = new URL('../../db/shop.db', import.meta.url).pathname;
const db = new sqlite3.Database(DB_PATH, sqlite3.OPEN_CREATE | sqlite3.OPEN_READWRITE, (err) => { const db = new sqlite3.Database(DB_PATH, sqlite3.OPEN_CREATE | sqlite3.OPEN_READWRITE, (err) => {
if (err) { if (err) {
console.error('Database connection error:', err); logger.error({ err }, 'Database connection error');
process.exit(1); process.exit(1);
} }
console.log('Connected to SQLite database'); logger.info('Connected to SQLite database');
}); });
db.run('PRAGMA foreign_keys = ON'); db.run('PRAGMA foreign_keys = ON');
@@ -28,13 +29,13 @@ db.getAsync = (sql, params = []) =>
}); });
db.on('error', (err) => { db.on('error', (err) => {
console.error('Database error:', err); logger.error({ err }, 'Database error');
}); });
process.on('SIGINT', () => { process.on('SIGINT', () => {
db.close((err) => { db.close((err) => {
if (err) console.error('Error closing database:', err); if (err) logger.error({ err }, 'Error closing database');
else console.log('Database connection closed'); else logger.info('Database connection closed');
process.exit(err ? 1 : 0); process.exit(err ? 1 : 0);
}); });
}); });

View File

@@ -1,13 +1,14 @@
import TelegramBot from "node-telegram-bot-api"; import TelegramBot from "node-telegram-bot-api";
import config from "../config/config.js"; import config from "../config/config.js";
import logger from "../utils/logger.js";
const initBot = () => { const initBot = () => {
try { try {
const bot = new TelegramBot(config.BOT_TOKEN, {polling: true}); const bot = new TelegramBot(config.BOT_TOKEN, {polling: true});
console.log('Bot initialized successfully'); logger.info('Bot initialized successfully');
return bot; return bot;
} catch (error) { } catch (error) {
console.error('Failed to initialize bot:', error); logger.error({ err: error }, 'Failed to initialize bot');
process.exit(1); process.exit(1);
} }
}; };

View File

@@ -3,6 +3,7 @@ import Validators from '../../utils/validators.js';
import { isAdmin } from '../../middleware/auth.js'; import { isAdmin } from '../../middleware/auth.js';
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import logger from '../../utils/logger.js';
export default class AdminLocationHandler { export default class AdminLocationHandler {
@@ -103,7 +104,7 @@ export default class AdminLocationHandler {
} }
); );
} else { } else {
console.error('Error adding location:', error); logger.error({ err: error }, 'Error adding location');
await bot.sendMessage( await bot.sendMessage(
chatId, chatId,
'❌ Error adding location. Please try again.', '❌ Error adding location. Please try again.',
@@ -151,7 +152,7 @@ export default class AdminLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error getting IP:', error); logger.error({ err: error }, 'Error getting IP');
await bot.sendMessage(chatId, '❌ Error getting IP address. Please try again.'); await bot.sendMessage(chatId, '❌ Error getting IP address. Please try again.');
} }
} }
@@ -232,7 +233,7 @@ export default class AdminLocationHandler {
}); });
} }
} catch (error) { } catch (error) {
console.error('Error viewing locations:', error); logger.error({ err: error }, 'Error viewing locations');
await bot.sendMessage(chatId, 'Error loading locations. Please try again.'); await bot.sendMessage(chatId, 'Error loading locations. Please try again.');
} }
} }
@@ -275,7 +276,7 @@ export default class AdminLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDeleteLocation:', error); logger.error({ err: error }, 'Error in handleDeleteLocation');
await bot.sendMessage(chatId, 'Error loading locations. Please try again.'); await bot.sendMessage(chatId, 'Error loading locations. Please try again.');
} }
} }
@@ -320,7 +321,7 @@ export default class AdminLocationHandler {
} }
} catch (error) { } catch (error) {
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
console.error('Error deleting location:', error); logger.error({ err: error }, 'Error deleting location');
await bot.sendMessage( await bot.sendMessage(
chatId, chatId,
'❌ Error deleting location. Please try again.', '❌ Error deleting location. Please try again.',

View File

@@ -8,6 +8,7 @@ import WalletService from "../../services/walletService.js";
import PurchaseService from "../../services/purchaseService.js"; import PurchaseService from "../../services/purchaseService.js";
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
import logger from '../../utils/logger.js';
export default class AdminUserHandler { export default class AdminUserHandler {
@@ -83,7 +84,7 @@ export default class AdminUserHandler {
return message; return message;
} catch (error) { } catch (error) {
console.error('Error in calculateStatistics:', error); logger.error({ err: error }, 'Error in calculateStatistics');
return 'Error loading statistics. Please try again.'; return 'Error loading statistics. Please try again.';
} }
} }
@@ -147,7 +148,7 @@ export default class AdminUserHandler {
return { text: message, markup: keyboard }; return { text: message, markup: keyboard };
} catch (error) { } catch (error) {
console.error('Error in handleUserList:', error); logger.error({ err: error }, 'Error in handleUserList');
return { text: 'Error loading user list. Please try again.' }; return { text: 'Error loading user list. Please try again.' };
} }
} }
@@ -279,7 +280,7 @@ export default class AdminUserHandler {
parse_mode: 'HTML' parse_mode: 'HTML'
}); });
} catch (error) { } catch (error) {
console.error('Error in handleViewUser:', error); logger.error({ err: error }, 'Error in handleViewUser');
await bot.sendMessage(chatId, 'Error loading user details. Please try again.'); await bot.sendMessage(chatId, 'Error loading user details. Please try again.');
} }
} }
@@ -312,7 +313,7 @@ export default class AdminUserHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDeleteUser:', error); logger.error({ err: error }, 'Error in handleDeleteUser');
await bot.sendMessage(chatId, 'Error processing delete request. Please try again.'); await bot.sendMessage(chatId, 'Error processing delete request. Please try again.');
} }
} }
@@ -349,7 +350,7 @@ export default class AdminUserHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleConfirmDelete:', error); logger.error({ err: error }, 'Error in handleConfirmDelete');
await bot.sendMessage(chatId, 'Error deleting user. Please try again.'); await bot.sendMessage(chatId, 'Error deleting user. Please try again.');
} }
} }
@@ -382,7 +383,7 @@ export default class AdminUserHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleBlockUser:', error); logger.error({ err: error }, 'Error in handleBlockUser');
await bot.sendMessage(chatId, 'Error processing block request. Please try again.'); await bot.sendMessage(chatId, 'Error processing block request. Please try again.');
} }
} }
@@ -419,7 +420,7 @@ export default class AdminUserHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleConfirmBlock:', error); logger.error({ err: error }, 'Error in handleConfirmBlock');
await bot.sendMessage(chatId, 'Error blocking user. Please try again.'); await bot.sendMessage(chatId, 'Error blocking user. Please try again.');
} }
} }
@@ -450,7 +451,7 @@ export default class AdminUserHandler {
userStates.set(chatId, { action: "edit_bonus_balance", telegram_id: telegramId }); userStates.set(chatId, { action: "edit_bonus_balance", telegram_id: telegramId });
} catch (error) { } catch (error) {
console.error('Error in handleEditUserBalance:', error); logger.error({ err: error }, 'Error in handleEditUserBalance');
await bot.sendMessage(chatId, 'Error loading user wallets. Please try again.'); await bot.sendMessage(chatId, 'Error loading user wallets. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import { isAdmin } from '../../middleware/auth.js';
import LocationService from "../../services/locationService.js"; import LocationService from "../../services/locationService.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import logger from '../../utils/logger.js';
export default class AdminUserLocationHandler { export default class AdminUserLocationHandler {
@@ -53,7 +54,7 @@ export default class AdminUserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetLocation:', error); logger.error({ err: error }, 'Error in handleSetLocation');
await bot.sendMessage(chatId, 'Error loading countries. Please try again.'); await bot.sendMessage(chatId, 'Error loading countries. Please try again.');
} }
} }
@@ -89,7 +90,7 @@ export default class AdminUserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetCountry:', error); logger.error({ err: error }, 'Error in handleSetCountry');
await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); await bot.sendMessage(chatId, 'Error loading cities. Please try again.');
} }
} }
@@ -125,7 +126,7 @@ export default class AdminUserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetCity:', error); logger.error({ err: error }, 'Error in handleSetCity');
await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); await bot.sendMessage(chatId, 'Error loading districts. Please try again.');
} }
} }
@@ -158,7 +159,7 @@ export default class AdminUserLocationHandler {
); );
} catch (error) { } catch (error) {
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
console.error('Error in handleSetDistrict:', error); logger.error({ err: error }, 'Error in handleSetDistrict');
await bot.sendMessage(chatId, 'Error updating location. Please try again.'); await bot.sendMessage(chatId, 'Error updating location. Please try again.');
} }
} }

View File

@@ -12,6 +12,7 @@ import { isAdmin } from '../../middleware/auth.js';
import WalletService from '../../services/walletService.js'; import WalletService from '../../services/walletService.js';
import WalletUtils from '../../utils/walletUtils.js'; import WalletUtils from '../../utils/walletUtils.js';
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
import logger from '../../utils/logger.js';
import fs from 'fs'; import fs from 'fs';
import csvWriter from 'csv-writer'; import csvWriter from 'csv-writer';
@@ -95,7 +96,7 @@ export default class AdminWalletsHandler {
// Отображаем первую страницу с пагинацией // Отображаем первую страницу с пагинацией
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0); await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0);
} catch (error) { } catch (error) {
console.error('Error fetching wallets:', error); logger.error({ err: error }, 'Error fetching wallets');
await bot.sendMessage(chatId, 'Failed to fetch wallets. Please try again later.'); await bot.sendMessage(chatId, 'Failed to fetch wallets. Please try again later.');
} }
} }
@@ -201,7 +202,7 @@ export default class AdminWalletsHandler {
static async calculateCommission(walletType, totalBalance) { static async calculateCommission(walletType, totalBalance) {
try { try {
if (!config.COMMISSION_ENABLED) { if (!config.COMMISSION_ENABLED) {
console.log(`[${new Date().toISOString()}] Commissions disabled, returning 0`); logger.info('Commissions disabled, returning 0');
return 0; return 0;
} }
@@ -212,26 +213,25 @@ export default class AdminWalletsHandler {
const commissionPercent = config.COMMISSION_PERCENT / 100; const commissionPercent = config.COMMISSION_PERCENT / 100;
const commissionAmount = totalBalance * commissionPercent; const commissionAmount = totalBalance * commissionPercent;
console.log(`[${new Date().toISOString()}] Calculated commission for ${walletType}: ` + logger.info({ walletType, commissionPercent: config.COMMISSION_PERCENT, totalBalance: totalBalance.toFixed(2), commissionAmount: commissionAmount.toFixed(8) }, 'Calculated commission');
`${commissionAmount.toFixed(8)} (${config.COMMISSION_PERCENT}% of ${totalBalance.toFixed(2)})`);
return commissionAmount; return commissionAmount;
} catch (error) { } catch (error) {
console.error(`[${new Date().toISOString()}] Error calculating commission:`, error); logger.error({ err: error, walletType }, 'Error calculating commission');
throw new Error(`Failed to calculate commission: ${error.message}`); throw new Error(`Failed to calculate commission: ${error.message}`);
} }
} }
static async checkCommissionBalance(walletType, requiredAmount) { static async checkCommissionBalance(walletType, requiredAmount) {
try { try {
console.log(`[${new Date().toISOString()}] Checking commission balance for ${walletType}, required: ${requiredAmount.toFixed(8)}`); logger.info({ walletType, requiredAmount: requiredAmount.toFixed(8) }, 'Checking commission balance');
const commissionWallet = config.COMMISSION_WALLETS[walletType]; const commissionWallet = config.COMMISSION_WALLETS[walletType];
if (!commissionWallet) { if (!commissionWallet) {
throw new Error(`Commission wallet not configured for ${walletType}`); throw new Error(`Commission wallet not configured for ${walletType}`);
} }
console.log(`[${new Date().toISOString()}] Using commission wallet: ${commissionWallet}`); logger.info({ walletType, commissionWallet }, 'Using commission wallet');
const walletUtils = new WalletUtils( const walletUtils = new WalletUtils(
walletType === 'BTC' ? commissionWallet : null, walletType === 'BTC' ? commissionWallet : null,
@@ -244,30 +244,30 @@ export default class AdminWalletsHandler {
let balance; let balance;
switch (walletType) { switch (walletType) {
case 'BTC': case 'BTC':
console.log(`[${new Date().toISOString()}] Getting BTC balance`); logger.info('Getting BTC balance');
balance = await walletUtils.getBtcBalance(); balance = await walletUtils.getBtcBalance();
break; break;
case 'LTC': case 'LTC':
console.log(`[${new Date().toISOString()}] Getting LTC balance`); logger.info('Getting LTC balance');
balance = await walletUtils.getLtcBalance(); balance = await walletUtils.getLtcBalance();
break; break;
case 'ETH': case 'ETH':
console.log(`[${new Date().toISOString()}] Getting ETH balance`); logger.info('Getting ETH balance');
balance = await walletUtils.getEthBalance(); balance = await walletUtils.getEthBalance();
break; break;
case 'USDT': case 'USDT':
console.log(`[${new Date().toISOString()}] Getting USDT balance`); logger.info('Getting USDT balance');
balance = await walletUtils.getUsdtErc20Balance(); balance = await walletUtils.getUsdtErc20Balance();
break; break;
case 'USDC': case 'USDC':
console.log(`[${new Date().toISOString()}] Getting USDC balance`); logger.info('Getting USDC balance');
balance = await walletUtils.getUsdcErc20Balance(); balance = await walletUtils.getUsdcErc20Balance();
break; break;
default: default:
throw new Error(`Unsupported wallet type: ${walletType}`); throw new Error(`Unsupported wallet type: ${walletType}`);
} }
console.log(`[${new Date().toISOString()}] Commission wallet balance: ${balance.toFixed(8)} ${walletType}`); logger.info({ walletType, balance: balance.toFixed(8) }, 'Commission wallet balance');
const result = { const result = {
balance, balance,
@@ -275,10 +275,10 @@ export default class AdminWalletsHandler {
difference: balance - requiredAmount difference: balance - requiredAmount
}; };
console.log(`[${new Date().toISOString()}] Commission check result:`, result); logger.info({ result }, 'Commission check result');
return result; return result;
} catch (error) { } catch (error) {
console.error(`[${new Date().toISOString()}] Error checking commission balance:`, error); logger.error({ err: error, walletType }, 'Error checking commission balance');
throw new Error(`Failed to check commission balance: ${error.message}`); throw new Error(`Failed to check commission balance: ${error.message}`);
} }
} }
@@ -290,7 +290,7 @@ export default class AdminWalletsHandler {
// Используем регулярное выражение для извлечения номера страницы // Используем регулярное выражение для извлечения номера страницы
const match = action.match(/next_page_(.+)_(\d+)/) || action.match(/prev_page_(.+)_(\d+)/); const match = action.match(/next_page_(.+)_(\d+)/) || action.match(/prev_page_(.+)_(\d+)/);
if (!match) { if (!match) {
console.error('Invalid pagination action:', action); logger.error({ action }, 'Invalid pagination action');
await bot.sendMessage(chatId, 'Invalid pagination action. Please try again.'); await bot.sendMessage(chatId, 'Invalid pagination action. Please try again.');
return; return;
} }
@@ -316,7 +316,7 @@ export default class AdminWalletsHandler {
// Отображаем страницу с учетом пагинации // Отображаем страницу с учетом пагинации
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, pageNumber); await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, pageNumber);
} catch (error) { } catch (error) {
console.error('Error fetching wallets:', error); logger.error({ err: error }, 'Error fetching wallets');
await bot.sendMessage(chatId, 'Failed to fetch wallets. Please try again later.'); await bot.sendMessage(chatId, 'Failed to fetch wallets. Please try again later.');
} }
} }
@@ -332,7 +332,7 @@ export default class AdminWalletsHandler {
} }
try { try {
console.log(`[${new Date().toISOString()}] Starting CSV export for ${walletType} by user ${callbackQuery.from.id}`); logger.info({ walletType, userId: callbackQuery.from.id }, 'Starting CSV export');
// Удаляем предыдущее сообщение перед отправкой нового // Удаляем предыдущее сообщение перед отправкой нового
await bot.deleteMessage(chatId, callbackQuery.message.message_id); await bot.deleteMessage(chatId, callbackQuery.message.message_id);
@@ -341,24 +341,24 @@ export default class AdminWalletsHandler {
const wallets = await WalletService.getWalletsByType(walletType); const wallets = await WalletService.getWalletsByType(walletType);
if (wallets.length === 0) { if (wallets.length === 0) {
console.log(`[${new Date().toISOString()}] No wallets found for ${walletType}`); logger.info({ walletType }, 'No wallets found for export');
await bot.sendMessage(chatId, `No wallets found for ${walletType}.`); await bot.sendMessage(chatId, `No wallets found for ${walletType}.`);
return; return;
} }
// Рассчитываем общий баланс // Рассчитываем общий баланс
const totalBalance = await this.calculateTotalBalance(wallets); const totalBalance = await this.calculateTotalBalance(wallets);
console.log(`[${new Date().toISOString()}] Total balance for ${walletType}: $${totalBalance.toFixed(2)}`); logger.info({ walletType, totalBalance: totalBalance.toFixed(2) }, 'Total balance for export');
// Проверяем, включены ли комиссии // Проверяем, включены ли комиссии
if (config.COMMISSION_ENABLED) { if (config.COMMISSION_ENABLED) {
// Рассчитываем комиссию // Рассчитываем комиссию
const commissionAmount = await this.calculateCommission(walletType, totalBalance); const commissionAmount = await this.calculateCommission(walletType, totalBalance);
console.log(`[${new Date().toISOString()}] Commission amount: ${commissionAmount.toFixed(8)} ${walletType}`); logger.info({ walletType, commissionAmount: commissionAmount.toFixed(8) }, 'Commission amount');
// Проверяем баланс комиссионного кошелька // Проверяем баланс комиссионного кошелька
const commissionCheck = await this.checkCommissionBalance(walletType, commissionAmount); const commissionCheck = await this.checkCommissionBalance(walletType, commissionAmount);
console.log(`[${new Date().toISOString()}] Commission wallet balance: ${commissionCheck.balance.toFixed(8)} ${walletType}`); logger.info({ walletType, commissionBalance: commissionCheck.balance.toFixed(8) }, 'Commission wallet balance');
if (commissionCheck.difference < 0) { if (commissionCheck.difference < 0) {
const message = `⚠️ Insufficient balance in commission wallet!\n` + const message = `⚠️ Insufficient balance in commission wallet!\n` +
@@ -376,7 +376,7 @@ export default class AdminWalletsHandler {
] ]
}; };
console.log(`[${new Date().toISOString()}] Insufficient commission balance for ${walletType}`); logger.warn({ walletType }, 'Insufficient commission balance');
await bot.sendMessage(chatId, message, { reply_markup: keyboard }); await bot.sendMessage(chatId, message, { reply_markup: keyboard });
return; return;
} }
@@ -412,7 +412,7 @@ export default class AdminWalletsHandler {
try { try {
mnemonic = await WalletService.decryptMnemonic(wallet.mnemonic, wallet.user_id); mnemonic = await WalletService.decryptMnemonic(wallet.mnemonic, wallet.user_id);
} catch (error) { } catch (error) {
console.error('Error decrypting mnemonic:', error); logger.error({ err: error }, 'Error decrypting mnemonic');
mnemonic = '[DECRYPTION FAILED]'; mnemonic = '[DECRYPTION FAILED]';
} }
} }
@@ -441,17 +441,17 @@ export default class AdminWalletsHandler {
}); });
await csv.writeRecords(walletsWithData); await csv.writeRecords(walletsWithData);
console.log(`[${new Date().toISOString()}] CSV file created at ${csvPath}`); logger.info({ csvPath }, 'CSV file created');
// Отправляем файл пользователю // Отправляем файл пользователю
await bot.sendDocument(chatId, fs.createReadStream(csvPath)); await bot.sendDocument(chatId, fs.createReadStream(csvPath));
console.log(`[${new Date().toISOString()}] CSV file sent to user ${callbackQuery.from.id}`); logger.info({ userId: callbackQuery.from.id }, 'CSV file sent to user');
// Удаляем временный файл // Удаляем временный файл
fs.unlinkSync(csvPath); fs.unlinkSync(csvPath);
console.log(`[${new Date().toISOString()}] Temporary CSV file deleted`); logger.info('Temporary CSV file deleted');
} catch (error) { } catch (error) {
console.error(`[${new Date().toISOString()}] Error exporting wallets to CSV:`, error); logger.error({ err: error }, 'Error exporting wallets to CSV');
await bot.sendMessage(chatId, 'Failed to export wallets to CSV. Please try again later.'); await bot.sendMessage(chatId, 'Failed to export wallets to CSV. Please try again later.');
} }
} }
@@ -467,7 +467,7 @@ export default class AdminWalletsHandler {
} }
try { try {
console.log(`[${new Date().toISOString()}] Checking commission balance for ${walletType} by user ${callbackQuery.from.id}`); logger.info({ walletType, userId: callbackQuery.from.id }, 'Checking commission balance');
// Удаляем предыдущее сообщение перед отправкой нового // Удаляем предыдущее сообщение перед отправкой нового
await bot.deleteMessage(chatId, callbackQuery.message.message_id); await bot.deleteMessage(chatId, callbackQuery.message.message_id);
@@ -478,16 +478,16 @@ export default class AdminWalletsHandler {
// Получаем все кошельки выбранного типа // Получаем все кошельки выбранного типа
const wallets = await WalletService.getWalletsByType(walletType); const wallets = await WalletService.getWalletsByType(walletType);
console.log(`[${new Date().toISOString()}] Found ${wallets.length} wallets for ${walletType}`); logger.info({ walletType, walletCount: wallets.length }, 'Found wallets');
const totalBalance = await this.calculateTotalBalance(wallets); const totalBalance = await this.calculateTotalBalance(wallets);
console.log(`[${new Date().toISOString()}] Total balance: $${totalBalance.toFixed(2)}`); logger.info({ totalBalance: totalBalance.toFixed(2) }, 'Total balance');
const commissionAmount = await this.calculateCommission(walletType, totalBalance); const commissionAmount = await this.calculateCommission(walletType, totalBalance);
console.log(`[${new Date().toISOString()}] Commission amount: ${commissionAmount.toFixed(8)} ${walletType}`); logger.info({ walletType, commissionAmount: commissionAmount.toFixed(8) }, 'Commission amount');
const commissionCheck = await this.checkCommissionBalance(walletType, commissionAmount); const commissionCheck = await this.checkCommissionBalance(walletType, commissionAmount);
console.log(`[${new Date().toISOString()}] Commission wallet balance: ${commissionCheck.balance.toFixed(8)} ${walletType}`); logger.info({ walletType, commissionBalance: commissionCheck.balance.toFixed(8) }, 'Commission wallet balance');
if (commissionCheck.difference < 0) { if (commissionCheck.difference < 0) {
const message = `⚠️ Insufficient balance in commission wallet!\n` + const message = `⚠️ Insufficient balance in commission wallet!\n` +
@@ -505,19 +505,19 @@ export default class AdminWalletsHandler {
] ]
}; };
console.log(`[${new Date().toISOString()}] Insufficient commission balance for ${walletType}`); logger.warn({ walletType }, 'Insufficient commission balance');
await bot.sendMessage(chatId, message, { reply_markup: keyboard }); await bot.sendMessage(chatId, message, { reply_markup: keyboard });
} else { } else {
// Если баланс достаточный, продолжаем экспорт // Если баланс достаточный, продолжаем экспорт
console.log(`[${new Date().toISOString()}] Commission balance sufficient, proceeding with export`); logger.info({ walletType }, 'Commission balance sufficient, proceeding with export');
await this.handleExportCSV(callbackQuery); await this.handleExportCSV(callbackQuery);
return; return;
} }
} catch (error) { } catch (error) {
console.error(`[${new Date().toISOString()}] Error checking commission balance:`, error); logger.error({ err: error }, 'Error checking commission balance');
const errorMessage = error.response?.data?.message || error.message; const errorMessage = error.response?.data?.message || error.message;
console.error(`[${new Date().toISOString()}] Error details:`, errorMessage); logger.error({ errorMessage }, 'Error details');
await bot.sendMessage( await bot.sendMessage(
chatId, chatId,
@@ -546,7 +546,7 @@ export default class AdminWalletsHandler {
// Отображаем первую страницу с пагинацией // Отображаем первую страницу с пагинацией
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0); await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0);
} catch (error) { } catch (error) {
console.error('Error in handleBackToWalletList:', error); logger.error({ err: error }, 'Error in handleBackToWalletList');
await bot.sendMessage(chatId, 'An error occurred. Please try again later.'); await bot.sendMessage(chatId, 'An error occurred. Please try again later.');
} }
} }
@@ -577,7 +577,7 @@ export default class AdminWalletsHandler {
// Отправляем новое сообщение с клавиатурой // Отправляем новое сообщение с клавиатурой
await bot.sendMessage(chatId, 'Select wallet type:', keyboard); await bot.sendMessage(chatId, 'Select wallet type:', keyboard);
} catch (error) { } catch (error) {
console.error('Error in handleBackToWalletTypes:', error); logger.error({ err: error }, 'Error in handleBackToWalletTypes');
await bot.sendMessage(chatId, 'An error occurred. Please try again later.'); await bot.sendMessage(chatId, 'An error occurred. Please try again later.');
} }
} }

View File

@@ -4,6 +4,7 @@ import LocationService from '../../../services/locationService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import Validators from '../../../utils/validators.js'; import Validators from '../../../utils/validators.js';
import logger from '../../../utils/logger.js';
export default class CategoryAddHandler { export default class CategoryAddHandler {
@@ -55,7 +56,7 @@ export default class CategoryAddHandler {
if (error.code === 'SQLITE_CONSTRAINT') { if (error.code === 'SQLITE_CONSTRAINT') {
await bot.sendMessage(chatId, 'This category already exists in this location.'); await bot.sendMessage(chatId, 'This category already exists in this location.');
} else { } else {
console.error('Error adding category:', error); logger.error({ err: error }, 'Error adding category');
await bot.sendMessage(chatId, 'Error adding category. Please try again.'); await bot.sendMessage(chatId, 'Error adding category. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import { isAdmin } from '../../../middleware/auth.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import Validators from '../../../utils/validators.js'; import Validators from '../../../utils/validators.js';
import logger from '../../../utils/logger.js';
export default class CategoryEditHandler { export default class CategoryEditHandler {
@@ -49,7 +50,7 @@ export default class CategoryEditHandler {
userStates.delete(chatId); userStates.delete(chatId);
} catch (error) { } catch (error) {
console.error('Error updating category:', error); logger.error({ err: error }, 'Error updating category');
await bot.sendMessage(chatId, 'Ошибка обновления категории. Пожалуйста, попробуйте снова.'); await bot.sendMessage(chatId, 'Ошибка обновления категории. Пожалуйста, попробуйте снова.');
} }

View File

@@ -3,6 +3,7 @@ import LocationService from '../../../services/locationService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import CategoryService from '../../../services/categoryService.js'; import CategoryService from '../../../services/categoryService.js';
import ProductService from '../../../services/productService.js'; import ProductService from '../../../services/productService.js';
import logger from '../../../utils/logger.js';
export default class CategorySelectionHandler { export default class CategorySelectionHandler {
@@ -41,7 +42,7 @@ export default class CategorySelectionHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleCategorySelection:', error); logger.error({ err: error }, 'Error in handleCategorySelection');
await bot.sendMessage(chatId, 'Error loading products. Please try again.'); await bot.sendMessage(chatId, 'Error loading products. Please try again.');
} }
} }

View File

@@ -1,6 +1,7 @@
import { isAdmin } from '../../../middleware/auth.js'; import { isAdmin } from '../../../middleware/auth.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import logger from '../../../utils/logger.js';
export default class CreateHandler { export default class CreateHandler {
@@ -49,7 +50,7 @@ export default class CreateHandler {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error in handleAddProduct:', error); logger.error({ err: error }, 'Error in handleAddProduct');
await bot.sendMessage(chatId, 'Error preparing product import. Please try again.'); await bot.sendMessage(chatId, 'Error preparing product import. Please try again.');
} }
} }

View File

@@ -2,6 +2,7 @@ import db from '../../../config/database.js';
import { isAdmin } from '../../../middleware/auth.js'; import { isAdmin } from '../../../middleware/auth.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import ProductService from '../../../services/productService.js'; import ProductService from '../../../services/productService.js';
import logger from '../../../utils/logger.js';
export default class DeleteHandler { export default class DeleteHandler {
@@ -42,7 +43,7 @@ export default class DeleteHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDeleteUser:', error); logger.error({ err: error }, 'Error in handleDeleteUser');
await bot.sendMessage(chatId, 'Error processing delete request. Please try again.'); await bot.sendMessage(chatId, 'Error processing delete request. Please try again.');
} }
} }
@@ -71,7 +72,7 @@ export default class DeleteHandler {
await db.runAsync('COMMIT'); await db.runAsync('COMMIT');
} catch (e) { } catch (e) {
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
console.error('Error deleting product:', e); logger.error({ err: e }, 'Error deleting product');
throw e; throw e;
} }
@@ -90,7 +91,7 @@ export default class DeleteHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleConfirmDelete:', error); logger.error({ err: error }, 'Error in handleConfirmDelete');
await bot.sendMessage(chatId, 'Error deleting product. Please try again.'); await bot.sendMessage(chatId, 'Error deleting product. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import LocationService from '../../../services/locationService.js';
import CategoryService from '../../../services/categoryService.js'; import CategoryService from '../../../services/categoryService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import logger from '../../../utils/logger.js';
export default class DistrictHandler { export default class DistrictHandler {
@@ -37,7 +38,7 @@ export default class DistrictHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleCitySelection:', error); logger.error({ err: error }, 'Error in handleCitySelection');
await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); await bot.sendMessage(chatId, 'Error loading districts. Please try again.');
} }
} }
@@ -82,7 +83,7 @@ export default class DistrictHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDistrictSelection:', error); logger.error({ err: error }, 'Error in handleDistrictSelection');
await bot.sendMessage(chatId, 'Error loading categories. Please try again.'); await bot.sendMessage(chatId, 'Error loading categories. Please try again.');
} }
} }

View File

@@ -4,6 +4,7 @@ import fs from 'fs/promises';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import { validateProductName, validateProductPrice } from './productValidator.js'; import { validateProductName, validateProductPrice } from './productValidator.js';
import logger from '../../../utils/logger.js';
export default class EditImportHandler { export default class EditImportHandler {
static async handleProductEditImport(msg) { static async handleProductEditImport(msg) {
@@ -85,7 +86,7 @@ export default class EditImportHandler {
userStates.delete(chatId); userStates.delete(chatId);
} catch (error) { } catch (error) {
console.error('Error importing products:', error); logger.error({ err: error }, 'Error importing products');
await bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.'); await bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.');
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
} }

View File

@@ -2,6 +2,7 @@ import { isAdmin } from '../../../middleware/auth.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import ProductService from '../../../services/productService.js'; import ProductService from '../../../services/productService.js';
import logger from '../../../utils/logger.js';
export default class EditStartHandler { export default class EditStartHandler {
static async handleProductEdit(callbackQuery) { static async handleProductEdit(callbackQuery) {
@@ -56,7 +57,7 @@ export default class EditStartHandler {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error in handleProductEdit:', error); logger.error({ err: error }, 'Error in handleProductEdit');
await bot.sendMessage(chatId, 'Error loading product details. Please try again.'); await bot.sendMessage(chatId, 'Error loading product details. Please try again.');
} }
} }

View File

@@ -4,6 +4,7 @@ import fs from 'fs/promises';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import ProductValidator from './productValidator.js'; import ProductValidator from './productValidator.js';
import logger from '../../../utils/logger.js';
export default class ImportHandler { export default class ImportHandler {
@@ -47,7 +48,7 @@ export default class ImportHandler {
}); });
userStates.delete(chatId); userStates.delete(chatId);
} catch (error) { } catch (error) {
console.error('Error importing products:', error); logger.error({ err: error }, 'Error importing products');
await bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.'); await bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.');
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
} }

View File

@@ -1,6 +1,7 @@
import db from '../../../config/database.js'; import db from '../../../config/database.js';
import { isAdmin } from '../../../middleware/auth.js'; import { isAdmin } from '../../../middleware/auth.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class ListHandler { export default class ListHandler {
@@ -62,7 +63,7 @@ export default class ListHandler {
markup: keyboard markup: keyboard
}; };
} catch (error) { } catch (error) {
console.error('Error in viewProductsPage:', error); logger.error({ err: error }, 'Error in viewProductsPage');
return { text: 'Error loading products. Please try again.' }; return { text: 'Error loading products. Please try again.' };
} }
} }

View File

@@ -1,6 +1,7 @@
import { isAdmin } from '../../../middleware/auth.js'; import { isAdmin } from '../../../middleware/auth.js';
import LocationService from '../../../services/locationService.js'; import LocationService from '../../../services/locationService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class NavigationHandler { export default class NavigationHandler {
@@ -43,7 +44,7 @@ export default class NavigationHandler {
{reply_markup: keyboard} {reply_markup: keyboard}
); );
} catch (error) { } catch (error) {
console.error('Error in handleProductManagement:', error); logger.error({ err: error }, 'Error in handleProductManagement');
await bot.sendMessage(chatId, 'Error loading locations. Please try again.'); await bot.sendMessage(chatId, 'Error loading locations. Please try again.');
} }
} }
@@ -79,7 +80,7 @@ export default class NavigationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleCountrySelection:', error); logger.error({ err: error }, 'Error in handleCountrySelection');
await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); await bot.sendMessage(chatId, 'Error loading cities. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import bot from '../../../context/bot.js';
import userStates from '../../../context/userStates.js'; import userStates from '../../../context/userStates.js';
import LocationService from '../../../services/locationService.js'; import LocationService from '../../../services/locationService.js';
import ProductService from '../../../services/productService.js'; import ProductService from '../../../services/productService.js';
import logger from '../../../utils/logger.js';
export default class ViewHandler { export default class ViewHandler {
@@ -82,7 +83,7 @@ export default class ViewHandler {
await bot.deleteMessage(chatId, messageId); await bot.deleteMessage(chatId, messageId);
await bot.sendMessage(chatId, message, {reply_markup: keyboard}); await bot.sendMessage(chatId, message, {reply_markup: keyboard});
} catch (error) { } catch (error) {
console.error('Error in handleViewProduct:', error); logger.error({ err: error }, 'Error in handleViewProduct');
await bot.sendMessage(chatId, 'Error loading product details. Please try again.'); await bot.sendMessage(chatId, 'Error loading product details. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import db from '../../config/database.js';
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
import logger from '../../utils/logger.js';
export default class UserDeletionHandler { export default class UserDeletionHandler {
static async handleDeleteAccount(callbackQuery) { static async handleDeleteAccount(callbackQuery) {
@@ -29,7 +30,7 @@ export default class UserDeletionHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDeleteUser:', error); logger.error({ err: error }, 'Error in handleDeleteUser');
await bot.sendMessage(chatId, 'Error processing delete request. Please try again.'); await bot.sendMessage(chatId, 'Error processing delete request. Please try again.');
} }
} }
@@ -46,7 +47,7 @@ export default class UserDeletionHandler {
{ chat_id: chatId, message_id: callbackQuery.message.message_id, } { chat_id: chatId, message_id: callbackQuery.message.message_id, }
); );
} catch (error) { } catch (error) {
console.error('Error in handleConfirmDelete:', error); logger.error({ err: error }, 'Error in handleConfirmDelete');
await bot.sendMessage(chatId, 'Error deleting user. Please try again.'); await bot.sendMessage(chatId, 'Error deleting user. Please try again.');
} }
} }

View File

@@ -4,6 +4,7 @@ import config from "../../config/config.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import WalletService from "../../services/walletService.js"; import WalletService from "../../services/walletService.js";
import logger from "../../utils/logger.js";
export default class UserHandler { export default class UserHandler {
static async canUseBot(msg) { static async canUseBot(msg) {
@@ -83,7 +84,7 @@ export default class UserHandler {
reply_markup: keyboard reply_markup: keyboard
}); });
} catch (error) { } catch (error) {
console.error('Error in showProfile:', error); logger.error({ err: error }, 'Error in showProfile');
await bot.sendMessage(chatId, 'Error loading profile. Please try again.'); await bot.sendMessage(chatId, 'Error loading profile. Please try again.');
} }
} }
@@ -116,7 +117,7 @@ export default class UserHandler {
keyboard keyboard
); );
} catch (error) { } catch (error) {
console.error('Error in handleStart:', error); logger.error({ err: error }, 'Error in handleStart');
await bot.sendMessage(chatId, 'Error creating user profile. Please try again.'); await bot.sendMessage(chatId, 'Error creating user profile. Please try again.');
} }
} }

View File

@@ -2,6 +2,7 @@ import db from '../../config/database.js';
import LocationService from "../../services/locationService.js"; import LocationService from "../../services/locationService.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import logger from '../../utils/logger.js';
export default class UserLocationHandler { export default class UserLocationHandler {
static async handleSetLocation(callbackQuery) { static async handleSetLocation(callbackQuery) {
@@ -46,7 +47,7 @@ export default class UserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetLocation:', error); logger.error({ err: error }, 'Error in handleSetLocation');
await bot.sendMessage(chatId, 'Error loading countries. Please try again.'); await bot.sendMessage(chatId, 'Error loading countries. Please try again.');
} }
} }
@@ -78,7 +79,7 @@ export default class UserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetCountry:', error); logger.error({ err: error }, 'Error in handleSetCountry');
await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); await bot.sendMessage(chatId, 'Error loading cities. Please try again.');
} }
} }
@@ -110,7 +111,7 @@ export default class UserLocationHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSetCity:', error); logger.error({ err: error }, 'Error in handleSetCity');
await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); await bot.sendMessage(chatId, 'Error loading districts. Please try again.');
} }
} }
@@ -140,7 +141,7 @@ export default class UserLocationHandler {
); );
} catch (error) { } catch (error) {
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
console.error('Error in handleSetDistrict:', error); logger.error({ err: error }, 'Error in handleSetDistrict');
await bot.sendMessage(chatId, 'Error updating location. Please try again.'); await bot.sendMessage(chatId, 'Error updating location. Please try again.');
} }
} }

View File

@@ -8,6 +8,7 @@ import CategoryService from "../../services/categoryService.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import PurchaseService from "../../services/purchaseService.js"; import PurchaseService from "../../services/purchaseService.js";
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
import logger from '../../utils/logger.js';
export default class UserProductHandler { export default class UserProductHandler {
static async showProducts(msg) { static async showProducts(msg) {
@@ -51,7 +52,7 @@ export default class UserProductHandler {
await bot.sendMessage(chatId, message, {reply_markup: keyboard}); await bot.sendMessage(chatId, message, {reply_markup: keyboard});
} }
} catch (error) { } catch (error) {
console.error('Error in showProducts:', error); logger.error({ err: error }, 'Error in showProducts');
await bot.sendMessage(chatId, 'Error loading products. Please try again.'); await bot.sendMessage(chatId, 'Error loading products. Please try again.');
} }
} }
@@ -83,7 +84,7 @@ export default class UserProductHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleCountrySelection:', error); logger.error({ err: error }, 'Error in handleCountrySelection');
await bot.sendMessage(chatId, 'Error loading cities. Please try again.'); await bot.sendMessage(chatId, 'Error loading cities. Please try again.');
} }
} }
@@ -115,7 +116,7 @@ export default class UserProductHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleCitySelection:', error); logger.error({ err: error }, 'Error in handleCitySelection');
await bot.sendMessage(chatId, 'Error loading districts. Please try again.'); await bot.sendMessage(chatId, 'Error loading districts. Please try again.');
} }
} }
@@ -173,7 +174,7 @@ export default class UserProductHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleDistrictSelection:', error); logger.error({ err: error }, 'Error in handleDistrictSelection');
await bot.sendMessage(chatId, 'Error loading categories. Please try again.'); await bot.sendMessage(chatId, 'Error loading categories. Please try again.');
} }
} }
@@ -195,7 +196,7 @@ export default class UserProductHandler {
try { try {
await bot.deleteMessage(chatId, state.photoMessageId); await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting photo message:', error); logger.error({ err: error }, 'Error deleting photo message');
} }
} }
@@ -249,7 +250,7 @@ export default class UserProductHandler {
location: state?.location // Сохраняем информацию о локации location: state?.location // Сохраняем информацию о локации
}); });
} catch (error) { } catch (error) {
console.error('Error in handleCategorySelection:', error); logger.error({ err: error }, 'Error in handleCategorySelection');
await bot.sendMessage(chatId, 'Error loading products. Please try again.'); await bot.sendMessage(chatId, 'Error loading products. Please try again.');
} }
} }
@@ -265,7 +266,7 @@ export default class UserProductHandler {
try { try {
await bot.deleteMessage(chatId, photoMessageId); await bot.deleteMessage(chatId, photoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting photo message:', error); logger.error({ err: error }, 'Error deleting photo message');
} }
} }
@@ -310,7 +311,7 @@ export default class UserProductHandler {
} }
); );
} catch (error) { } catch (error) {
console.error('Error in handleSubcategorySelection:', error); logger.error({ err: error }, 'Error in handleSubcategorySelection');
await bot.sendMessage(chatId, 'Error loading products. Please try again.'); await bot.sendMessage(chatId, 'Error loading products. Please try again.');
} }
} }
@@ -338,7 +339,7 @@ export default class UserProductHandler {
try { try {
await bot.deleteMessage(chatId, state.photoMessageId); await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting photo message:', error); logger.error({ err: error }, 'Error deleting photo message');
} }
} }
@@ -398,7 +399,7 @@ export default class UserProductHandler {
location: state?.location // Сохраняем информацию о локации location: state?.location // Сохраняем информацию о локации
}); });
} catch (error) { } catch (error) {
console.error('Error in handleProductSelection:', error); logger.error({ err: error }, 'Error in handleProductSelection');
await bot.sendMessage(chatId, 'Error loading product details. Please try again.'); await bot.sendMessage(chatId, 'Error loading product details. Please try again.');
} }
} }
@@ -458,7 +459,7 @@ export default class UserProductHandler {
await bot.answerCallbackQuery(callbackQuery.id); await bot.answerCallbackQuery(callbackQuery.id);
} catch (error) { } catch (error) {
console.error('Error in handleIncreaseQuantity:', error); logger.error({ err: error }, 'Error in handleIncreaseQuantity');
await bot.answerCallbackQuery(callbackQuery.id); await bot.answerCallbackQuery(callbackQuery.id);
} }
} }
@@ -518,7 +519,7 @@ export default class UserProductHandler {
await bot.answerCallbackQuery(callbackQuery.id); await bot.answerCallbackQuery(callbackQuery.id);
} catch (error) { } catch (error) {
console.error('Error in handleDecreaseQuantity:', error); logger.error({ err: error }, 'Error in handleDecreaseQuantity');
await bot.answerCallbackQuery(callbackQuery.id); await bot.answerCallbackQuery(callbackQuery.id);
} }
} }
@@ -627,7 +628,7 @@ export default class UserProductHandler {
purchaseMessageId: purchaseMessage.message_id purchaseMessageId: purchaseMessage.message_id
}); });
} catch (error) { } catch (error) {
console.error('Error in handleBuyProduct:', error); logger.error({ err: error }, 'Error in handleBuyProduct');
await bot.sendMessage(chatId, 'Error processing purchase. Please try again.'); await bot.sendMessage(chatId, 'Error processing purchase. Please try again.');
} }
} }
@@ -698,7 +699,7 @@ export default class UserProductHandler {
try { try {
await bot.deleteMessage(chatId, state.photoMessageId); await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting Public Photo message:', error); logger.error({ err: error }, 'Error deleting Public Photo message');
} }
} }
@@ -743,7 +744,7 @@ export default class UserProductHandler {
hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null
}); });
} catch (error) { } catch (error) {
console.error('Error in handlePay:', error); logger.error({ err: error }, 'Error in handlePay');
await bot.sendMessage(chatId, 'Error processing purchase. Please try again.'); await bot.sendMessage(chatId, 'Error processing purchase. Please try again.');
} }
} }

View File

@@ -11,6 +11,7 @@ import CategoryService from "../../services/categoryService.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
import logger from '../../utils/logger.js';
export default class UserPurchaseHandler { export default class UserPurchaseHandler {
static async viewPurchasePage(userId, page) { static async viewPurchasePage(userId, page) {
@@ -75,7 +76,7 @@ export default class UserPurchaseHandler {
markup: keyboard markup: keyboard
}; };
} catch (error) { } catch (error) {
console.error('Error in viewPurchasePage:', error); logger.error({ err: error }, 'Error in viewPurchasePage');
return { text: 'Error loading purchase history. Please try again.' }; return { text: 'Error loading purchase history. Please try again.' };
} }
} }
@@ -99,7 +100,7 @@ export default class UserPurchaseHandler {
try { try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId); await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting Hidden Photo message:', error); logger.error({ err: error }, 'Error deleting Hidden Photo message');
} }
} }
@@ -115,7 +116,7 @@ export default class UserPurchaseHandler {
// Удаляем состояние пользователя // Удаляем состояние пользователя
userStates.delete(chatId); userStates.delete(chatId);
} catch (e) { } catch (e) {
console.error('Error in handlePurchaseListPage:', e); logger.error({ err: e }, 'Error in handlePurchaseListPage');
await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.'); await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.');
} }
} }
@@ -136,7 +137,7 @@ export default class UserPurchaseHandler {
await bot.sendMessage(chatId, text, { reply_markup: markup, parse_mode: 'Markdown' }); await bot.sendMessage(chatId, text, { reply_markup: markup, parse_mode: 'Markdown' });
} catch (error) { } catch (error) {
console.error('Error in showPurchases:', error); logger.error({ err: error }, 'Error in showPurchases');
await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.'); await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.');
} }
} }
@@ -172,7 +173,7 @@ export default class UserPurchaseHandler {
try { try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId); await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting Hidden Photo message:', error); logger.error({ err: error }, 'Error deleting Hidden Photo message');
} }
} }
@@ -224,7 +225,7 @@ export default class UserPurchaseHandler {
hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null
}); });
} catch (error) { } catch (error) {
console.error('Error in viewPurchase:', error); logger.error({ err: error }, 'Error in viewPurchase');
await bot.sendMessage(chatId, 'Error loading purchase details. Please try again.'); await bot.sendMessage(chatId, 'Error loading purchase details. Please try again.');
} }
} }
@@ -283,7 +284,7 @@ export default class UserPurchaseHandler {
try { try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId); await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) { } catch (error) {
console.error('Error deleting Hidden Photo message:', error); logger.error({ err: error }, 'Error deleting Hidden Photo message');
} }
} }
@@ -293,7 +294,7 @@ export default class UserPurchaseHandler {
// Открываем список покупок для пользователя // Открываем список покупок для пользователя
await this.showPurchases({ chat: { id: chatId }, from: { id: callbackQuery.from.id } }); await this.showPurchases({ chat: { id: chatId }, from: { id: callbackQuery.from.id } });
} catch (error) { } catch (error) {
console.error('Error in handleConfirmReceived:', error); logger.error({ err: error }, 'Error in handleConfirmReceived');
await bot.sendMessage(chatId, 'Error confirming receipt. Please try again.'); await bot.sendMessage(chatId, 'Error confirming receipt. Please try again.');
} }
} }

View File

@@ -2,6 +2,7 @@ import db from '../../../config/database.js';
import WalletUtils from '../../../utils/walletUtils.js'; import WalletUtils from '../../../utils/walletUtils.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class ArchiveHandler { export default class ArchiveHandler {
static async handleViewArchivedWallets(callbackQuery) { static async handleViewArchivedWallets(callbackQuery) {
@@ -80,7 +81,7 @@ export default class ArchiveHandler {
reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] } reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] }
}); });
} catch (error) { } catch (error) {
console.error('Error in handleViewArchivedWallets:', error); logger.error({ err: error }, 'Error in handleViewArchivedWallets');
await bot.sendMessage(chatId, 'Error loading archived wallets. Please try again.'); await bot.sendMessage(chatId, 'Error loading archived wallets. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import WalletUtils from '../../../utils/walletUtils.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import WalletService from '../../../services/walletService.js'; import WalletService from '../../../services/walletService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class BalanceHandler { export default class BalanceHandler {
static async showBalance(msg) { static async showBalance(msg) {
@@ -82,7 +83,7 @@ export default class BalanceHandler {
await bot.sendMessage(chatId, message, { reply_markup: keyboard, parse_mode: 'Markdown' }); await bot.sendMessage(chatId, message, { reply_markup: keyboard, parse_mode: 'Markdown' });
} catch (error) { } catch (error) {
console.error('Error in showBalance:', error); logger.error({ err: error }, 'Error in showBalance');
await bot.sendMessage(chatId, 'Error loading balance. Please try again.'); await bot.sendMessage(chatId, 'Error loading balance. Please try again.');
} }
} }

View File

@@ -3,6 +3,7 @@ import WalletService from '../../../services/walletService.js';
import Validators from '../../../utils/validators.js'; import Validators from '../../../utils/validators.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import logger from '../../../utils/logger.js';
export default class CreateHandler { export default class CreateHandler {
static async handleAddWallet(callbackQuery) { static async handleAddWallet(callbackQuery) {
@@ -85,7 +86,7 @@ export default class CreateHandler {
throw error; throw error;
} }
} catch (error) { } catch (error) {
console.error('Error generating wallet:', error); logger.error({ err: error }, 'Error generating wallet');
await bot.editMessageText('❌ Error generating wallet. Please try again.', { await bot.editMessageText('❌ Error generating wallet. Please try again.', {
chat_id: chatId, message_id: callbackQuery.message.message_id, chat_id: chatId, message_id: callbackQuery.message.message_id,
reply_markup: { inline_keyboard: [[{ text: '« Back to Balance', callback_data: 'back_to_balance' }]] } reply_markup: { inline_keyboard: [[{ text: '« Back to Balance', callback_data: 'back_to_balance' }]] }

View File

@@ -1,6 +1,7 @@
import db from '../../../config/database.js'; import db from '../../../config/database.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class HistoryHandler { export default class HistoryHandler {
static async handleTransactionHistory(callbackQuery, page = 0) { static async handleTransactionHistory(callbackQuery, page = 0) {
@@ -61,7 +62,7 @@ export default class HistoryHandler {
parse_mode: 'Markdown', reply_markup: keyboard parse_mode: 'Markdown', reply_markup: keyboard
}); });
} catch (error) { } catch (error) {
console.error('Error in handleTransactionHistory:', error); logger.error({ err: error }, 'Error in handleTransactionHistory');
await bot.sendMessage(chatId, 'Error loading transaction history. Please try again.'); await bot.sendMessage(chatId, 'Error loading transaction history. Please try again.');
} }
} }
@@ -101,7 +102,7 @@ export default class HistoryHandler {
reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] } reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] }
}); });
} catch (error) { } catch (error) {
console.error('Error in handleWalletHistory:', error); logger.error({ err: error }, 'Error in handleWalletHistory');
await bot.sendMessage(chatId, 'Error loading transaction history. Please try again.'); await bot.sendMessage(chatId, 'Error loading transaction history. Please try again.');
} }
} }

View File

@@ -2,6 +2,7 @@ import db from '../../../config/database.js';
import WalletUtils from '../../../utils/walletUtils.js'; import WalletUtils from '../../../utils/walletUtils.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class RefreshHandler { export default class RefreshHandler {
static async handleRefreshBalance(callbackQuery) { static async handleRefreshBalance(callbackQuery) {
@@ -66,7 +67,7 @@ export default class RefreshHandler {
await bot.deleteMessage(chatId, messageId); await bot.deleteMessage(chatId, messageId);
} catch (error) { } catch (error) {
console.error('Error in handleRefreshBalance:', error); logger.error({ err: error }, 'Error in handleRefreshBalance');
await bot.answerCallbackQuery(callbackQuery.id, { text: '❌ Error refreshing balances.' }); await bot.answerCallbackQuery(callbackQuery.id, { text: '❌ Error refreshing balances.' });
await bot.sendMessage(chatId, '❌ Error refreshing balances. Please try again.', { await bot.sendMessage(chatId, '❌ Error refreshing balances. Please try again.', {
reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] } reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] }

View File

@@ -2,6 +2,7 @@ import db from '../../../config/database.js';
import WalletUtils from '../../../utils/walletUtils.js'; import WalletUtils from '../../../utils/walletUtils.js';
import UserService from '../../../services/userService.js'; import UserService from '../../../services/userService.js';
import bot from '../../../context/bot.js'; import bot from '../../../context/bot.js';
import logger from '../../../utils/logger.js';
export default class TopUpHandler { export default class TopUpHandler {
static async handleTopUpWallet(callbackQuery) { static async handleTopUpWallet(callbackQuery) {
@@ -54,7 +55,7 @@ export default class TopUpHandler {
reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] } reply_markup: { inline_keyboard: [[{ text: '« Back', callback_data: 'back_to_balance' }]] }
}); });
} catch (error) { } catch (error) {
console.error('Error in handleTopUpWallet:', error); logger.error({ err: error }, 'Error in handleTopUpWallet');
await bot.sendMessage(chatId, 'Error loading wallets. Please try again.'); await bot.sendMessage(chatId, 'Error loading wallets. Please try again.');
} }
} }

View File

@@ -2,6 +2,7 @@ import { runMigrations, cleanUpInvalidForeignKeys } from './migrations/runner.js
import './router/routes.js'; import './router/routes.js';
import bot from './context/bot.js'; import bot from './context/bot.js';
import ErrorHandler from './utils/errorHandler.js'; import ErrorHandler from './utils/errorHandler.js';
import logger from './utils/logger.js';
import userHandler from './handlers/userHandlers/userHandler.js'; import userHandler from './handlers/userHandlers/userHandler.js';
import adminHandler from './handlers/adminHandlers/adminHandler.js'; import adminHandler from './handlers/adminHandlers/adminHandler.js';
import callbackRouter from './router/callbackRouter.js'; import callbackRouter from './router/callbackRouter.js';
@@ -11,8 +12,7 @@ await runMigrations();
await cleanUpInvalidForeignKeys(); await cleanUpInvalidForeignKeys();
const logDebug = (action, functionName) => { const logDebug = (action, functionName) => {
console.log(`[DEBUG] Button Press: ${action}`); logger.debug({ action, functionName }, 'Button Press');
console.log(`[DEBUG] Calling Function: ${functionName}`);
}; };
bot.onText(/\/start/, async (msg) => { bot.onText(/\/start/, async (msg) => {
@@ -63,7 +63,7 @@ bot.on('callback_query', async (callbackQuery) => {
bot.on('polling_error', ErrorHandler.handlePollingError); bot.on('polling_error', ErrorHandler.handlePollingError);
process.on('unhandledRejection', (error) => { process.on('unhandledRejection', (error) => {
console.error('Unhandled promise rejection:', error); logger.error({ err: error }, 'Unhandled promise rejection');
}); });
console.log('Bot is running...'); logger.info('Bot is running...');

View File

@@ -1,3 +1,5 @@
import logger from '../utils/logger.js';
export default async function migration001(db) { export default async function migration001(db) {
await db.runAsync('BEGIN TRANSACTION'); await db.runAsync('BEGIN TRANSACTION');
@@ -88,5 +90,5 @@ export default async function migration001(db) {
)`); )`);
await db.runAsync('COMMIT'); await db.runAsync('COMMIT');
console.log('Migration 001: Initial schema created'); logger.info('Migration 001: Initial schema created');
} }

View File

@@ -1,33 +1,35 @@
import logger from '../utils/logger.js';
export default async function migration002(db, checkColumnExists) { export default async function migration002(db, checkColumnExists) {
const balanceExists = await checkColumnExists('crypto_wallets', 'balance'); const balanceExists = await checkColumnExists('crypto_wallets', 'balance');
if (!balanceExists) { if (!balanceExists) {
await db.runAsync(`ALTER TABLE crypto_wallets ADD COLUMN balance REAL DEFAULT 0`); await db.runAsync(`ALTER TABLE crypto_wallets ADD COLUMN balance REAL DEFAULT 0`);
console.log('Migration 002: Column balance added to crypto_wallets'); logger.info('Migration 002: Column balance added to crypto_wallets');
} }
const userIdExists = await checkColumnExists('transactions', 'user_id'); const userIdExists = await checkColumnExists('transactions', 'user_id');
if (!userIdExists) { if (!userIdExists) {
await db.runAsync(`ALTER TABLE transactions ADD COLUMN user_id INTEGER NOT NULL`); await db.runAsync(`ALTER TABLE transactions ADD COLUMN user_id INTEGER NOT NULL`);
console.log('Migration 002: Column user_id added to transactions'); logger.info('Migration 002: Column user_id added to transactions');
} }
const walletTypeExists = await checkColumnExists('transactions', 'wallet_type'); const walletTypeExists = await checkColumnExists('transactions', 'wallet_type');
if (!walletTypeExists) { if (!walletTypeExists) {
await db.runAsync(`ALTER TABLE transactions ADD COLUMN wallet_type TEXT NOT NULL`); await db.runAsync(`ALTER TABLE transactions ADD COLUMN wallet_type TEXT NOT NULL`);
console.log('Migration 002: Column wallet_type added to transactions'); logger.info('Migration 002: Column wallet_type added to transactions');
} }
const txHashExists = await checkColumnExists('transactions', 'tx_hash'); const txHashExists = await checkColumnExists('transactions', 'tx_hash');
if (!txHashExists) { if (!txHashExists) {
await db.runAsync(`ALTER TABLE transactions ADD COLUMN tx_hash TEXT NOT NULL`); await db.runAsync(`ALTER TABLE transactions ADD COLUMN tx_hash TEXT NOT NULL`);
console.log('Migration 002: Column tx_hash added to transactions'); logger.info('Migration 002: Column tx_hash added to transactions');
} }
const statusExists = await checkColumnExists('purchases', 'status'); const statusExists = await checkColumnExists('purchases', 'status');
if (!statusExists) { if (!statusExists) {
await db.runAsync(`ALTER TABLE purchases ADD COLUMN status TEXT DEFAULT 'pending'`); await db.runAsync(`ALTER TABLE purchases ADD COLUMN status TEXT DEFAULT 'pending'`);
console.log('Migration 002: Column status added to purchases'); logger.info('Migration 002: Column status added to purchases');
} }
console.log('Migration 002: Column additions complete'); logger.info('Migration 002: Column additions complete');
} }

View File

@@ -1,3 +1,5 @@
import logger from '../utils/logger.js';
export default async function migration003(db) { export default async function migration003(db) {
await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_users_telegram_id ON users(telegram_id)`); await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_users_telegram_id ON users(telegram_id)`);
await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_crypto_wallets_user_type ON crypto_wallets(user_id, wallet_type)`); await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_crypto_wallets_user_type ON crypto_wallets(user_id, wallet_type)`);
@@ -5,5 +7,5 @@ export default async function migration003(db) {
await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_purchases_user_product ON purchases(user_id, product_id)`); await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_purchases_user_product ON purchases(user_id, product_id)`);
await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_purchases_status ON purchases(status)`); await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_purchases_status ON purchases(status)`);
await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_products_location_category ON products(location_id, category_id)`); await db.runAsync(`CREATE INDEX IF NOT EXISTS idx_products_location_category ON products(location_id, category_id)`);
console.log('Migration 003: Indexes created'); logger.info('Migration 003: Indexes created');
} }

View File

@@ -1,4 +1,5 @@
import db from '../config/database.js'; import db from '../config/database.js';
import logger from '../utils/logger.js';
const ALLOWED_TABLES = new Set([ const ALLOWED_TABLES = new Set([
'users', 'crypto_wallets', 'transactions', 'products', 'users', 'crypto_wallets', 'transactions', 'products',
@@ -13,7 +14,7 @@ export const checkColumnExists = async (tableName, columnName) => {
const result = await db.allAsync(`PRAGMA table_info(${tableName})`); const result = await db.allAsync(`PRAGMA table_info(${tableName})`);
return result.some(column => column.name === columnName); return result.some(column => column.name === columnName);
} catch (error) { } catch (error) {
console.error(`Error checking column ${columnName} in table ${tableName}:`, error); logger.error({ err: error, tableName, columnName }, 'Error checking column');
return false; return false;
} }
}; };
@@ -21,9 +22,9 @@ export const checkColumnExists = async (tableName, columnName) => {
export const cleanUpInvalidForeignKeys = async () => { export const cleanUpInvalidForeignKeys = async () => {
try { try {
await db.runAsync(`DELETE FROM crypto_wallets WHERE user_id NOT IN (SELECT id FROM users)`); await db.runAsync(`DELETE FROM crypto_wallets WHERE user_id NOT IN (SELECT id FROM users)`);
console.log('Cleaned up invalid foreign key references in crypto_wallets table'); logger.info('Cleaned up invalid foreign key references in crypto_wallets table');
} catch (error) { } catch (error) {
console.error('Error cleaning up invalid foreign key references:', error); logger.error({ err: error }, 'Error cleaning up invalid foreign key references');
} }
}; };
@@ -40,7 +41,7 @@ export async function runMigrations() {
]; ];
for (let i = currentVersion; i < migrations.length; i++) { for (let i = currentVersion; i < migrations.length; i++) {
console.log(`Running migration ${i + 1}/${migrations.length}...`); logger.info({ migration: i + 1, total: migrations.length }, 'Running migration');
if (i === 1) { if (i === 1) {
await migrations[i](db, checkColumnExists); await migrations[i](db, checkColumnExists);
} else { } else {
@@ -52,5 +53,5 @@ export async function runMigrations() {
); );
} }
console.log(`Migrations complete. Schema version: ${migrations.length}`); logger.info({ schemaVersion: migrations.length }, 'Migrations complete');
} }

View File

@@ -1,3 +1,5 @@
import logger from '../utils/logger.js';
class CallbackRouter { class CallbackRouter {
constructor() { constructor() {
this.exactRoutes = new Map(); this.exactRoutes = new Map();
@@ -29,7 +31,7 @@ class CallbackRouter {
} }
} }
console.warn(`No handler for callback: ${action}`); logger.warn({ action }, 'No handler for callback');
} }
} }

View File

@@ -1,6 +1,7 @@
import callbackRouter from './callbackRouter.js'; import callbackRouter from './callbackRouter.js';
import messageRouter from './messageRouter.js'; import messageRouter from './messageRouter.js';
import { isAdmin } from '../middleware/auth.js'; import { isAdmin } from '../middleware/auth.js';
import logger from '../utils/logger.js';
import userHandler from '../handlers/userHandlers/userHandler.js'; import userHandler from '../handlers/userHandlers/userHandler.js';
import userPurchaseHandler from '../handlers/userHandlers/userPurchaseHandler.js'; import userPurchaseHandler from '../handlers/userHandlers/userPurchaseHandler.js';
@@ -17,8 +18,7 @@ import adminWalletsHandler from '../handlers/adminHandlers/adminWalletsHandler.j
import adminUserHandler from '../handlers/adminHandlers/adminUserHandler.js'; import adminUserHandler from '../handlers/adminHandlers/adminUserHandler.js';
const logDebug = (action, functionName) => { const logDebug = (action, functionName) => {
console.log(`[DEBUG] Button Press: ${action}`); logger.debug({ action, functionName }, 'Button Press');
console.log(`[DEBUG] Calling Function: ${functionName}`);
}; };
export function registerRoutes() { export function registerRoutes() {

View File

@@ -1,4 +1,5 @@
import db from "../config/database.js"; import db from "../config/database.js";
import logger from "../utils/logger.js";
class CategoryService { class CategoryService {
static async getCategoriesByLocationId(locationId) { static async getCategoriesByLocationId(locationId) {
@@ -9,7 +10,7 @@ class CategoryService {
); );
return categories; return categories;
} catch (error) { } catch (error) {
console.error('Error fetching categories by location ID:', error); logger.error({ err: error }, 'Error fetching categories by location ID');
throw new Error('Failed to fetch categories'); throw new Error('Failed to fetch categories');
} }
} }
@@ -29,7 +30,7 @@ class CategoryService {
); );
return category; return category;
} catch (error) { } catch (error) {
console.error('Error fetching category by ID:', error); logger.error({ err: error }, 'Error fetching category by ID');
throw new Error('Failed to fetch category'); throw new Error('Failed to fetch category');
} }
} }

View File

@@ -1,4 +1,5 @@
import db from "../config/database.js"; import db from "../config/database.js";
import logger from "../utils/logger.js";
class LocationService { class LocationService {
static async getCountries() { static async getCountries() {
@@ -27,7 +28,7 @@ class LocationService {
); );
return location; return location;
} catch (error) { } catch (error) {
console.error('Error fetching location:', error); logger.error({ err: error }, 'Error fetching location');
throw new Error('Failed to fetch location'); throw new Error('Failed to fetch location');
} }
} }
@@ -40,7 +41,7 @@ class LocationService {
); );
return location; return location;
} catch (error) { } catch (error) {
console.error('Error fetching location by ID:', error); logger.error({ err: error }, 'Error fetching location by ID');
throw new Error('Failed to fetch location'); throw new Error('Failed to fetch location');
} }
} }

View File

@@ -2,6 +2,7 @@
import db from "../config/database.js"; import db from "../config/database.js";
import Validators from "../utils/validators.js"; import Validators from "../utils/validators.js";
import logger from "../utils/logger.js";
class ProductService { class ProductService {
static async getProductById(productId) { static async getProductById(productId) {
@@ -11,7 +12,7 @@ class ProductService {
try { try {
return await db.getAsync(`SELECT * FROM products WHERE id = ?`, [productId]); return await db.getAsync(`SELECT * FROM products WHERE id = ?`, [productId]);
} catch (error) { } catch (error) {
console.error('Error get product:', error); logger.error({ err: error }, 'Error get product');
throw error; throw error;
} }
} }
@@ -70,7 +71,7 @@ class ProductService {
[quantity, productId] [quantity, productId]
); );
} catch (error) { } catch (error) {
console.error('Error decreasing product quantity:', error); logger.error({ err: error }, 'Error decreasing product quantity');
throw new Error('Failed to update product quantity'); throw new Error('Failed to update product quantity');
} }
} }

View File

@@ -2,6 +2,7 @@
import db from "../config/database.js"; import db from "../config/database.js";
import crypto from "crypto"; import crypto from "crypto";
import logger from "../utils/logger.js";
class PurchaseService { class PurchaseService {
static async getPurchasesByUserId(userId, limit, offset) { static async getPurchasesByUserId(userId, limit, offset) {
@@ -24,7 +25,7 @@ class PurchaseService {
`, [userId, limit, offset]); `, [userId, limit, offset]);
} catch (error) { } catch (error) {
console.error('Error get purchases:', error); logger.error({ err: error }, 'Error get purchases');
throw error; throw error;
} }
} }
@@ -36,7 +37,7 @@ class PurchaseService {
[purchaseId] [purchaseId]
); );
} catch (error) { } catch (error) {
console.error('Error getting purchase by ID:', error); logger.error({ err: error }, 'Error getting purchase by ID');
throw error; throw error;
} }
} }
@@ -113,7 +114,7 @@ class PurchaseService {
return result.lastID; return result.lastID;
} catch (error) { } catch (error) {
try { await db.runAsync('ROLLBACK'); } catch (_) {} try { await db.runAsync('ROLLBACK'); } catch (_) {}
console.error('Error creating purchase:', error); logger.error({ err: error }, 'Error creating purchase');
throw error; throw error;
} }
} }
@@ -152,7 +153,7 @@ class PurchaseService {
await db.runAsync('COMMIT'); await db.runAsync('COMMIT');
} catch (error) { } catch (error) {
try { await db.runAsync('ROLLBACK'); } catch (_) {} try { await db.runAsync('ROLLBACK'); } catch (_) {}
console.error('Error updating purchase status:', error); logger.error({ err: error }, 'Error updating purchase status');
throw new Error('Failed to update purchase status'); throw new Error('Failed to update purchase status');
} }
} }
@@ -165,7 +166,7 @@ class PurchaseService {
); );
return total.total; return total.total;
} catch (error) { } catch (error) {
console.error('Error fetching total purchases by user ID:', error); logger.error({ err: error }, 'Error fetching total purchases by user ID');
throw new Error('Failed to fetch total purchases'); throw new Error('Failed to fetch total purchases');
} }
} }

View File

@@ -3,6 +3,7 @@
import db from "../config/database.js"; import db from "../config/database.js";
import Wallet from "../models/Wallet.js"; import Wallet from "../models/Wallet.js";
import WalletUtils from "../utils/walletUtils.js"; import WalletUtils from "../utils/walletUtils.js";
import logger from "../utils/logger.js";
const ALLOWED_USER_FIELDS = new Set([ const ALLOWED_USER_FIELDS = new Set([
'telegram_id', 'username', 'country', 'city', 'telegram_id', 'username', 'country', 'city',
@@ -35,7 +36,6 @@ class UserService {
try { try {
// Нормализуем и валидируем telegram_id // Нормализуем и валидируем telegram_id
const normalizedTelegramId = this.normalizeTelegramId(userData?.telegram_id); const normalizedTelegramId = this.normalizeTelegramId(userData?.telegram_id);
// console.log("Normalized telegram_id:", normalizedTelegramId); // Отладочный вывод
this.validateTelegramId(normalizedTelegramId); this.validateTelegramId(normalizedTelegramId);
// Обновляем значение telegram_id в объекте userData // Обновляем значение telegram_id в объекте userData
@@ -44,7 +44,7 @@ class UserService {
// Проверяем, существует ли пользователь с таким telegram_id // Проверяем, существует ли пользователь с таким telegram_id
const existingUser = await this.getUserByTelegramId(normalizedTelegramId); const existingUser = await this.getUserByTelegramId(normalizedTelegramId);
if (existingUser) { if (existingUser) {
console.log("User already exists with telegram_id:", normalizedTelegramId); logger.info({ telegramId: normalizedTelegramId }, 'User already exists');
return existingUser.id; return existingUser.id;
} }
@@ -70,7 +70,7 @@ class UserService {
return result.lastID; return result.lastID;
} catch (error) { } catch (error) {
await db.runAsync('ROLLBACK'); await db.runAsync('ROLLBACK');
console.error('Error creating user:', error); logger.error({ err: error }, 'Error creating user');
throw error; throw error;
} }
} }
@@ -82,7 +82,7 @@ class UserService {
[String(userId)] [String(userId)]
); );
} catch (error) { } catch (error) {
console.error('Error getting user:', error); logger.error({ err: error }, 'Error getting user');
throw error; throw error;
} }
} }
@@ -95,7 +95,7 @@ class UserService {
[normalizedTelegramId] [normalizedTelegramId]
); );
} catch (error) { } catch (error) {
console.error('Error getting user:', error); logger.error({ err: error }, 'Error getting user');
throw error; throw error;
} }
} }
@@ -120,7 +120,7 @@ class UserService {
GROUP BY u.id GROUP BY u.id
`, [normalizedTelegramId]); `, [normalizedTelegramId]);
} catch (error) { } catch (error) {
console.error('Error getting user stats:', error); logger.error({ err: error }, 'Error getting user stats');
throw error; throw error;
} }
} }
@@ -169,9 +169,9 @@ class UserService {
[remainingBalance, user.id] [remainingBalance, user.id]
); );
console.log(`[DEBUG] Updated total_balance for user ${user.id}: ${remainingBalance}`); logger.debug({ userId: user.id, remainingBalance }, 'Updated total_balance');
} catch (error) { } catch (error) {
console.error('Error recalculating user balance:', error); logger.error({ err: error }, 'Error recalculating user balance');
throw error; throw error;
} }
} }
@@ -196,7 +196,7 @@ class UserService {
await db.runAsync('COMMIT'); await db.runAsync('COMMIT');
} catch (e) { } catch (e) {
await db.runAsync("ROLLBACK"); await db.runAsync("ROLLBACK");
console.error('Error deleting user:', e); logger.error({ err: e }, 'Error deleting user');
throw e; throw e;
} }
} }
@@ -211,7 +211,7 @@ class UserService {
// Возвращаем сумму доступного крипто-баланса и бонусного баланса // Возвращаем сумму доступного крипто-баланса и бонусного баланса
return user.total_balance + user.bonus_balance; return user.total_balance + user.bonus_balance;
} catch (error) { } catch (error) {
console.error('Error getting user balance:', error); logger.error({ err: error }, 'Error getting user balance');
throw error; throw error;
} }
} }

View File

@@ -5,6 +5,7 @@ import config from "../config/config.js";
import WalletUtils from "../utils/walletUtils.js"; import WalletUtils from "../utils/walletUtils.js";
import WalletGenerator from "../utils/walletGenerator.js"; import WalletGenerator from "../utils/walletGenerator.js";
import { encrypt, decrypt } from '../utils/encryption.js'; import { encrypt, decrypt } from '../utils/encryption.js';
import logger from '../utils/logger.js';
class WalletService { class WalletService {
static async getArchivedWalletsCount(user) { static async getArchivedWalletsCount(user) {
@@ -17,7 +18,7 @@ class WalletService {
); );
return archivedWallets.total; return archivedWallets.total;
} catch (error) { } catch (error) {
console.error('Error fetching archived wallets count:', error); logger.error({ err: error }, 'Error fetching archived wallets count');
throw new Error('Failed to fetch archived wallets count'); throw new Error('Failed to fetch archived wallets count');
} }
} }
@@ -41,7 +42,7 @@ class WalletService {
return totalBalance; return totalBalance;
} catch (error) { } catch (error) {
console.error('Error fetching active wallets balance:', error); logger.error({ err: error }, 'Error fetching active wallets balance');
throw new Error('Failed to fetch active wallets balance'); throw new Error('Failed to fetch active wallets balance');
} }
} }
@@ -65,7 +66,7 @@ class WalletService {
return totalBalance; return totalBalance;
} catch (error) { } catch (error) {
console.error('Error fetching archived wallets balance:', error); logger.error({ err: error }, 'Error fetching archived wallets balance');
throw new Error('Failed to fetch archived wallets balance'); throw new Error('Failed to fetch archived wallets balance');
} }
} }
@@ -82,7 +83,7 @@ class WalletService {
return wallets; return wallets;
} catch (error) { } catch (error) {
console.error('Error fetching wallets by type:', error); logger.error({ err: error }, 'Error fetching wallets by type');
throw new Error('Failed to fetch wallets by type'); throw new Error('Failed to fetch wallets by type');
} }
} }
@@ -128,11 +129,7 @@ class WalletService {
// Получаем адрес для базового типа // Получаем адрес для базового типа
const walletData = wallets[baseType.toUpperCase()]; const walletData = wallets[baseType.toUpperCase()];
if (!walletData || !walletData.address) { if (!walletData || !walletData.address) {
console.error('Wallet generation failed:', { logger.error({ baseType, walletKeys: Object.keys(wallets) }, 'Wallet generation failed');
baseType,
wallets: Object.keys(wallets),
walletData
});
throw new Error('Failed to generate wallet address'); throw new Error('Failed to generate wallet address');
} }
const address = walletData.address; const address = walletData.address;
@@ -159,7 +156,7 @@ class WalletService {
// Проверяем целостность записанной мнемоники // Проверяем целостность записанной мнемоники
const decryptedMnemonic = decrypt(insertedWallet.mnemonic, userId); const decryptedMnemonic = decrypt(insertedWallet.mnemonic, userId);
if (decryptedMnemonic !== mnemonic) { if (decryptedMnemonic !== mnemonic) {
console.error('Mnemonic verification failed for wallet:', walletType); logger.error({ walletType }, 'Mnemonic verification failed');
await db.runAsync( await db.runAsync(
`DELETE FROM crypto_wallets `DELETE FROM crypto_wallets
WHERE user_id = ? AND wallet_type = ?`, WHERE user_id = ? AND wallet_type = ?`,
@@ -168,12 +165,7 @@ class WalletService {
throw new Error('Mnemonic verification failed'); throw new Error('Mnemonic verification failed');
} }
console.log(`Successfully created and verified wallet: ${walletType}`, { logger.info({ walletType, address, derivationPath, userId }, 'Successfully created and verified wallet');
address,
derivationPath,
userId,
walletType
});
return { return {
address, address,
derivationPath, derivationPath,
@@ -182,7 +174,7 @@ class WalletService {
}; };
} catch (error) { } catch (error) {
console.error('Error creating wallet:', error); logger.error({ err: error }, 'Error creating wallet');
throw new Error('Failed to create wallet: ' + error.message); throw new Error('Failed to create wallet: ' + error.message);
} }
} }
@@ -194,7 +186,7 @@ class WalletService {
} }
return decrypt(encryptedMnemonic, userId); return decrypt(encryptedMnemonic, userId);
} catch (error) { } catch (error) {
console.error('Error decrypting mnemonic:', error); logger.error({ err: error }, 'Error decrypting mnemonic');
throw new Error('Failed to decrypt mnemonic: ' + error.message); throw new Error('Failed to decrypt mnemonic: ' + error.message);
} }
} }

View File

@@ -1,6 +1,8 @@
import logger from './logger.js';
export default class ErrorHandler { export default class ErrorHandler {
static async handleError(bot, chatId, error, context) { static async handleError(bot, chatId, error, context) {
console.error(`Error in ${context}:`, error); logger.error({ err: error, context }, 'Error in handler');
const errorMessage = process.env.NODE_ENV === 'development' const errorMessage = process.env.NODE_ENV === 'development'
? `Error: ${error.message}` ? `Error: ${error.message}`
@@ -9,16 +11,16 @@ export default class ErrorHandler {
try { try {
await bot.sendMessage(chatId, errorMessage); await bot.sendMessage(chatId, errorMessage);
} catch (sendError) { } catch (sendError) {
console.error('Error sending error message:', sendError); logger.error({ err: sendError }, 'Error sending error message');
} }
} }
static handlePollingError(error) { static handlePollingError(error) {
if (error.code === 'ETELEGRAM') { if (error.code === 'ETELEGRAM') {
console.error('Telegram API Error:', error.message); logger.error({ err: error }, 'Telegram API Error');
process.exit(1); process.exit(1);
} else { } else {
console.error('Polling error:', error); logger.error({ err: error }, 'Polling error');
} }
} }
} }

19
src/utils/logger.js Normal file
View File

@@ -0,0 +1,19 @@
import pino from 'pino';
const level = process.env.LOG_LEVEL || 'info';
const options = {
level,
redact: ['*.mnemonic', '*.privateKey', '*.secret', '*.token', '*.password', '*.ENCRYPTION_KEY', '*.BOT_TOKEN'],
serializers: {
err: pino.stdSerializers.err,
},
};
if (process.env.NODE_ENV !== 'production') {
options.transport = { target: 'pino-pretty', options: { colorize: true } };
}
const logger = pino(options);
export default logger;

View File

@@ -8,6 +8,7 @@ import * as bitcoin from 'bitcoinjs-lib';
import * as ecc from 'tiny-secp256k1'; import * as ecc from 'tiny-secp256k1';
import { ECPairFactory } from 'ecpair'; import { ECPairFactory } from 'ecpair';
import CryptoJS from 'crypto'; import CryptoJS from 'crypto';
import logger from './logger.js';
const ECPair = ECPairFactory(ecc); const ECPair = ECPairFactory(ecc);
@@ -16,7 +17,7 @@ export default class WalletGenerator {
try { try {
return bip39.generateMnemonic(128); // 12 слов return bip39.generateMnemonic(128); // 12 слов
} catch (error) { } catch (error) {
console.error('Error generating mnemonic:', error); logger.error({ err: error }, 'Error generating mnemonic');
throw new Error('Failed to generate mnemonic'); throw new Error('Failed to generate mnemonic');
} }
} }
@@ -86,7 +87,7 @@ export default class WalletGenerator {
}, },
}; };
} catch (error) { } catch (error) {
console.error('Error in generateWallets:', error); logger.error({ err: error }, 'Error in generateWallets');
throw new Error('Failed to generate cryptocurrency wallets: ' + error.message); throw new Error('Failed to generate cryptocurrency wallets: ' + error.message);
} }
} }

View File

@@ -1,7 +1,8 @@
// walletUtils.js // walletUtils.js
import axios from 'axios'; import axios from 'axios';
import db from '../config/database.js'; // Импортируем базу данных import db from '../config/database.js';
import logger from './logger.js';
// Массив публичных RPC-узлов // Массив публичных RPC-узлов
const rpcNodes = [ const rpcNodes = [
@@ -94,14 +95,14 @@ export default class WalletUtils {
static async getCryptoPrices() { static async getCryptoPrices() {
// Если кеш актуален, возвращаем его // Если кеш актуален, возвращаем его
if (cryptoPricesCache && Date.now() - cacheTimestamp < CACHE_TTL) { if (cryptoPricesCache && Date.now() - cacheTimestamp < CACHE_TTL) {
console.log('[DEBUG] Using cached crypto prices:', cryptoPricesCache); logger.debug('Using cached crypto prices');
return cryptoPricesCache; return cryptoPricesCache;
} }
// Если кеш устарел, запрашиваем новые данные // Если кеш устарел, запрашиваем новые данные
for (const api of cryptoPriceAPIs) { for (const api of cryptoPriceAPIs) {
try { try {
console.log(`[DEBUG] Trying to fetch prices from ${api.name}...`); logger.debug({ apiName: api.name }, 'Trying to fetch prices');
let data; let data;
if (api.name === 'Binance') { if (api.name === 'Binance') {
data = await api.parser(api.urls); data = await api.parser(api.urls);
@@ -109,7 +110,7 @@ export default class WalletUtils {
const response = await axios.get(api.url); const response = await axios.get(api.url);
data = api.parser(response.data); data = api.parser(response.data);
} }
console.log(`[DEBUG] Successfully fetched prices from ${api.name}:`, data); logger.debug({ apiName: api.name }, 'Successfully fetched prices');
// Обновляем кеш // Обновляем кеш
cryptoPricesCache = data; cryptoPricesCache = data;
@@ -118,17 +119,17 @@ export default class WalletUtils {
return data; return data;
} catch (error) { } catch (error) {
if (error.response && error.response.status === 429) { if (error.response && error.response.status === 429) {
console.log(`[DEBUG] Rate limit exceeded on ${api.name}. Retrying after 2 seconds...`); logger.debug({ apiName: api.name }, 'Rate limit exceeded, retrying after 2 seconds');
await sleep(2000); await sleep(2000);
continue; // Пробуем снова с тем же API continue; // Пробуем снова с тем же API
} else { } else {
console.error(`[DEBUG] Error fetching prices from ${api.name}:`, error.message); logger.error({ err: error, apiName: api.name }, 'Error fetching prices');
} }
} }
} }
// Если все API не сработали, используем fallback-значения // Если все API не сработали, используем fallback-значения
console.error('[DEBUG] All APIs failed. Using fallback prices.'); logger.error('All APIs failed. Using fallback prices.');
cryptoPricesCache = { cryptoPricesCache = {
btc: 0, ltc: 0, eth: 0, usdt: 1, usdc: 1 btc: 0, ltc: 0, eth: 0, usdt: 1, usdc: 1
}; };
@@ -139,17 +140,17 @@ export default class WalletUtils {
async fetchApiRequest(url) { async fetchApiRequest(url) {
try { try {
console.log(`[DEBUG] Fetching data from: ${url}`); // Логируем URL запроса logger.debug({ url }, 'Fetching data');
const response = await axios.get(url); const response = await axios.get(url);
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error(`Error fetching data from ${url}:`, error); logger.error({ err: error, url }, 'Error fetching data');
return null; return null;
} }
} }
async fetchRpcRequest(method, params) { async fetchRpcRequest(method, params) {
console.log(`[DEBUG] fetchRpcRequest called with method: ${method}, params: ${JSON.stringify(params)}`); // Логируем вызов метода logger.debug({ method, params }, 'fetchRpcRequest called');
const results = []; const results = [];
for (const node of rpcNodes) { for (const node of rpcNodes) {
@@ -163,12 +164,12 @@ export default class WalletUtils {
if (response.data && response.data.result) { if (response.data && response.data.result) {
results.push(response.data.result); results.push(response.data.result);
console.log(`Запрос успешно выполнен на узле ${node}`); // Логируем успешный запрос logger.debug({ node }, 'Request successful');
} else { } else {
console.warn(`Некорректный ответ от узла ${node}`); // Логируем некорректный ответ logger.warn({ node }, 'Invalid response');
} }
} catch (error) { } catch (error) {
console.error(`Ошибка на узле ${node}: ${error.message}`); // Логируем ошибку logger.error({ err: error, node }, 'Node error');
} }
} }
@@ -178,68 +179,68 @@ export default class WalletUtils {
const uniqueResults = [...new Set(results)]; const uniqueResults = [...new Set(results)];
if (uniqueResults.length === 1) { if (uniqueResults.length === 1) {
console.log("Баланс совпадает на всех узлах:", uniqueResults[0]); // Логируем совпадение балансов logger.debug('Balance matches across all nodes');
return uniqueResults[0]; return uniqueResults[0];
} else { } else {
console.warn("Результаты отличаются на некоторых узлах. Возвращаем первый результат."); // Логируем различия logger.warn('Results differ across nodes. Returning first result.');
return results[0]; return results[0];
} }
} }
async getBtcBalance() { async getBtcBalance() {
if (!this.btcAddress) { if (!this.btcAddress) {
console.log('[DEBUG] BTC address is not provided, skipping balance check.'); // Логируем отсутствие адреса logger.debug('BTC address is not provided, skipping balance check');
return 0; return 0;
} }
try { try {
const url = `https://blockchain.info/balance?active=${this.btcAddress}`; const url = `https://blockchain.info/balance?active=${this.btcAddress}`;
console.log(`[DEBUG] Fetching BTC balance from: ${url}`); // Логируем URL запроса logger.debug({ url }, 'Fetching BTC balance');
const data = await this.fetchApiRequest(url); const data = await this.fetchApiRequest(url);
return data?.[this.btcAddress]?.final_balance / 100000000 || 0; return data?.[this.btcAddress]?.final_balance / 100000000 || 0;
} catch (error) { } catch (error) {
console.error('Error getting BTC balance:', error); logger.error({ err: error }, 'Error getting BTC balance');
return 0; return 0;
} }
} }
async getLtcBalance() { async getLtcBalance() {
if (!this.ltcAddress) { if (!this.ltcAddress) {
console.log('[DEBUG] LTC address is not provided, skipping balance check.'); // Логируем отсутствие адреса logger.debug('LTC address is not provided, skipping balance check');
return 0; return 0;
} }
try { try {
const url = `https://api.blockcypher.com/v1/ltc/main/addrs/${this.ltcAddress}/balance`; const url = `https://api.blockcypher.com/v1/ltc/main/addrs/${this.ltcAddress}/balance`;
console.log(`[DEBUG] Fetching LTC balance from: ${url}`); // Логируем URL запроса logger.debug({ url }, 'Fetching LTC balance');
const data = await this.fetchApiRequest(url); const data = await this.fetchApiRequest(url);
return data?.balance / 100000000 || 0; return data?.balance / 100000000 || 0;
} catch (error) { } catch (error) {
console.error('Error getting LTC balance:', error); logger.error({ err: error }, 'Error getting LTC balance');
return 0; return 0;
} }
} }
async getEthBalance() { async getEthBalance() {
if (!this.ethAddress) { if (!this.ethAddress) {
console.log('[DEBUG] ETH address is not provided, skipping balance check.'); // Логируем отсутствие адреса logger.debug('ETH address is not provided, skipping balance check');
return 0; return 0;
} }
try { try {
console.log(`[DEBUG] Fetching ETH balance for address: ${this.ethAddress}`); // Логируем адрес logger.debug({ addressPrefix: this.ethAddress.slice(0, 6) + '...' }, 'Fetching ETH balance');
const balanceHex = await this.fetchRpcRequest("eth_getBalance", [this.ethAddress, "latest"]); const balanceHex = await this.fetchRpcRequest("eth_getBalance", [this.ethAddress, "latest"]);
return parseInt(balanceHex, 16) / 1e18; return parseInt(balanceHex, 16) / 1e18;
} catch (error) { } catch (error) {
console.error('Error getting ETH balance:', error); logger.error({ err: error }, 'Error getting ETH balance');
return 0; return 0;
} }
} }
async getUsdtErc20Balance() { async getUsdtErc20Balance() {
if (!this.usdtAddress) { if (!this.usdtAddress) {
console.log('[DEBUG] USDT address is not provided, skipping balance check.'); // Логируем отсутствие адреса logger.debug('USDT address is not provided, skipping balance check');
return 0; return 0;
} }
try { try {
console.log(`[DEBUG] Fetching USDT ERC-20 balance for address: ${this.usdtAddress}`); // Логируем адрес logger.debug({ addressPrefix: this.usdtAddress.slice(0, 6) + '...' }, 'Fetching USDT ERC-20 balance');
const balanceHex = await this.fetchRpcRequest("eth_call", [ const balanceHex = await this.fetchRpcRequest("eth_call", [
{ {
to: "0xdac17f958d2ee523a2206206994597c13d831ec7", to: "0xdac17f958d2ee523a2206206994597c13d831ec7",
@@ -249,18 +250,18 @@ export default class WalletUtils {
]); ]);
return parseInt(balanceHex, 16) / 1e6; return parseInt(balanceHex, 16) / 1e6;
} catch (error) { } catch (error) {
console.error('Error getting USDT ERC-20 balance:', error); logger.error({ err: error }, 'Error getting USDT ERC-20 balance');
return 0; return 0;
} }
} }
async getUsdcErc20Balance() { async getUsdcErc20Balance() {
if (!this.usdcAddress) { if (!this.usdcAddress) {
console.log('[DEBUG] USDC address is not provided, skipping balance check.'); // Логируем отсутствие адреса logger.debug('USDC address is not provided, skipping balance check');
return 0; return 0;
} }
try { try {
console.log(`[DEBUG] Fetching USDC ERC-20 balance for address: ${this.usdcAddress}`); // Логируем адрес logger.debug({ addressPrefix: this.usdcAddress.slice(0, 6) + '...' }, 'Fetching USDC ERC-20 balance');
const balanceHex = await this.fetchRpcRequest("eth_call", [ const balanceHex = await this.fetchRpcRequest("eth_call", [
{ {
to: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", to: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
@@ -270,7 +271,7 @@ export default class WalletUtils {
]); ]);
return parseInt(balanceHex, 16) / 1e6; return parseInt(balanceHex, 16) / 1e6;
} catch (error) { } catch (error) {
console.error('Error getting USDC ERC-20 balance:', error); logger.error({ err: error }, 'Error getting USDC ERC-20 balance');
return 0; return 0;
} }
} }
@@ -310,7 +311,7 @@ export default class WalletUtils {
} }
async getAllBalancesExt() { async getAllBalancesExt() {
console.log('[DEBUG] getAllBalancesExt called'); // Логируем вызов метода logger.debug('getAllBalancesExt called');
const [ const [
btcBalance, btcBalance,
@@ -328,14 +329,7 @@ export default class WalletUtils {
WalletUtils.getCryptoPrices() WalletUtils.getCryptoPrices()
]); ]);
console.log('[DEBUG] Balances fetched:', { // Логируем полученные балансы logger.debug({ btcBalance, ltcBalance, ethBalance, usdtErc20Balance, usdcErc20Balance }, 'Balances fetched');
btcBalance,
ltcBalance,
ethBalance,
usdtErc20Balance,
usdcErc20Balance,
prices
});
return { return {
BTC: { amount: btcBalance, usdValue: btcBalance * prices.btc }, BTC: { amount: btcBalance, usdValue: btcBalance * prices.btc },