Skip to content

WebSocket communication

Karl Oczadly edited this page Feb 13, 2021 · 11 revisions

Introduction to Nano WebSockets

The Nano WebSocket API provides real-time access to network events and node functions, allowing your application to receive new information as soon as the node sees or processes the data.

For further information and guidance, visit the Nano documentation website at docs.nano.org.

Node configuration

In order to utilise the WebSockets functionality, you will need to configure and enable them in the settings. These can be found in the config-node.toml configuration file:

  • node.websocket/enable must be set to true
  • node.websocket/address should be set to ::1 in most instances, unless you need to bind the socket to a different interface
  • node.websocket/port is the port the websocket should listen on — by default, this value is 7078

How to use the library

The NanoWebSocketClient class is the primary class used to configure and connect to the node's WebSocket interface. The constructor argument takes the address and port of the websocket endpoint, or will default to localhost:7078 if using the parameter-less variant.

In order to use the WebSocket library, it is recommended that you first specify a WsObserver object to monitor the status of the WebSocket. This can be accomplished through the setObserver(WsObserver) method within the NanoWebSocketClient class, and will allow you to be notified of when the websocket is opened and closed, as well as dealing with uncaught exceptions which may occur.

You can now initiate the Websocket connection through the use of the connect() method. This will attempt to connect to the node's WebSocket, or return false if the connection could not be established.

Once the above is done, a listener should be registered for each topic you want to listen to. To do this, call any of the relevant topicXXX() methods returned by the call to .getTopics(), then call the .registerListener(TopicListener) method to register your listener. For example: ws.getTopics().topicConfirmedBlocks().registerListener(myListener);.

Finally, you will need to subscribe to any of the topics through the subscribe() method. Some topics may support additional arguments and filters which you can pass through this method (check the table below), and others may also provide an update function for modifying existing filters. Calling the subscribe() methods will process them asynchronously, while the subscribeBlocking() variants will block and wait for an acknowledgement response from the server before continuing. The same concept applies to the update and unsubscribe methods.

Supported topics

Topic Method Message class Sub args Update args
confirmation topicConfirmedBlocks() TopicMessageConfirmation
active_difficulty topicActiveDifficulty() TopicMessageActiveDifficulty
bootstrap topicBootstrap() TopicMessageBootstrap
stopped_election topicStoppedElection() TopicMessageStoppedElection
telemetry topicTelemetry() TopicMessageTelemetry
new_unconfirmed_block topicUnconfirmedBlocks() Block
vote topicVote() TopicMessageVote
work topicWork() TopicMessageWork

Example

In the example below, we will listen for newly confirmed blocks which belong to a specific set of accounts (using a filter), and print the block and election information to the console.

Main application code:

// Create a WebSocket client, with an endpoint address of localhost:7078 (the default address)
NanoWebSocketClient ws = new NanoWebSocketClient();

// Register a WebSocket observer (not necessary, but recommended)
ws.setObserver(new SampleWsObserver());

// Attempt to connect to the WebSocket
if (!ws.connect()) {
    // Connection failed
    System.err.println("Could not connect to WebSocket!");
    return;
}

// Register a topic listener (in this case, using a lambda function)
ws.getTopics().topicConfirmedBlocks().registerListener((message, context) -> {
    System.out.println(message.getHash());                                      // Print the block hash
    System.out.println("  Amount: " + message.getAmount());                     // Print the transaction amount
    System.out.println("  Conf: " + message.getConfirmationType());             // Print the confirmation type
    System.out.println("  Voted by: " + message.getElectionInfo().getVoters()); // Print vote count
});

// Subscribe to the confirmed blocks topic, and specify filters and configuration
boolean subscribed = ws.getTopics().topicConfirmedBlocks().subscribeBlocking(
        new TopicConfirmation.SubArgs()
                .includeElectionInfo() // Include election info in the messages
                .filterAccounts( // Account filter (only include blocks belonging to these accounts)
                        "nano_34qjpc8t1u6wnb584pc4iwsukwa8jhrobpx4oea5gbaitnqafm6qsgoacpiz",
                        "nano_1b9rcj4o7r37acf8hdm5iq9qn5tx8nfwqr51d6yxtknona1ybir5kgjpyoh9")
);

// Print subscription status
System.out.println(subscribed ? "Subscribed to topic!" : "Could not subscribe to topic!");

And the WebSocket observer we are using:

static class SampleWsObserver implements WsObserver {
    @Override
    public void onOpen(int httpStatus) {
        System.out.println("WebSocket connected!");
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        System.out.println("WebSocket disconnected!");
    }

    @Override
    public void onSocketError(Exception ex) {
        ex.printStackTrace();
    }
}

Example console output:

WebSocket connected!
Subscribed to topic!
478DC8ECA3F0D3B4CEE42A5971F1D963F36FEE8E5DBF326E7A181864041F66D4
  Amount: 0.000547 Nano
  Conf: ACTIVE_QUORUM
  Voted by: 74
C2BA24A043EAE962FD750F784FF5D8703FC09B703E531777F269EF7F99B04D29
  Amount: 0.000547 Nano
  Conf: ACTIVE_QUORUM
  Voted by: 65
Clone this wiki locally