UNPKG

nano-mcp

Version:

NANO MCP (Nano Cryptocurrency) Server for AI Assistants - A JSON-RPC 2.0 API server for Nano cryptocurrency operations with QR code generation, local work generation and auto-receive pending blocks

165 lines (124 loc) 5.36 kB
/** * RPC Helper Utility * Provides a simple wrapper for making RPC calls to Nano nodes */ const https = require('https'); const http = require('http'); const { URL } = require('url'); /** * Make an RPC call to a Nano node * @param {string} rpcUrl - The RPC node URL * @param {Object} params - RPC call parameters (should include 'action') * @param {string|null} rpcKey - Optional RPC key for authenticated endpoints * @returns {Promise<Object>} The RPC response */ async function makeRPCCall(rpcUrl, params, rpcKey = null) { return new Promise((resolve, reject) => { try { const url = new URL(rpcUrl); const isHttps = url.protocol === 'https:'; const httpModule = isHttps ? https : http; // Build request body const requestBody = { ...params }; if (rpcKey) { requestBody.key = rpcKey; } const data = JSON.stringify(requestBody); console.log(`[RPC Helper] Making RPC call to ${rpcUrl}`); console.log(`[RPC Helper] Action: ${params.action}`); const options = { hostname: url.hostname, port: url.port || (isHttps ? 443 : 80), path: url.pathname || '/', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, timeout: 30000 // 30 second timeout }; const req = httpModule.request(options, (res) => { let responseData = ''; res.on('data', (chunk) => { responseData += chunk; }); res.on('end', () => { try { const jsonResponse = JSON.parse(responseData); if (jsonResponse.error) { console.error(`[RPC Helper] RPC Error: ${jsonResponse.error}`); reject(new Error(jsonResponse.error)); } else { console.log(`[RPC Helper] RPC call successful`); resolve(jsonResponse); } } catch (error) { console.error(`[RPC Helper] Failed to parse response: ${error.message}`); console.error(`[RPC Helper] Raw response: ${responseData}`); reject(new Error(`Failed to parse RPC response: ${error.message}`)); } }); }); req.on('error', (error) => { console.error(`[RPC Helper] Request error: ${error.message}`); reject(new Error(`RPC request failed: ${error.message}`)); }); req.on('timeout', () => { console.error(`[RPC Helper] Request timeout`); req.destroy(); reject(new Error('RPC request timeout')); }); req.write(data); req.end(); } catch (error) { console.error(`[RPC Helper] Error setting up RPC call: ${error.message}`); reject(error); } }); } /** * Make multiple RPC calls in parallel * @param {string} rpcUrl - The RPC node URL * @param {Array<Object>} callsParams - Array of RPC call parameters * @param {string|null} rpcKey - Optional RPC key * @returns {Promise<Array<Object>>} Array of RPC responses */ async function makeMultipleRPCCalls(rpcUrl, callsParams, rpcKey = null) { console.log(`[RPC Helper] Making ${callsParams.length} parallel RPC calls`); const promises = callsParams.map(params => makeRPCCall(rpcUrl, params, rpcKey) ); return Promise.all(promises); } /** * Make an RPC call with retry logic * @param {string} rpcUrl - The RPC node URL * @param {Object} params - RPC call parameters * @param {string|null} rpcKey - Optional RPC key * @param {number} maxRetries - Maximum number of retry attempts * @returns {Promise<Object>} The RPC response */ async function makeRPCCallWithRetry(rpcUrl, params, rpcKey = null, maxRetries = 3) { let lastError; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { console.log(`[RPC Helper] Attempt ${attempt}/${maxRetries}`); const result = await makeRPCCall(rpcUrl, params, rpcKey); return result; } catch (error) { lastError = error; console.error(`[RPC Helper] Attempt ${attempt} failed: ${error.message}`); if (attempt < maxRetries) { const delayMs = attempt * 1000; // Progressive delay: 1s, 2s, 3s console.log(`[RPC Helper] Retrying in ${delayMs}ms...`); await new Promise(resolve => setTimeout(resolve, delayMs)); } } } throw new Error(`RPC call failed after ${maxRetries} attempts: ${lastError.message}`); } module.exports = { makeRPCCall, makeMultipleRPCCalls, makeRPCCallWithRetry };