UNPKG

@factorial-finance/blueprint-node

Version:

blueprint-node-plugin

156 lines (155 loc) 7.54 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HTTPServer = void 0; const http_1 = require("http"); const url_1 = require("url"); const test_wallets_1 = require("../constants/test-wallets"); const chalk_1 = __importDefault(require("chalk")); const logger_1 = require("../utils/logger"); class HTTPServer { constructor(jsonRPCServer, config) { this.jsonRPCServer = jsonRPCServer; this.port = config.port; this.host = config.host; this.server = (0, http_1.createServer)(this.handleRequest.bind(this)); this.setupErrorHandlers(); } setupErrorHandlers() { this.server.on('error', (error) => { logger_1.Logger.error('Server error:', error); }); // Graceful shutdown process.on('SIGTERM', () => { logger_1.Logger.info('Received SIGTERM, shutting down gracefully'); this.server.close(() => { logger_1.Logger.info('HTTP server closed'); process.exit(0); }); }); process.on('SIGINT', () => { logger_1.Logger.info('Received SIGINT, shutting down gracefully'); this.server.close(() => { logger_1.Logger.info('HTTP server closed'); process.exit(0); }); }); } async handleRequest(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] || 'Content-Type'); res.setHeader('Content-Type', 'application/json'); // Handle OPTIONS preflight request if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } const url = new url_1.URL(req.url || '', `http://${req.headers.host}`); // Only accept requests to /jsonRPC endpoint if (url.pathname !== '/jsonRPC') { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not Found' })); return; } // Only accept POST requests if (req.method !== 'POST') { res.writeHead(405, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Method Not Allowed' })); return; } // Read request body let body = ''; req.on('data', (chunk) => { body += chunk.toString(); }); req.on('end', async () => { try { const jsonRPCRequest = JSON.parse(body); const jsonRPCResponse = await this.jsonRPCServer.receive(jsonRPCRequest); if (jsonRPCResponse) { const tonApiResponse = jsonRPCResponse.error ? { ok: false, error: jsonRPCResponse.error } : { ok: true, result: jsonRPCResponse.result }; res.writeHead(200); res.end(JSON.stringify(tonApiResponse)); } else { res.writeHead(204); res.end(); } } catch (error) { logger_1.Logger.error('Error processing request:', error); res.writeHead(400); res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32700, message: 'Parse error' }, id: null })); } }); } start() { return new Promise((resolve) => { this.server.listen(this.port, this.host, () => { this.displayServerInfo(); resolve(); }); }); } displayServerInfo() { if (process.env.NODE_ENV !== 'test') { console.clear(); } logger_1.Logger.print(''); logger_1.Logger.print(chalk_1.default.green(`🚀 Started HTTP JSON-RPC server at http://${this.host}:${this.port}/jsonRPC`)); logger_1.Logger.print(''); logger_1.Logger.print(chalk_1.default.yellow('📋 Available API Methods:')); logger_1.Logger.print(chalk_1.default.cyan(' • sendBoc(boc) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • runGetMethod(address, method, stack) => GetMethodResult')); logger_1.Logger.print(chalk_1.default.cyan(' • getAddressInformation(address) => ContractState')); logger_1.Logger.print(chalk_1.default.cyan(' • getTransactions(address, limit, lt?, hash?) => Transaction[]')); logger_1.Logger.print(chalk_1.default.cyan(' • getTransaction(address, lt, hash) => Transaction')); logger_1.Logger.print(chalk_1.default.cyan(' • tryLocateResultTx(source, destination, created_lt) => Transaction')); logger_1.Logger.print(chalk_1.default.cyan(' • tryLocateSourceTx(source, destination, created_lt) => Transaction')); logger_1.Logger.print(''); logger_1.Logger.print(chalk_1.default.yellow('📋 Test API Methods:')); logger_1.Logger.print(chalk_1.default.cyan(' • setBalance(address, balance) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • increaseBalance(address, amount) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • setAccountCode(address, code) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • setAccountData(address, data) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • addLibrary(lib) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • setLibraries(libs) => { @type: "ok" }')); logger_1.Logger.print(chalk_1.default.cyan(' • getLibraries() => { cell }')); logger_1.Logger.print(''); logger_1.Logger.print(chalk_1.default.yellow('📋 Not Available API Methods:')); logger_1.Logger.print(chalk_1.default.gray(' • getMasterchainInfo() => MasterchainInfo')); logger_1.Logger.print(chalk_1.default.gray(' • getShards(seqno) => ShardInfo[]')); logger_1.Logger.print(chalk_1.default.gray(' • estimateFee(address, args) => FeeInfo')); logger_1.Logger.print(chalk_1.default.gray(' • getBlockTransactions(workchain, seqno, shard) => BlockTransactions')); logger_1.Logger.print(''); // Display wallet information logger_1.Logger.print(chalk_1.default.green('💰 Test V5R1 Wallets (10,000 TON each)')); logger_1.Logger.print(chalk_1.default.yellow('⚠️ WARNING: Public test wallets - never send real funds!')); logger_1.Logger.print(''); logger_1.Logger.print(chalk_1.default.white(`🔑 Mnemonic: ${test_wallets_1.testWallets.mnemonic}`)); logger_1.Logger.print(''); for (const wallet of test_wallets_1.testWallets.subWallets) { logger_1.Logger.print(chalk_1.default.white(`#${wallet.subwalletNumber}: ${wallet.address}`)); } logger_1.Logger.print(''); logger_1.Logger.logSeparator(); } close() { this.server.close(); } } exports.HTTPServer = HTTPServer;