Skip to content

Messages

John Smith edited this page Apr 26, 2020 · 5 revisions

WIKI Home -> Message API docs

You will need an instance of NKNClient

NKNClient client = new NKNClient(new Identity("Name", Wallet.createNew()));

As you can see, the client requires Identity which is built from a friendly name, whatever you like (it may be null) and instance of Wallet which you plan to use for this particular instance. Let's just generate a new one.

Let's set it up for receiving messages first. Get a SimpleMessagesProtocol instance which represents a way to uses SDK for that protocol and register a callback which will get called when it receives a message

client.simpleMessagesProtocol().onNewMessage(receivedMessage -> {
    if (receivedMessage.isText) {
        System.out.println("New text message from " + receivedMessage.from);
        System.out.println(receivedMessage.textData);
    } else if (receivedMessage.isBinary) {
        System.out.println("New binary message from " + receivedMessage.from);
        System.out.println(Hex.toHexString(receivedMessage.binaryData.toByteArray()).toUpperCase());
    }
});

There is also another type of message - ACK with corresponding isAck property. This message does not have any data, only information about the sender and is used to inform a sender of the message that the receiving party received the message successfully

Since we are talking about automatic ACKs, there might be a situation when this behavior is not desirable. You can disable it (and re-enable it later, if you want to) at any time of client runtime using this call.

client.simpleMessagesProtocol().setNoAutomaticACKs(true);

And we can also control encryption level using

client.setEncryptionLevel(NKNClient.EncryptionLevel.DO_NOT_ENCRYPT); // Default is ENCRYPT_ONLY_UNICAST

Possible values of this enum are: DO_NOT_ENCRYPT, ENCRYPT_ONLY_UNICAST, CONVERT_MULTICAST_TO_UNICAST_AND_ENCRYPT and ENCRYPT_UNICAST_AND_MULTICAST

Note: Multicast encryption is not implemented yet. If you set encryption to ENCRYPT_UNICAST_AND_MULTICAST and attempt to send a multicast message, an exception will be thrown

The counterpart of sending encrypted messages is receiving them. There are multiple strategies that deal with received non-encrypted messages. This behavior is set using client.setPeerEncryptionRequirement(NKNClient.PeerEncryptionRequirement.ON_NON_ENCRYPTED_MESSAGE___ALLOW_ALL_DROP_NONE) method call. All enum values are ON_NON_ENCRYPTED_MESSAGE___ALLOW_NONE_DROP_ALL, ON_NON_ENCRYPTED_MESSAGE___ALLOW_ACK_DROP_OTHER and ON_NON_ENCRYPTED_MESSAGE___ALLOW_ALL_DROP_NONE which are pretty self-explanatory.

The ReceivedMessage class, an instance of which is returned on new message callback contains field wasEncrypted. If your peer encryption requirement policy allows for non-encrypted messages, this is a way to tell whether they were properly encrypted or sent as plaintext.

We are ready to receive messages. Let's start the client!

Both client.simpleMessagesProtocol().setNoAutomaticACKs and client.setEncryptionLevel can be used even when client is running, to have different behaviour at different times.

client.start();

Time to send some messages.

CompletableFuture<NKNClient.ReceivedMessage> promise = client.simpleMessagesProtocol().sendTextMessageAsync(identity.getFullIdentifier(), "Hello!");

promise.whenComplete((response, error) -> {
    if (error == null) {
        System.out.println("Response ==> " + response.textData);
        // We are expecting text message, no need to check if it actually is one. For the sake of this example
    } else {
        error.printStackTrace();
    }
});

The full identifier is the identifier of the receiving side. It is in format name.publickey. In this case, we are sending a message to ourselves. Promise gets called when ACK (or response) is received or on timeout (or other error). When the field noAutomaticACKs is set, it gets called when the message was sent (or error). In that case, the value of response will be null

We are talking about replies, but how to send one? Well, instead of registering onNewMessage listener we register onNewMessageWithReply listener and whatever we return will be used as a reply message

client.simpleMessagesProtocol().onNewMessageWithReply(receivedMessage -> {
    if (receivedMessage.isText) {
        System.out.println("New text message from " + receivedMessage.from);
        System.out.println(receivedMessage.textData);
    } else if (receivedMessage.isBinary) {
        System.out.println("New binary message from " + receivedMessage.from);
        System.out.println(Hex.toHexString(receivedMessage.binaryData.toByteArray()).toUpperCase());
    }
    return "This is text message reply";
});

Whatever this listener returns will be used as a reply. If it returns String, the TextMessage will be sent, if it returns byte[] or ByteString BinarayMessage will be sent. If it returns null, simple ACK message without any content will be sent.

What if we want to send the same message to multiple recipients at the same time? We have multicast messages for that.

List<CompletableFuture<NKNClient.ReceivedMessage>> promises = clientSender.simpleMessagesProtocol().sendTextMessageMulticastAsync(new String[] {
        identityA.getFullIdentifier(),
        identityB.getFullIdentifier(),
        identityC.getFullIdentifier()
}, "Hello!");


promises.forEach(p -> p.whenComplete((response, error) -> {
    if (error == null) {
        System.out.println("Response from " + response.from);
        System.out.println("  ==> " + (response.isAck ? "[ACK]" : response.isText ? response.textData : ("0x" + Hex.toHexString(response.binaryData.toByteArray()).toUpperCase())));
    } else {
        System.out.println("Error: " + error.toString());
    }
}));

We provide a list of target addresses and get a list of promises, one for each address. And they get called when the client receives replies from those specific targets — exactly the same way as unicast messages.

After we are done, its time to call:

client.close();

NOTE 1: This example uses only text messages. Binary messages work the exact same way, but use methods sendBinaryMessageAsync and sendBinaryMessageMulticastAsync

NOTE 2: Method send<Text/Binary>Message[Multicast]Async is overloaded with field ByteString replyTo. If you pass msgId of the received message to this field, a new message will be sent out a reply to that message. If you pass null to this field (or use the overloaded method without this field), it will be sent out as a new message.

Clone this wiki locally