The messaging is very advanced as REST, JMS, AMQP, SOAP

Messages are the working fuel of the nyssr.net. They are streamed primitive variables (integers, strings, etc.) as well as structures and arrays based on them, to represent complex data. Messages can be composed ad hoc. Preferably, however, you define a description in JSON (or XML) and generate classes that can be used to populate and read type-safe messages. Additionally, this provides you with an API to share.

Example of a record definition in JSON:

{
  "records": [
    {
      "id": "be125fa3-b4a7-493c-ad9a-5fa1a23be84d",
      "name": "NOTIFY_REMOTE_NODE_ADDED",
      "isService": "true",
      "namespaces": "SYSTEM",
      "description": "Notification that a remote node has been added.^It is now possible to send messages to the remote node.",
      "slots": [
        {
          "key": "1",
          "name": "REMOTE_NODE",
          "direction": "REQUEST",
          "mandatory": "true",
          "type": "NODE_ADDRESS",
          "description": "The remote node."
        },
        {
          "key": "2",
          "name": "TYPE",
          "direction": "REQUEST",
          "mandatory": "true",
          "type": "STRING",
          "description": "The type of the remote node, see ETypeOfNode."
        }
      ]
    }
  ]
}

Example sending this message:

final CEnvelope env = CEnvelope.forLocalNanoService(CRecordNotifyRemoteNodeAdded.ID);
final CRecord rec = CRecordNotifyRemoteNodeAdded.create();
CRecordNotifyRemoteNodeAdded.setRemoteNode(rec,
                                           nodeAddress);
CRecordNotifyRemoteNodeAdded.setType(rec,
                                     aNodeInfo.isClient() ? ETypeOfNode.CLIENT.name() : ETypeOfNode.SERVER.name());
sendNotification(env,
                 rec);

Messages are always sent asynchronously. The sender can therefore not wait synchronously for a response, but implements simple message handler functions that are called by the system when a message arrives.

Example of how to handle this message:

// install message handlers
void init()
{
    addMessageHandler(CRecordNotifyRemoteNodeAdded.ID,
                      this::asyncNotifyRemoteNodeAdded);
}

// is called when this message comes in
private boolean asyncNotifyRemoteNodeAdded(@NotNull final CEnvelope aEnvelope,
                                           @NotNull final CRecord aRecord) throws CException
{
    if (aEnvelope.isAnswer())
    {
        return false; // not handled
    }
    else
    {
        final CNodeAddress node = CRecordNotifyRemoteNodeAdded.getRemoteNode(aRecord,
                                                                             null);
        if (node != null)
        {
            // do something with node
            // ...
            aEnvelope.setResultSuccess();
        }
        else
        {
            aEnvelope.setResult(CResultCode.MISSING_ARGUMENT,
                                "Missing Node Address");
        }
        return true; // handled
    }
}

Messages will always arrive in the same thread, which means there is no risk of errors due to concurrency. This means that targets that have been registered for the same thread will always get messages delivered one after the other. An internal exchange of data between these targets remains possible without danger.

Messages are composed of an envelope and a record. While the envelope contains all the data for delivery, as in a written letter, the record will contain the user data.

In principle, the record is a map with keys and values. For example, it can be manipulated by the recipient as desired (add data, delete data) before it is sent back again.

The envelope, on the other hand, contains many switches that control the transport, e.g. response requested, compression or encryption requested, result code, result text, transaction number, forwarding requested, logging undesired, priority, etc.).

The design of a message with envelope and record

The design of a message with envelope and record

Sending messages works across the entire nyssr.net, regardless of where the nodes are located. Not all nodes have to be hosted in the cloud; it is sufficient if there is a path from the sender to the receiver.

Sending a message directly from one object to another object across the network

Sending a message directly from one object to another object across the network

An important feature of messages is the way they are addressed. They usually contain the network-wide unique address of a receiver and that of the sender. Messages are directional and pass from the sender object to the receiver object.

After handling the message, the system automatically returns it to the sender. Automatic return can be prevented by sender or receiver. The reply contains a status code and, if necessary, an error text. In the event of an error, the sender is informed of the processing status (okay, recipient unknown, message was not processed, and so on). This handshake is a key feature of nyssr.net.

For the use of patterns such as broadcasts or observers, there are other mechanisms which build on that principle on top.

Messages can be put on hold so that they are not automatically returned to the sender. This is useful if, for example, the recipient in turn needs to send messages to fulfill the request. After complete processing, the message can be returned manually.

Block message to perform internal request

Block message to perform internal request

Another feature is the forwarding of messages if the request is not processed immediately.

Forward message to another target

Forward message to another target

Messages for recipients on other nodes are passed from node to node until they reach their destination. Each node knows the state of the entire network, which means all other nodes and the connections between them. Each route between two nodes has a "cost" (ping duration or fixed cost). Therefore, each node can forward the message to the destination node along the most favorable route (Dijkstra's algorithm).

Routing of messages considering the costs

Routing of messages considering the costs

Messages have a priority. In case of heavy traffic, messages with high priority are given priority. Answers, for example, have an automatically high priority, while LOG messages or file snippets get a low priority. The user can explicitly set the desired priority for each message.

Messages can be compressed and encrypted. The corresponding flags can be set explicitly per message or per node. If messages are encrypted, the sender and receiver node exchange public keys beforehand (RSA).