UNPKG

@substrate/api-sidecar

Version:

REST service that makes it easy to interact with blockchain nodes built using Substrate's FRAME framework.

201 lines 8.53 kB
#!/usr/bin/env node "use strict"; // Copyright 2017-2025 Parity Technologies (UK) Ltd. // This file is part of Substrate API Sidecar. // // Substrate API Sidecar is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // Introduced via `@polkadot/api v7.0.1`. require("@polkadot/api-augment"); const express_1 = require("express"); const package_json_1 = __importDefault(require("../package.json")); const apiRegistry_1 = require("./apiRegistry"); const App_1 = __importDefault(require("./App")); const chains_config_1 = require("./chains-config"); const chains_config_2 = require("./chains-config"); const consoleOverride_1 = require("./logging/consoleOverride"); const Log_1 = require("./logging/Log"); const index_1 = require("./metrics/index"); const middleware = __importStar(require("./middleware")); const parseArgs_1 = require("./parseArgs"); const SidecarConfig_1 = require("./SidecarConfig"); /* * initApis function prepares the API registry and initializes the API * it returns the specName of the main API to be used by sidecar */ async function initApis() { const { config } = SidecarConfig_1.SidecarConfig; const { logger } = Log_1.Log; logger.info('Initializing APIs'); const requiredApis = [ { url: config.SUBSTRATE.URL }, ...config.SUBSTRATE.MULTI_CHAIN_URL.map((chain) => ({ url: chain.url, type: chain.type })), ].filter((apiOption) => !!apiOption.url); // Create the API registry const apis = await Promise.all(requiredApis.map((apiUrl) => apiRegistry_1.ApiPromiseRegistry.initApi(apiUrl.url, apiUrl.type || undefined))); for (const api of apis) { await api.isReady; } const specNames = []; let isAssetHub = false; let isAssetHubMigrated = false; for (let i = 0; i < apis.length; i++) { if (!apis[i]) { logger.error('Failed to create API instance'); } const api = apis[i]; // Gather some basic details about the node so we can display a nice message const [chainName, { implName, specName }] = await Promise.all([ api.rpc.system.chain(), api.rpc.state.getRuntimeVersion(), ]); // This is assuming that the first requiredApi will be SUBSTRATE.URL if (i === 0 && chains_config_2.assetHubSpecNames.has(specName.toString().toLowerCase())) { isAssetHub = true; let stage; if (api.query.ahMigrator) { stage = await api.query.ahMigrator.ahMigrationStage(); } if (stage && stage.isMigrationDone) { isAssetHubMigrated = true; } else if (api.query.staking && !api.query.ahMigrator) { // Asset Hub is migrated, and removed the ahMigrator pallet. isAssetHubMigrated = true; } apiRegistry_1.ApiPromiseRegistry.setAssetHubInfo({ isAssetHub, isAssetHubMigrated }); } startUpPrompt(requiredApis[i].url, chainName.toString(), implName.toString()); specNames.push(specName.toString()); } logger.info('All APIs initialized'); return specNames[0]; } async function main() { const { config } = SidecarConfig_1.SidecarConfig; const { logger } = Log_1.Log; // Overide console.{log, error, warn, etc} (0, consoleOverride_1.consoleOverride)(logger); logger.info(`Version: ${package_json_1.default.version}`); const preMiddlewares = [(0, express_1.json)({ limit: config.EXPRESS.MAX_BODY }), middleware.httpLoggerCreate(logger)]; if (config.METRICS.ENABLED) { // Create Metrics App const metricsApp = new index_1.MetricsApp({ port: config.METRICS.PROM_PORT, host: config.METRICS.PROM_HOST, }); // Generate metrics middleware preMiddlewares.push(metricsApp.preMiddleware()); // Start the Metrics server metricsApp.listen(); } const specNames = await initApis(); const pallets = []; if (config.EXPRESS.INJECTED_CONTROLLERS) { // Get the pallets from the API const api = apiRegistry_1.ApiPromiseRegistry.getApi(specNames); if (api) { const chainPallets = api.registry.metadata.toJSON().pallets.map((p) => p.name); pallets.push(...chainPallets); } } const app = new App_1.default({ preMiddleware: preMiddlewares, controllers: (0, chains_config_1.getControllers)(config, specNames, pallets), postMiddleware: [ middleware.txError, middleware.httpError, middleware.error, middleware.legacyError, middleware.internalError, ], port: config.EXPRESS.PORT, host: config.EXPRESS.HOST, }); // Start the server const server = app.listen(); server.keepAliveTimeout = config.EXPRESS.KEEP_ALIVE_TIMEOUT; server.headersTimeout = config.EXPRESS.KEEP_ALIVE_TIMEOUT + 5000; } /** * Prompt the user with some basic info about the node and the network they have * connected Sidecar to. * * @param url Url of the node Sidecar is connected to, can be a websocket or http address * @param chainName chain name of the network Sidecar is connected to * @param implName implementation name of the node Sidecar is connected to */ function startUpPrompt(url, chainName, implName) { const { logger } = Log_1.Log; logger.info(`Connected to chain ${chainName} on the ${implName} client at ${url}`); // Split the Url to check for 2 things. Secure connection, and if its a local IP. const splitUrl = url.split(':'); // If its 'ws' its not a secure connection. const isSecure = splitUrl[0] === 'wss' || splitUrl[0] === 'https'; // Check if its a local IP. const isLocal = splitUrl[1] === '//127.0.0.1' || splitUrl[1] === '//localhost'; if (!isSecure && !isLocal) { logger.warn(`Using unencrypted connection to a public node (${url}); All traffic is sent over the internet in cleartext.`); } } process.on('SIGINT', function () { console.log('Caught interrupt signal, exiting...'); // TODO: disconnnect all APIs process.exit(0); }); const args = (0, parseArgs_1.parseArgs)(); if (args.version) { console.log(`@substrate/api-sidecar v${package_json_1.default.version}`); process.exit(0); } else { main().catch(console.log); } //# sourceMappingURL=main.js.map