PHP WebShell

Текущая директория: /opt/BitGoJS/node_modules/@polkadot/rpc-provider/substrate-connect

Просмотр файла: Health.js

import { stringify } from '@polkadot/util';
/*
 * Creates a new health checker.
 *
 * The role of the health checker is to report to the user the health of a smoldot chain.
 *
 * In order to use it, start by creating a health checker, and call `setSendJsonRpc` to set the
 * way to send a JSON-RPC request to a chain. The health checker is disabled by default. Use
 * `start()` in order to start the health checks. The `start()` function must be passed a callback called
 * when an update to the health of the node is available.
 *
 * In order to send a JSON-RPC request to the chain, you **must** use the `sendJsonRpc` function
 * of the health checker. The health checker rewrites the `id` of the requests it receives.
 *
 * When the chain send a JSON-RPC response, it must be passed to `responsePassThrough()`. This
 * function intercepts the responses destined to the requests that have been emitted by the health
 * checker and returns `null`. If the response doesn't concern the health checker, the response is
 * simply returned by the function.
 *
 * # How it works
 *
 * The health checker periodically calls the `system_health` JSON-RPC call in order to determine
 * the health of the chain.
 *
 * In addition to this, as long as the health check reports that `isSyncing` is `true`, the
 * health checker also maintains a subscription to new best blocks using `chain_subscribeNewHeads`.
 * Whenever a new block is notified, a health check is performed immediately in order to determine
 * whether `isSyncing` has changed to `false`.
 *
 * Thanks to this subscription, the latency of the report of the switch from `isSyncing: true` to
 * `isSyncing: false` is very low.
 *
 */
export function healthChecker() {
    // `null` if health checker is not started.
    let checker = null;
    let sendJsonRpc = null;
    return {
        responsePassThrough: (jsonRpcResponse) => {
            if (checker === null) {
                return jsonRpcResponse;
            }
            return checker.responsePassThrough(jsonRpcResponse);
        },
        sendJsonRpc: (request) => {
            if (!sendJsonRpc) {
                throw new Error('setSendJsonRpc must be called before sending requests');
            }
            if (checker === null) {
                sendJsonRpc(request);
            }
            else {
                checker.sendJsonRpc(request);
            }
        },
        setSendJsonRpc: (cb) => {
            sendJsonRpc = cb;
        },
        start: (healthCallback) => {
            if (checker !== null) {
                throw new Error("Can't start the health checker multiple times in parallel");
            }
            else if (!sendJsonRpc) {
                throw new Error('setSendJsonRpc must be called before starting the health checks');
            }
            checker = new InnerChecker(healthCallback, sendJsonRpc);
            checker.update(true);
        },
        stop: () => {
            if (checker === null) {
                return;
            } // Already stopped.
            checker.destroy();
            checker = null;
        }
    };
}
class InnerChecker {
    __internal__healthCallback;
    __internal__currentHealthCheckId = null;
    __internal__currentHealthTimeout = null;
    __internal__currentSubunsubRequestId = null;
    __internal__currentSubscriptionId = null;
    __internal__requestToSmoldot;
    __internal__isSyncing = false;
    __internal__nextRequestId = 0;
    constructor(healthCallback, requestToSmoldot) {
        this.__internal__healthCallback = healthCallback;
        this.__internal__requestToSmoldot = (request) => requestToSmoldot(stringify(request));
    }
    sendJsonRpc = (request) => {
        // Replace the `id` in the request to prefix the request ID with `extern:`.
        let parsedRequest;
        try {
            parsedRequest = JSON.parse(request);
        }
        catch {
            return;
        }
        if (parsedRequest.id) {
            const newId = 'extern:' + stringify(parsedRequest.id);
            parsedRequest.id = newId;
        }
        this.__internal__requestToSmoldot(parsedRequest);
    };
    responsePassThrough = (jsonRpcResponse) => {
        let parsedResponse;
        try {
            parsedResponse = JSON.parse(jsonRpcResponse);
        }
        catch {
            return jsonRpcResponse;
        }
        // Check whether response is a response to `system_health`.
        if (parsedResponse.id && this.__internal__currentHealthCheckId === parsedResponse.id) {
            this.__internal__currentHealthCheckId = null;
            // Check whether query was successful. It is possible for queries to fail for
            // various reasons, such as the client being overloaded.
            if (!parsedResponse.result) {
                this.update(false);
                return null;
            }
            this.__internal__healthCallback(parsedResponse.result);
            this.__internal__isSyncing = parsedResponse.result.isSyncing;
            this.update(false);
            return null;
        }
        // Check whether response is a response to the subscription or unsubscription.
        if (parsedResponse.id &&
            this.__internal__currentSubunsubRequestId === parsedResponse.id) {
            this.__internal__currentSubunsubRequestId = null;
            // Check whether query was successful. It is possible for queries to fail for
            // various reasons, such as the client being overloaded.
            if (!parsedResponse.result) {
                this.update(false);
                return null;
            }
            if (this.__internal__currentSubscriptionId) {
                this.__internal__currentSubscriptionId = null;
            }
            else {
                this.__internal__currentSubscriptionId = parsedResponse.result;
            }
            this.update(false);
            return null;
        }
        // Check whether response is a notification to a subscription.
        if (parsedResponse.params &&
            this.__internal__currentSubscriptionId &&
            parsedResponse.params.subscription === this.__internal__currentSubscriptionId) {
            // Note that after a successful subscription, a notification containing
            // the current best block is always returned. Considering that a
            // subscription is performed in response to a health check, calling
            // `startHealthCheck()` here will lead to a second health check.
            // It might seem redundant to perform two health checks in a quick
            // succession, but doing so doesn't lead to any problem, and it is
            // actually possible for the health to have changed in between as the
            // current best block might have been updated during the subscription
            // request.
            this.update(true);
            return null;
        }
        // Response doesn't concern us.
        if (parsedResponse.id) {
            const id = parsedResponse.id;
            // Need to remove the `extern:` prefix.
            if (!id.startsWith('extern:')) {
                throw new Error('State inconsistency in health checker');
            }
            const newId = JSON.parse(id.slice('extern:'.length));
            parsedResponse.id = newId;
        }
        return stringify(parsedResponse);
    };
    update = (startNow) => {
        // If `startNow`, clear `#currentHealthTimeout` so that it is set below.
        if (startNow && this.__internal__currentHealthTimeout) {
            clearTimeout(this.__internal__currentHealthTimeout);
            this.__internal__currentHealthTimeout = null;
        }
        if (!this.__internal__currentHealthTimeout) {
            const startHealthRequest = () => {
                this.__internal__currentHealthTimeout = null;
                // No matter what, don't start a health request if there is already one in progress.
                // This is sane to do because receiving a response to a health request calls `update()`.
                if (this.__internal__currentHealthCheckId) {
                    return;
                }
                // Actual request starting.
                this.__internal__currentHealthCheckId = `health-checker:${this.__internal__nextRequestId}`;
                this.__internal__nextRequestId += 1;
                this.__internal__requestToSmoldot({
                    id: this.__internal__currentHealthCheckId,
                    jsonrpc: '2.0',
                    method: 'system_health',
                    params: []
                });
            };
            if (startNow) {
                startHealthRequest();
            }
            else {
                this.__internal__currentHealthTimeout = setTimeout(startHealthRequest, 1000);
            }
        }
        if (this.__internal__isSyncing &&
            !this.__internal__currentSubscriptionId &&
            !this.__internal__currentSubunsubRequestId) {
            this.startSubscription();
        }
        if (!this.__internal__isSyncing &&
            this.__internal__currentSubscriptionId &&
            !this.__internal__currentSubunsubRequestId) {
            this.endSubscription();
        }
    };
    startSubscription = () => {
        if (this.__internal__currentSubunsubRequestId || this.__internal__currentSubscriptionId) {
            throw new Error('Internal error in health checker');
        }
        this.__internal__currentSubunsubRequestId = `health-checker:${this.__internal__nextRequestId}`;
        this.__internal__nextRequestId += 1;
        this.__internal__requestToSmoldot({
            id: this.__internal__currentSubunsubRequestId,
            jsonrpc: '2.0',
            method: 'chain_subscribeNewHeads',
            params: []
        });
    };
    endSubscription = () => {
        if (this.__internal__currentSubunsubRequestId || !this.__internal__currentSubscriptionId) {
            throw new Error('Internal error in health checker');
        }
        this.__internal__currentSubunsubRequestId = `health-checker:${this.__internal__nextRequestId}`;
        this.__internal__nextRequestId += 1;
        this.__internal__requestToSmoldot({
            id: this.__internal__currentSubunsubRequestId,
            jsonrpc: '2.0',
            method: 'chain_unsubscribeNewHeads',
            params: [this.__internal__currentSubscriptionId]
        });
    };
    destroy = () => {
        if (this.__internal__currentHealthTimeout) {
            clearTimeout(this.__internal__currentHealthTimeout);
            this.__internal__currentHealthTimeout = null;
        }
    };
}
export class HealthCheckError extends Error {
    __internal__cause;
    getCause() {
        return this.__internal__cause;
    }
    constructor(response, message = 'Got error response asking for system health') {
        super(message);
        this.__internal__cause = response;
    }
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!