Files
peya-nodejs-pool/lib/telegramBot.js
2020-02-10 15:49:40 -05:00

361 lines
13 KiB
JavaScript

/**
* Cryptonote Node.JS Pool
* https://github.com/dvandal/cryptonote-nodejs-pool
*
* Telegram bot
*
* Author: Daniel Vandal
**/
// Load required modules
process.env.NTBA_FIX_319 = 1;
let TelegramBot = require('node-telegram-bot-api');
let timeAgo = require('time-ago');
let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api);
let notifications = require('./notifications.js');
let utils = require('./utils.js');
// Initialize log system
let logSystem = 'telegramBot';
require('./exceptionWriter.js')(logSystem);
/**
* Check telegram configuration
**/
// Check bot settings
if (!config.telegram) {
log('error', logSystem, 'Telegram is not enabled');
} else if (!config.telegram.enabled) {
log('error', logSystem, 'Telegram is not enabled');
} else if (!config.telegram.token) {
log('error', logSystem, 'No telegram token found in configuration');
}
// Bot commands
let botCommands = {
stats: "/stats",
report: "/report",
notify: "/notify",
blocks: "/blocks"
}
if (config.telegram.botCommands) {
Object.assign(botCommands, config.telegram.botCommands);
}
// Telegram channel
let channel = config.telegram.channel.replace(/@/g, '') || '';
// Periodical channel statistics
let periodicalStats = (channel && config.telegram.channelStats && config.telegram.channelStats.enabled)
let statsInterval = (config.telegram.channelStats && config.telegram.channelStats.interval > 0) ? parseInt(config.telegram.channelStats.interval) : 0;
/**
* Initialize new telegram bot
**/
log('info', logSystem, 'Started');
let token = config.telegram.token;
let bot = new TelegramBot(token, {
polling: true
});
/**
* Periodical pool statistics
**/
if (periodicalStats && statsInterval > 0 && channel) {
log('info', logSystem, 'Sending pool statistics to telegram channel @%s each %d minutes', [channel, statsInterval]);
setInterval(function () {
sendPoolStats('@' + channel);
}, (statsInterval * 60) * 1000);
}
/**
* Handle "/start" or "/help"
**/
bot.onText(new RegExp('^/(start|help)$', 'i'), (telegramMsg) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
log('info', logSystem, 'Commands list request from @%s (%s)', [telegramMsg.from.username, telegramMsg.from.id]);
let message = 'Hi @' + telegramMsg.from.username + ',\n\n' +
'Here are the commands you can use:\n\n' +
'Pool statistics: ' + botCommands['stats'] + '\n' +
'Blocks notifications: ' + botCommands['blocks'] + '\n' +
'Miner statistics: ' + botCommands['report'] + ' _address_\n' +
'Miner notifications: ' + botCommands['notify'] + ' _address_\n\n' +
'Thank you!';
bot.sendMessage(telegramMsg.from.id, message, {
parse_mode: 'Markdown'
});
});
/**
* Pool Statistics
**/
bot.onText(new RegExp('^' + botCommands['stats'] + '$', 'i'), (telegramMsg) => {
log('info', logSystem, 'Pool statistics request from @%s (%s)', [telegramMsg.from.username, telegramMsg.from.id]);
sendPoolStats(telegramMsg.chat.id);
});
function sendPoolStats (chatId) {
apiInterfaces.pool('/stats', function (error, stats) {
if (error || !stats) {
log('error', logSystem, 'Unable to get API data for stats: ' + error);
return bot.sendMessage(id, 'Unable to get pool statistics. Please retry.');
}
let poolHost = config.poolHost || "Pool";
let poolHashrate = utils.getReadableHashRate(stats.pool.hashrate);
let poolMiners = stats.pool.miners || 0;
let poolWorkers = stats.pool.workers || 0;
let poolBlocks = stats.pool.totalBlocks || 0;
let poolLastBlock = (stats.pool.lastBlockFound) ? timeAgo.ago(new Date(parseInt(stats.pool.lastBlockFound))) : 'Never';
let networkHashrate = utils.getReadableHashRate(stats.network.difficulty / stats.config.coinDifficultyTarget);
let networkDiff = stats.network.difficulty || 'N/A';
let networkHeight = stats.network.height || 'N/A';
let networkLastReward = utils.getReadableCoins(stats.lastblock.reward);
let networkLastBlock = (stats.lastblock.timestamp) ? timeAgo.ago(new Date(parseInt(stats.lastblock.timestamp * 1000))) : 'Never';
let currentEffort = stats.pool.roundHashes ? (stats.pool.roundHashes / stats.network.difficulty * 100)
.toFixed(1) + '%' : '0%';
let response = '';
response += '*' + poolHost + '*\n';
response += 'Hashrate: ' + poolHashrate + '\n';
response += 'Connected Miners: ' + poolMiners + '\n';
response += 'Active Workers: ' + poolWorkers + '\n';
response += 'Blocks Found: ' + poolBlocks + '\n';
response += 'Last Block: ' + poolLastBlock + '\n';
response += 'Current Effort: ' + currentEffort + '\n';
response += '\n';
response += '*Network*\n';
response += 'Hashrate: ' + networkHashrate + '\n';
response += 'Difficulty: ' + networkDiff + '\n';
response += 'Block Height: ' + networkHeight + '\n';
response += 'Block Found: ' + networkLastBlock + '\n';
response += 'Last Reward: ' + networkLastReward;
return bot.sendMessage(chatId, response, {
parse_mode: 'Markdown'
});
});
}
/**
* Miner Statistics
**/
bot.onText(new RegExp('^' + botCommands['report'] + '$', 'i'), (telegramMsg) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
let apiRequest = '/get_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=default';
apiInterfaces.pool(apiRequest, function (error, response) {
if (response.address) {
sendMinerStats(telegramMsg, response.address);
} else {
let message = 'To display miner report you need to specify the miner address on first request';
bot.sendMessage(telegramMsg.from.id, message, {
parse_mode: 'Markdown'
});
}
});
});
bot.onText(new RegExp('^' + botCommands['report'] + ' (.*)$', 'i'), (telegramMsg, match) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
let address = (match && match[1]) ? match[1].trim() : '';
if (!address || address == '') {
return bot.sendMessage(telegramMsg.from.id, 'No address specified!');
}
sendMinerStats(telegramMsg, address);
});
function sendMinerStats (telegramMsg, address) {
log('info', logSystem, 'Miner report request from @%s (%s) for address: %s', [telegramMsg.from.username, telegramMsg.from.id, address]);
apiInterfaces.pool('/stats_address?address=' + address, function (error, data) {
if (error || !data) {
log('error', logSystem, 'Unable to get API data for miner stats: ' + error);
return bot.sendMessage(telegramMsg.from.id, 'Unable to get miner statistics. Please retry.');
}
if (!data.stats) {
return bot.sendMessage(telegramMsg.from.id, 'No miner statistics found for that address. Please check the address and try again.');
}
let minerHashrate = utils.getReadableHashRate(data.stats.hashrate);
let minerBalance = utils.getReadableCoins(data.stats.balance);
let minerPaid = utils.getReadableCoins(data.stats.paid);
let minerLastShare = timeAgo.ago(new Date(parseInt(data.stats.lastShare * 1000)));
let response = '*Report for ' + address.substring(0, 7) + '...' + address.substring(address.length - 7) + '*\n';
response += 'Hashrate: ' + minerHashrate + '\n';
response += 'Last share: ' + minerLastShare + '\n';
response += 'Balance: ' + minerBalance + '\n';
response += 'Paid: ' + minerPaid + '\n';
if (data.workers && data.workers.length > 0) {
let f = true;
for (let i in data.workers) {
if (!data.workers[i] || !data.workers[i].hashrate || data.workers[i].hashrate === 0) continue;
if (f) {
response += '\n';
response += '*Active Workers*\n';
}
let workerName = data.workers[i].name;
let workerHashrate = utils.getReadableHashRate(data.workers[i].hashrate);
response += workerName + ': ' + workerHashrate + '\n';
f = false;
}
}
bot.sendMessage(telegramMsg.from.id, response, {
parse_mode: 'Markdown'
});
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=default&address=' + address;
apiInterfaces.pool(apiRequest, function (error, response) {});
});
}
/**
* Miner notifications
**/
bot.onText(new RegExp('^' + botCommands['notify'] + '$', 'i'), (telegramMsg) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
let apiRequest = '/get_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=default';
apiInterfaces.pool(apiRequest, function (error, response) {
if (response.address) {
toggleMinerNotifications(telegramMsg, response.address);
} else {
let message = 'To enable or disable notifications you need to specify the miner address on first request';
bot.sendMessage(telegramMsg.from.id, message, {
parse_mode: 'Markdown'
});
}
});
});
bot.onText(new RegExp('^' + botCommands['notify'] + ' (.*)$', 'i'), (telegramMsg, match) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
let address = (match && match[1]) ? match[1].trim() : '';
if (!address || address == '') {
return bot.sendMessage(telegramMsg.from.id, 'No address specified!');
}
toggleMinerNotifications(telegramMsg, address);
});
function toggleMinerNotifications (telegramMsg, address) {
let apiRequest = '/get_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=miner&address=' + address;
apiInterfaces.pool(apiRequest, function (error, response) {
if (response.chatId && response.chatId == telegramMsg.from.id) {
disableMinerNotifications(telegramMsg, address);
} else {
enableMinerNotifications(telegramMsg, address);
}
});
}
function enableMinerNotifications (telegramMsg, address) {
log('info', logSystem, 'Enable miner notifications to @%s (%s) for address: %s', [telegramMsg.from.username, telegramMsg.from.id, address]);
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=miner&address=' + address + '&action=enable';
apiInterfaces.pool(apiRequest, function (error, response) {
if (error) {
log('error', logSystem, 'Unable to enable telegram notifications: ' + error);
return bot.sendMessage(telegramMsg.from.id, 'An error occurred. Please retry.');
}
if (response.status != 'done') {
return bot.sendMessage(telegramMsg.from.id, response.status);
}
bot.sendMessage(telegramMsg.from.id, 'Miner notifications enabled for ' + address.substring(0, 7) + '...' + address.substring(address.length - 7));
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=default&address=' + address;
apiInterfaces.pool(apiRequest, function (error, response) {});
});
}
function disableMinerNotifications (telegramMsg, address) {
log('info', logSystem, 'Disable miner notifications to @%s (%s) for address: %s', [telegramMsg.from.username, telegramMsg.from.id, address]);
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=miner&address=' + address + '&action=disable';
apiInterfaces.pool(apiRequest, function (error, response) {
if (error) {
log('error', logSystem, 'Unable to disable telegram notifications: ' + error);
return bot.sendMessage(telegramMsg.from.id, 'An error occurred. Please retry.');
}
if (response.status != 'done') {
return bot.sendMessage(telegramMsg.from.id, response.status);
}
bot.sendMessage(telegramMsg.from.id, 'Miner notifications disabled for ' + address.substring(0, 7) + '...' + address.substring(address.length - 7));
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=default&address=' + address;
apiInterfaces.pool(apiRequest, function (error, response) {});
});
}
/**
* Blocks notifications
**/
bot.onText(new RegExp('^' + botCommands['blocks'] + '$', 'i'), (telegramMsg) => {
if (telegramMsg.from.id != telegramMsg.chat.id) return;
toggleBlocksNotifications(telegramMsg);
});
function toggleBlocksNotifications (telegramMsg) {
let apiRequest = '/get_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=blocks';
apiInterfaces.pool(apiRequest, function (error, response) {
if (error) {
return bot.sendMessage(telegramMsg.from.id, 'An error occurred. Please retry.');
}
if (response.enabled) {
disableBlocksNotifications(telegramMsg);
} else {
enableBlocksNotifications(telegramMsg);
}
});
}
function enableBlocksNotifications (telegramMsg) {
log('info', logSystem, 'Enable blocks notifications to @%s (%s)', [telegramMsg.from.username, telegramMsg.from.id]);
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=blocks&action=enable';
apiInterfaces.pool(apiRequest, function (error, response) {
if (error) {
log('error', logSystem, 'Unable to enable telegram notifications: ' + error);
return bot.sendMessage(telegramMsg.from.id, 'An error occurred. Please retry.');
}
if (response.status != 'done') {
return bot.sendMessage(telegramMsg.from.id, response.status);
}
return bot.sendMessage(telegramMsg.from.id, 'Blocks notifications enabled');
});
}
function disableBlocksNotifications (telegramMsg) {
log('info', logSystem, 'Disable blocks notifications to @%s (%s)', [telegramMsg.from.username, telegramMsg.from.id]);
let apiRequest = '/set_telegram_notifications?chatId=' + telegramMsg.from.id + '&type=blocks&action=disable';
apiInterfaces.pool(apiRequest, function (error, response) {
if (error) {
log('error', logSystem, 'Unable to disable telegram notifications: ' + error);
return bot.sendMessage(telegramMsg.from.id, 'An error occurred. Please retry.');
}
if (response.status != 'done') {
return bot.sendMessage(telegramMsg.from.id, response.status);
}
return bot.sendMessage(telegramMsg.from.id, 'Blocks notifications disabled');
});
}