@factorial-finance/blueprint-node
Version:
blueprint-node-plugin
156 lines (155 loc) • 7.54 kB
JavaScript
;
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;