Home Reference Source Test

src/main/generic/api/NetworkClient.js

/** @class Client.Network */
Client.Network = class Network {
    /**
     * @param {Client} client
     * @package
     */
    constructor(client) {
        this._client = client;
    }

    /**
     * @returns {Promise.<Array.<Client.PeerInfo>>} List of peers currently connected to this node.
     */
    async getPeers() {
        const consensus = await this._client._consensus;
        const infos = [];
        for (const connection of consensus.network.connections.valueIterator()) {
            infos.push(new Client.PeerInfo(connection));
        }
        return infos;
    }

    /**
     * @param {PeerAddress|Client.AddressInfo|string} address
     * @returns {Promise.<?Client.PeerInfo>}
     */
    async getPeer(address) {
        const consensus = await this._client._consensus;
        const connection = consensus.network.connections.getConnectionByPeerAddress(await this._toPeerAddress(address));
        if (connection) {
            return new Client.PeerInfo(connection);
        }
        return null;
    }

    /**
     * @returns {Promise.<Array.<Client.AddressInfo>>} List of addresses known to this node.
     */
    async getAddresses() {
        const consensus = await this._client._consensus;
        const infos = [];
        for (const addressState of consensus.network.addresses.iterator()) {
            infos.push(new Client.AddressInfo(addressState));
        }
        return infos;
    }

    /**
     * @param {PeerAddress|Client.AddressInfo|string} address
     * @returns {Promise.<?Client.AddressInfo>}
     */
    async getAddress(address) {
        const consensus = await this._client._consensus;
        const addressState = consensus.network.addresses.getState(await this._toPeerAddress(address));
        if (addressState) {
            return new Client.AddressInfo(addressState);
        }
        return null;
    }

    /**
     * @returns {Promise.<Client.BasicAddress>}
     */
    async getOwnAddress() {
        const consensus = await this._client._consensus;
        return new Client.BasicAddress(consensus.network.config.peerAddress);
    }

    /**
     * @returns {Promise.<Client.NetworkStatistics>} Statistics on the network
     */
    async getStatistics() {
        const consensus = await this._client._consensus;
        return new Client.NetworkStatistics(consensus.network);
    }

    /**
     * @param {PeerAddress|Client.BasicAddress|string} address
     * @returns {Promise.<void>}
     */
    async connect(address) {
        const consensus = await this._client._consensus;
        consensus.network.connections.connectOutbound(await this._toPeerAddress(address));
    }

    /**
     * @param {PeerAddress|Client.BasicAddress|string} address
     * @returns {Promise.<void>}
     */
    async disconnect(address) {
        const consensus = await this._client._consensus;
        const connection = consensus.network.connections.getConnectionByPeerAddress(await this._toPeerAddress(address));
        if (connection) {
            connection.peerChannel.close(CloseType.MANUAL_PEER_DISCONNECT);
        }
    }

    /**
     * @param {PeerAddress|Client.BasicAddress|string} address
     * @returns {Promise.<void>}
     */
    async ban(address) {
        const consensus = await this._client._consensus;
        const peerAddress = await this._toPeerAddress(address);
        const connection = consensus.network.connections.getConnectionByPeerAddress(peerAddress);
        if (connection) {
            connection.peerChannel.close(CloseType.MANUAL_PEER_BAN);
        } else {
            const state = consensus.network.addresses.getState(peerAddress);
            state.state = PeerAddressState.BANNED;
        }
    }

    async unban(address) {
        const consensus = await this._client._consensus;
        const state = consensus.network.addresses.getState(await this._toPeerAddress(address));
        state.state = PeerAddressState.TRIED;
    }

    /**
     * @param {PeerAddress|Client.BasicAddress|string} address
     * @returns {Promise.<PeerAddress>}
     */
    async _toPeerAddress(address) {
        const consensus = await this._client._consensus;
        let peerAddress;
        if (address instanceof PeerAddress) {
            peerAddress = consensus.network.addresses.get(address);
        } else if (address instanceof Client.BasicAddress) {
            peerAddress = consensus.network.addresses.get(address.peerAddress);
        } else if (typeof address === 'string') {
            for (const peerAddressState of consensus.network.addresses.iterator()) {
                if (peerAddressState.peerAddress.toString() === address) {
                    peerAddress = peerAddressState.peerAddress;
                    break;
                }
            }
        }
        if (!peerAddress) throw new Error('Invalid or unknown peer address');
        return peerAddress;
    }
};

/** @class Client.BasicAddress */
Client.BasicAddress = class BasicAddress {
    /**
     * @param {PeerAddress} address
     */
    constructor(address) {
        this._address = address;
    }

    /** @type {PeerAddress} */
    get peerAddress() {
        return this._address;
    }

    /** @type {PeerId} */
    get peerId() {
        return this._address.peerId;
    }

    /** @type {Array.<String>} */
    get services() {
        return Services.toNameArray(Services.legacyProvideToCurrent(this._address.services));
    }

    /** @type {object} */
    toPlain() {
        return {
            peerAddress: this.peerAddress.toString(),
            peerId: this.peerId.toString(),
            services: this.services
        };
    }
};

/** @class Client.AddressInfo */
Client.AddressInfo = class AddressInfo extends Client.BasicAddress {
    /**
     * @param {PeerAddressState} addressState
     */
    constructor(addressState) {
        super(addressState.peerAddress);
        this._state = addressState.state;
    }

    /** @type {boolean} */
    get banned() {
        return this._state === PeerAddressState.BANNED;
    }

    /** @type {boolean} */
    get connected() {
        return this._state === PeerAddressState.ESTABLISHED;
    }

    /** @type {number} */
    get state() {
        return this._state;
    }

    /** @type {object} */
    toPlain() {
        const plain = super.toPlain();
        plain.banned = this.banned;
        plain.connected = this.connected;
        return plain;
    }
};

/** @class Client.PeerInfo */
Client.PeerInfo = class PeerInfo extends Client.BasicAddress {
    /**
     * @param {PeerConnection} connection
     */
    constructor(connection) {
        super(connection.peerAddress);
        this._connection = connection;
        const networkConnection = this._connection.networkConnection;
        const peer = this._connection.peer;
        this._bytesReceived = networkConnection ? networkConnection.bytesReceived : 0;
        this._bytesSent = networkConnection ? networkConnection.bytesSent : 0;
        this._latency = this._connection.statistics.latencyMedian;
        this._state = this._connection.state;
        this._version = peer ? peer.version : undefined;
        this._timeOffset = peer ? peer.timeOffset : undefined;
        this._headHash = peer ? peer.headHash : undefined;
        this._userAgent = peer ? peer.userAgent : undefined;
    }

    /** @type {number} */
    get connectionSince() {
        return this._connection.establishedSince;
    }

    /** @type {NetAddress} */
    get netAddress() {
        return this._connection.networkConnection.netAddress;
    }

    /** @type {number} */
    get bytesReceived() {
        return this._bytesReceived;
    }

    /** @type {number} */
    get bytesSent() {
        return this._bytesSent;
    }

    /** @type {number} */
    get latency() {
        return this._latency;
    }

    /** @type {number} */
    get version() {
        return this._version;
    }

    /** @type {number} */
    get state() {
        return this._state;
    }

    /** @type {number} */
    get timeOffset() {
        return this._timeOffset;
    }

    /** @type {Hash} */
    get headHash() {
        return this._headHash;
    }

    /** @type {string} */
    get userAgent() {
        return this._userAgent;
    }

    /** @type {object} */
    toPlain() {
        const plain = super.toPlain();
        plain.connectionSince = this.connectionSince;
        plain.netAddress = this.netAddress.toString();
        plain.bytesReceived = this.bytesReceived;
        plain.bytesSent = this.bytesSent;
        plain.latency = this.latency;
        plain.version = this.version;
        plain.state = this.state;
        plain.timeOffset = this.timeOffset;
        plain.headHash = this.headHash.toPlain();
        plain.userAgent = this.userAgent;
        return plain;
    }
};

/** @class Client.NetworkStatistics */
Client.NetworkStatistics = class NetworkStatistics {
    /**
     * @param {Network} network
     */
    constructor(network) {
        this._bytesReceived = network.bytesReceived;
        this._bytesSent = network.bytesSent;
        this._peerCounts = {
            total: network.peerCount,
            connecting: network.peerCountConnecting,
            dumb: network.peerCountDumb,
            rtc: network.peerCountWebRtc,
            ws: network.peerCountWebSocket,
            wss: network.peerCountWebSocketSecure
        };
        this._knownAddressesCounts = {
            total: network.knownAddressesCount,
            rtc: network.addresses.knownRtcAddressesCount,
            ws: network.addresses.knownWsAddressesCount,
            wss: network.addresses.knownWssAddressesCount
        };
        this._timeOffset = network.time.offset;
    }

    /** @type {number} */
    get bytesReceived() {
        return this._bytesReceived;
    }

    /** @type {number} */
    get bytesSent() {
        return this._bytesSent;
    }

    /** @type {number} */
    get totalPeerCount() {
        return this._peerCounts.total;
    }

    get peerCountsByType() {
        return this._peerCounts;
    }

    /** @type {number} */
    get totalKnownAddresses() {
        return this._knownAddressesCounts.total;
    }

    get knownAddressesByType() {
        return this._knownAddressesCounts;
    }

    /** @type {number} */
    get timeOffset() {
        return this._timeOffset;
    }

    /** @type {object} */
    toPlain() {
        return {
            bytesReceived: this.bytesReceived,
            bytesSent: this.bytesSent,
            totalPeerCount: this.totalPeerCount,
            peerCountsByType: this.peerCountsByType,
            totalKnownAddresses: this.totalKnownAddresses,
            knownAddressesByType: this.knownAddressesByType,
            timeOffset: this.timeOffset
        };
    }
};