UNPKG

arweave-multihost

Version:

JavaScript/TypeScript Arweave SDK with multiple host support

124 lines (123 loc) 4.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; const arweave_1 = __importDefault(require("arweave")); ; ; const DEFAULT_HOSTS = [ { host: "arweave.net", protocol: "https", port: 443, }, { host: "gateway.amplify.host", protocol: "https", port: 443, }, { host: "arweave.dev", protocol: "https", port: 443, }, ]; const defaultArweaveConfig = { timeout: 10000, logging: false, onError: console.error, }; /** * Returns overrriden arweave instance * @param hosts - Array of hosts * @param config - Other configuration options * (timeout, logging, logger, onError callback) * @returns arweave instance */ function init(hosts, config = defaultArweaveConfig) { if (hosts.length === 0) { throw new Error("Multihost config should have at least one host"); } const arweave = arweave_1.default.init(Object.assign(Object.assign({}, hosts[0]), config)); let currentHostIndex = 0, lastFailedHost = 0; function updateHostParams(hostConfig) { arweave.api.config.host = hostConfig.host; arweave.api.config.port = hostConfig.port; arweave.api.config.protocol = hostConfig.protocol; } const originalApiRequestMethods = { get: arweave.api.get.bind(arweave.api), post: arweave.api.post.bind(arweave.api), }; function switchHost() { const oldHost = getCurrentHost(); currentHostIndex = (currentHostIndex + 1) % hosts.length; const newHost = hosts[currentHostIndex]; if (config.logging && config.logger !== undefined) { config.logger("Request failed. Switching host and retrying. " + `Old host: ${JSON.stringify(oldHost)}. ` + `New host: ${JSON.stringify(newHost)}.`); } updateHostParams(newHost); } function getCurrentHost() { return hosts[currentHostIndex]; } function isHostActive(host) { const currentHost = getCurrentHost(); return JSON.stringify(host) === JSON.stringify(currentHost); } async function overridenRequestMethod(sendOriginalRequest) { for (let i = 0; i < hosts.length; i++) { const hostUsedForRequest = getCurrentHost(); try { const response = await sendOriginalRequest(); if (response.status >= 500 && response.status < 600) { throw new Error("Error while sending http request: " + `Status: ${response.status}. ` + `Data: ${JSON.stringify(response.data)}`); } return response; } catch (err) { // config.onError callback may be used for error logging if (config.onError) { config.onError(err); } if (i === hosts.length - 1) { throw err; } else { // We switch host only if it's still active. // If it's not active it means that it was switched by // another concurrent request if (isHostActive(hostUsedForRequest)) { switchHost(); } } } } throw new Error("Should never reach this"); } arweave.api.get = async (endpoint, axiosConfig) => { return await overridenRequestMethod(() => originalApiRequestMethods.get(endpoint, axiosConfig)); }; arweave.api.post = async (endpoint, body, axiosConfig) => { return await overridenRequestMethod(() => originalApiRequestMethods.post(endpoint, body, axiosConfig)); }; return arweave; } /** * Returns overrriden arweave instance with default hosts * (arweave.net, gateway.amplify.host, arweave.dev) * @param config - Other configuration options * (timeout, logging, logger, onError callback) * @returns arweave instance */ function initWithDefaultHosts(config) { return init(DEFAULT_HOSTS, config); } module.exports = { init, initWithDefaultHosts, };