@rsksmart/rsk-cli
Version:
CLI tool for Rootstock network using Viem
218 lines (217 loc) ⢠10 kB
JavaScript
import { MonitorManager } from "../utils/monitoring/MonitorManager.js";
import chalk from "chalk";
import { isAddress } from "viem";
import Table from "cli-table3";
import ora from "ora";
function logMessage(params, message, color = chalk.white) {
if (!params.isExternal) {
console.log(color(message));
}
}
function logError(params, message) {
logMessage(params, `ā ${message}`, chalk.red);
}
function logSuccess(params, message) {
logMessage(params, message, chalk.green);
}
function logWarning(params, message) {
logMessage(params, message, chalk.yellow);
}
function logInfo(params, message) {
logMessage(params, message, chalk.blue);
}
function startSpinner(params, spinner, message) {
if (!params.isExternal) {
spinner.start(message);
}
}
function stopSpinner(params, spinner) {
if (!params.isExternal) {
spinner.stop();
}
}
function succeedSpinner(params, spinner, message) {
if (!params.isExternal) {
spinner.succeed(message);
}
}
export async function monitorCommand(options) {
try {
const spinner = options.isExternal ? ora({ isEnabled: false }) : ora();
startSpinner(options, spinner, 'ā³ Initializing monitor...');
const monitorManager = new MonitorManager(options.testnet);
await monitorManager.initialize();
succeedSpinner(options, spinner, 'ā
Monitor initialized successfully');
if (options.tx) {
return await handleTransactionMonitoring(options, monitorManager);
}
if (options.address) {
if (!isAddress(options.address)) {
logError(options, 'Invalid address format.');
logMessage(options, 'Expected: Valid Ethereum/Rootstock address (40 hex characters with 0x prefix)', chalk.gray);
logMessage(options, `Received: ${options.address} (length: ${String(options.address).length})`, chalk.gray);
return;
}
logInfo(options, `š Starting address monitoring...`);
logMessage(options, `Network: ${options.testnet ? 'Testnet' : 'Mainnet'}`, chalk.gray);
logMessage(options, `Address: ${options.address}`, chalk.gray);
logMessage(options, `Monitor balance: ${options.monitorBalance ? 'Yes' : 'No'}`, chalk.gray);
logMessage(options, `Monitor transactions: ${options.monitorTransactions ? 'Yes' : 'No'}`, chalk.gray);
logMessage(options, '');
startSpinner(options, spinner, 'ā³ Starting address monitoring...');
const sessionId = await monitorManager.startAddressMonitoring(options.address, options.monitorBalance ?? true, options.monitorTransactions ?? false, options.testnet);
succeedSpinner(options, spinner, 'ā
Address monitoring started successfully');
logSuccess(options, `\nšÆ Monitoring started successfully!`);
logInfo(options, `Press Ctrl+C to stop monitoring`);
logMessage(options, '');
process.on('SIGINT', async () => {
logWarning(options, `\nā¹ļø Stopping monitoring...`);
await monitorManager.stopMonitoring(sessionId);
process.exit(0);
});
setInterval(() => { }, 1000);
}
else {
const activeSessions = monitorManager.getActiveSessions();
if (activeSessions.length === 0) {
logWarning(options, `š No active monitoring sessions found.`);
logMessage(options, `Use --address <address> to start monitoring an address.`, chalk.gray);
return;
}
logInfo(options, `š Active Monitoring Sessions (${activeSessions.length})`);
logMessage(options, '');
const table = new Table({
head: ['Session ID', 'Type', 'Target', 'Status', 'Checks', 'Started'],
colWidths: [36, 12, 42, 10, 8, 20],
});
for (const session of activeSessions) {
const target = session.config.type === 'transaction'
? session.config.txHash.slice(0, 20) + '...'
: session.config.address;
table.push([
session.id.slice(0, 8) + '...',
session.config.type,
target,
session.isActive ? 'Active' : 'Stopped',
session.checkCount.toString(),
session.startTime.toLocaleTimeString()
]);
}
logMessage(options, table.toString());
}
}
catch (error) {
if (error.message?.includes('Invalid address format')) {
logError(options, 'Invalid address format provided.');
logMessage(options, 'Please provide a valid Ethereum/Rootstock address.', chalk.gray);
}
else if (error.message?.includes('Failed to initialize monitoring')) {
logError(options, 'Failed to connect to the network.');
logMessage(options, 'Please check your internet connection and try again.', chalk.gray);
}
else {
logError(options, `Error in monitoring: ${error.message || error}`);
}
}
}
async function handleTransactionMonitoring(options, monitorManager) {
if (!options.tx) {
logError(options, 'Transaction ID is required for transaction monitoring.');
return;
}
const confirmations = options.confirmations ?? 12;
logInfo(options, `š Starting transaction monitoring...`);
logMessage(options, `Network: ${options.testnet ? 'Testnet' : 'Mainnet'}`, chalk.gray);
logMessage(options, `Transaction: ${options.tx}`, chalk.gray);
logMessage(options, `Required confirmations: ${confirmations}`, chalk.gray);
logMessage(options, '');
const spinner = options.isExternal ? ora({ isEnabled: false }) : ora();
try {
startSpinner(options, spinner, 'ā³ Starting transaction monitoring...');
const sessionId = await monitorManager.startTransactionMonitoring(options.tx, confirmations, options.testnet);
succeedSpinner(options, spinner, 'ā
Transaction monitoring started successfully');
logSuccess(options, `\nšÆ Monitoring started successfully!`);
logInfo(options, `Press Ctrl+C to stop monitoring`);
logMessage(options, '');
process.on('SIGINT', async () => {
logWarning(options, `\nā¹ļø Stopping monitoring...`);
await monitorManager.stopMonitoring(sessionId);
process.exit(0);
});
setInterval(() => { }, 1000);
}
catch (error) {
stopSpinner(options, spinner);
logError(options, `Error in monitoring: ${error.message || error}`);
return;
}
}
export async function listMonitoringSessions(testnet, isExternal = false) {
try {
const options = { testnet, isExternal };
const spinner = isExternal ? ora({ isEnabled: false }) : ora();
startSpinner(options, spinner, 'ā³ Initializing monitor...');
const monitorManager = new MonitorManager(testnet);
await monitorManager.initialize();
succeedSpinner(options, spinner, 'ā
Monitor initialized successfully');
const activeSessions = monitorManager.getActiveSessions();
if (activeSessions.length === 0) {
logWarning(options, `š No active monitoring sessions found.`);
return;
}
logInfo(options, `š Active Monitoring Sessions (${activeSessions.length})`);
logMessage(options, '');
const table = new Table({
head: ['Session ID', 'Type', 'Target', 'Status', 'Checks', 'Started'],
colWidths: [36, 12, 42, 10, 8, 20],
});
for (const session of activeSessions) {
const target = session.config.type === 'transaction'
? session.config.txHash.slice(0, 20) + '...'
: session.config.address;
table.push([
session.id.slice(0, 8) + '...',
session.config.type,
target,
session.isActive ? 'Active' : 'Stopped',
session.checkCount.toString(),
session.startTime.toLocaleTimeString()
]);
}
logMessage(options, table.toString());
}
catch (error) {
const options = { testnet, isExternal };
logError(options, `Error listing sessions: ${error.message || error}`);
}
}
export async function stopMonitoringSession(sessionId, testnet, isExternal = false) {
try {
const options = { testnet, isExternal };
if (!sessionId || sessionId.length < 8) {
logError(options, 'Invalid session ID provided.');
logMessage(options, 'Please provide a valid session ID (at least 8 characters).', chalk.gray);
return;
}
const spinner = isExternal ? ora({ isEnabled: false }) : ora();
startSpinner(options, spinner, 'ā³ Initializing monitor...');
const monitorManager = new MonitorManager(testnet);
await monitorManager.initialize();
succeedSpinner(options, spinner, 'ā
Monitor initialized successfully');
startSpinner(options, spinner, 'ā³ Stopping monitoring session...');
const success = await monitorManager.stopMonitoring(sessionId);
if (success) {
succeedSpinner(options, spinner, 'ā
Monitoring session stopped successfully');
logSuccess(options, `Session ${sessionId} stopped successfully`);
}
else {
stopSpinner(options, spinner);
logError(options, `Failed to stop monitoring session: ${sessionId}`);
logMessage(options, 'Session not found or already stopped.', chalk.gray);
}
}
catch (error) {
const options = { testnet, isExternal };
logError(options, `Error stopping session: ${error.message || error}`);
}
}