Subscribe GetNodes
Since we are connected successfully to the Streaming API service, we can stream down available nodes from the HCS. See the protobuf definition.
Payload Static Reference
export interface FileID { 'shardNum'?: (number | string | Long); 'realmNum'?: (number | string | Long); 'fileNum'?: (number | string | Long);}export interface GetNodesQuery { 'fileId'?: (FileID | null); 'limit'?: (number);}export interface SubscribeGetNodesPayload { subscribe: string; body: GetNodesQuery;}const subscribeTopicRoute = `/com.hedera.mirror.api.proto.NetworkService/getNodes`;const payloadBody: GetNodesQuery = { fileId: { fileNum: '101' // The ID of the address book file on the network. Can be either 101 or 102. }, limit: 100 // The maximum number of node addresses to receive before stopping. If not set or set to zero it will return all node addresses in the database.}const payload: SubscribeGetNodesPayload = { subscribe: subscribeTopicRoute, body: payloadBody}
Payload breakdown
To subscribe this stream, our payload should match reference protobuf definition.
View Definition
/** * Request object to query an address book for its list of nodes */message AddressBookQuery { /** * The ID of the address book file on the network. Can be either 0.0.101 or 0.0.102. */ .proto.FileID file_id = 1; /** * The maximum number of node addresses to receive before stopping. If not set or set to zero it will return all node addresses in the database. */ int32 limit = 2;}
By looking into the defination, we can see that we need to provide a FileID
and limit
(optional) to get the latest messages.
For forming the payload, we should also be aware of basic_types.proto
used in the defination.
View Definition
//** * The ID for a file */message FileID { /** * The shard number (nonnegative) */ int64 shardNum = 1; /** * The realm number (nonnegative) */ int64 realmNum = 2; /** * A nonnegative File number unique within its realm */ int64 fileNum = 3;}
All we need is to build a payload as below:
- React.js
- Node.js
- HTML/Javascript
import React, { useEffect, useState } from "react";import io from 'socket.io-client';function StreamingInit () { // Make sure you match the url for testnet/mainnet const demoFileId = `102`; // The ID of the address book file on the network. Can be either 101 or 102. const StreamingAPIURL = `wss://<StreamingAPI_URL>/<ARKHIA_API_KEY>`; const socket = io(StreamingAPIURL); const [socketStatus, setSocketStatus] = useState(``); const [socketConnect, setSocketConnect] = useState(false); // Available services in page 2 of these docs const subscribeGetNodesRoute = `/com.hedera.mirror.api.proto.NetworkService/getNodes`; const getSubscriptionPayload = (file_id: string, limit: string) => { const subscriptionPayload = { subscribe: subscribeGetNodesRoute, body: { fileId: { fileNum: file_id // The ID of the address book file on the network. Can be either 101 or 102. }, limit // The maximum number of node addresses to receive before stopping. If not set or set to zero it will return all node addresses in the database. } }; }; const subscribeGetNodes = () => { const requestPayload = getSubscriptionPayload(demoFileId , `100`); // get latest 100 socket.emit(`subscribe`, requestPayload, (msg: any) => { console.log(`GetNodes streaming down...`); socket.on(msg.listeners.data, function (message: any) { console.log(message) }); socket.on(msg.listeners.error, function (message: any) { setSocketError(message); console.log(`Error`); console.log(message) }); }); }; useEffect(() => { socket.on(`connect`, () => { setSocketConnect(true); socket.on(`status`, (msg) => { console.log(`status`, msg); setSocketStatus(`StreamingAPI is successfully connected`); }); socket.emit(`list-services`, (services: any) => { console.log(`Listing available services`, services); }); }); socket.on(`disconnect`, (msg: any) => { setSocketConnect(false); setSocketStatus(`StreamingAPI is disconnected.`) console.log(`Disconnected.`) }); socket.on(`error`, (message: any) => { setSocketConnect(false); console.error(message); setSocketStatus(message) }) }, [socket]); return ( <> <div> { socketStatus && ( <> <h6>StreamingAPI status</h6> <div>{socketStatus}</div> </> ) } { socketConnect && ( <> <button onClick={subscribeGetNodes}> </> ) } </div> </> );}export default StreamingInit;
const io = require('socket.io-client');// Make sure you match the url for testnet/mainnet const demoFileId = `102`; // The ID of the address book file on the network. Can be either 101 or 102.const StreamingAPIURL = `wss://<StreamingAPI_URL>/<ARKHIA_API_KEY>`;const socket = io(StreamingAPIURL);// Available services in page 2 of these docsconst subscribeGetNodesRoute = `/com.hedera.mirror.api.proto.NetworkService/getNodes`;const getSubscriptionPayload = (file_id, limit) => { return { subscribe: subscribeGetNodesRoute, body: { fileId: { fileNum: file_id // The ID of the address book file on the network. Can be either 101 or 102. }, limit // The maximum number of node addresses to receive before stopping. If not set or set to zero it will return all node addresses in the database. } };};const subscribeGetNodes = () => { const requestPayload = getSubscriptionPayload(demoFileId, `100`); // get latest 100 socket.emit(`subscribe`, requestPayload, (msg) => { console.log(`GetNodes streaming down...`); socket.on(msg.listeners.data, function (message) { console.log(message) }); socket.on(msg.listeners.error, function (message) { console.log(`Error`); console.log(message) }); });}socket.on(`connect`, () => { socket.on(`status`, (msg) => { console.log(`StreamingAPI is successfully connected`); console.log(`status`, msg); }); subscribeGetNodes();});socket.on(`disconnect`, (msg) => { console.log(`StreamingAPI is disconnected.`) console.log(`Disconnected.`)});socket.on(`error`, (message) => { console.error(message); console.log(message)})
<!DOCTYPE html><html><head> <style> body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } #messages { list-style-type: none; margin: 0; padding: 0; } #messages>li { padding: 0.5rem 1rem; background: #868484; } #messages>li:nth-child(odd) { background: #efefef; } </style></head><body> <ul id="messages"></ul></body><script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.min.js"></script><script> // Make sure you match the url for testnet/mainnet const demoFileId = `102`; // The ID of the address book file on the network. Can be either 101 or 102. const StreamingAPIURL = `wss://<StreamingAPI_URL>/<ARKHIA_API_KEY>`; const socket = io(StreamingAPIURL); // Available services in page 2 of these docs const subscribeGetNodesRoute = `/com.hedera.mirror.api.proto.NetworkService/getNodes`; socket.on('connect', function () { socket.on('status', (msg) => { console.log('status', msg); addMessage('status', msg); }); socket.emit('list-services', function (services) { console.log('services', services); // addMessage('services', services); }) subscribeGetNodes(); }); const subscribeGetNodes = () => { const requestPayload = getSubscriptionPayload(demoFileId, `100`); // get latest 100 socket.emit(`subscribe`, requestPayload, (msg) => { addMessage(`Message from: ${demoFileId}`, `GetNodes streaming down...`); socket.on(msg.listeners.data, function (message) { addMessage(`Message from: ${demoFileId}`, message); }); socket.on(msg.listeners.error, function (message) { console.log(`Error`); addMessage(`Error from: ${demoFileId}`, { error: message }); }); }); } const getSubscriptionPayload = (file_id, limit) => { return { subscribe: subscribeGetNodesRoute, body: { fileId: { fileNum: file_id // The ID of the address book file on the network. Can be either 101 or 102. }, limit // The maximum number of node addresses to receive before stopping. If not set or set to zero it will return all node addresses in the database. } }; }; function addMessage(event, message) { var item = document.createElement('li'); item.innerHTML = `` messages.appendChild(item); window.scrollTo(0, document.body.scrollHeight); }</script></html>