Hydra Router Message Client

Note: hrmc requires hydra-router version 1.6.0 or greater

As a messaging gateway, Hydra Router supports WebSocket connections and message routing to connected clients and microservices. While developing message-based clients and services it becomes necessary to test message flows. This is what lead us to create a tool called hrmc - the Hydra Router Message Client. HRMC is a NodeJS based REPL where you can interactively connect to a Hydra Router to send messages.

$ hrmc
Hydra Router Message Client v.1.0.3
Use client.help() for help.
Use client members or .exit to close repl.

The hrmc REPL exports a single class called client which contains member functions for connecting and sending messages to a Hydra Router instance. For example, to open a connection to a hydra router instance running on localhost port 5353:

➤ client.open('ws://localhost:5353')

To close the connection:

➤ client.close()

Installing hrmc

You can install hrmc using NPM:

$ npm install -g hrmc

We should install it using the -g global flag to ensure it can be launched from any of your projects. The hrmc project is hosted on github at: https://github.com/cjus/hrmc

Using hrmc

Before using hrmc make sure you're running an instance of hydra-router. As we saw earlier you can use the client object's member functions to open and close a connection on a Hydra Router.

To get a list of available commands use:

➤ client.help()

The list of available client members include: open close reopen createMessage and sendMessage.

Let see how this all works using an example session. In this session we'll connect to a hydra router and call its internal API. Then we'll speak with a user service.

We begin by connecting to hydra-router. In this example I'm connecting to a hydra router at 192.168.1.221:5482

➤ client.open('ws://192.168.1.221:5482')

For consistency all hrmc client functions which expect a parameter - expect that parameter to be a string! Because JSON using double quotes we'll use the single quote character.

The response that returns is:

➤ Connection established: 27ce6oxplm5
{"to":"27ce6oxplm5@client:/","frm":"5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/","mid":"72ffb790-6634-4e97-8e48-276c223b7b0f","ts":"2018-02-19T14:43:37.407Z","typ":"connection","ver":"UMF/1.4.6","bdy":{"id":"27ce6oxplm5","ip":"::ffff:192.168.1.221"}}

The above may be a bit hard to read so you can use the client.jsonPrint() function to pretty print the JSON.

{
  "to": "27ce6oxplm5@client:/",
  "frm": "5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/",
  "mid": "72ffb790-6634-4e97-8e48-276c223b7b0f",
  "ts": "2018-02-19T14:43:37.407Z",
  "typ": "connection",
  "ver": "UMF/1.4.6",
  "bdy": {
    "id": "27ce6oxplm5",
    "ip": "::ffff:192.168.1.221"
  }
}

So that's the response from the hydra-router. The JSON document is in a format called UMF which hydra uses for messaging.

See hydra messaging for more information

In the to field we see that the message is seen as coming from 27ce6oxplm5@client:/You'll notice that there is an ID in from of the @client. That's the unique client ID for our connected hrmc. It's the same ID returned when we established our connection above.

The frm field tells us that the above message was sent from a hydra-router with a unique service ID of 5d77f8ac3d784bc2946e4d2a2f806805 The bdy body portion of the message is particularly important as it assigns our client the unique ID of 27ce6oxplm5.

Let's move on. Next we'll create a new message to send to Hydra Router.

➤ client.createMessage()
{"to":"hydra-router:/","frm":"27ce6oxplm5@client:/","mid":"c677bf50-80be-4d2e-87e1-4d048c372b47","ts":"2018-02-19T15:26:35.835Z","ver":"UMF/1.4.6","bdy":{}}

This creates a basic message, we can copy the JSON to an editor and customize it. Update the to field to hydra-router:[get]/v1/router/version

When we take the response and view it using use the client.jsonPrint() function we see:

{
  "to": "27ce6oxplm5@client:/",
  "frm": "5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/",
  "mid": "312da70c-8b72-48a9-a481-77d32653e867",
  "ts": "2018-02-19T15:35:34.114Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "version": "1.6.0-experimental"
  }
}

At the time of this writing I'm using the 1.6.0-experimental version of Hydra-Router.

Now, let's speak to the user service.

We can create another message using client.createMessage and then change the to field to: user-service:[get]/v1/user/health

So in the new message we're sending to Hydra Router we'll ask it to pass it along to a service called user-service and to request the v1/user/health end point. The response would be something like when viewed using the client.jsonPrint() function:

{
  "to": "27ce6oxplm5@client:/",
  "frm": "user-servcie:[get]/v1/user/health",
  "mid": "1a92789c-e6e4-43e8-b4ad-c08999c26141",
  "rmid": "c677bf50-80be-4d2e-87e1-4d048c372b47",
  "ts": "2018-02-19T15:58:25.440Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "result": {
      "serviceName": "user-svcs",
      "instanceID": "a125395c70f643dfb6743dc5aba32e17",
      "hostName": "dac3865f9fd0",
      "sampledOn": "2018-02-19T15:58:25.454Z",
      "processID": 1,
      "architecture": "x64",
      "platform": "linux",
      "nodeVersion": "v8.0.0",
      "memory": {
        "rss": 54370304,
        "heapTotal": 28356608,
        "heapUsed": 25279784,
        "external": 66409
      },
      "uptimeSeconds": 287.767
    }
  }
}

More advanced examples

Now what if we wanted a backend service to asynchronously send messages back to connected clients?

A backend service would only have to know the client ID to route a message! Here's how the message would be formatted.

{
  "to": "hydra-router:/",
  "frm": "abackend-service:/",
  "fwd": "27ce6oxplm55@client:/",
  "mid": "5cc4e3f5-ad72-41f3-a23f-212bdabc331f",
  "ts": "2018-02-17T16:02:48.902Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "msg": "Hello from a backend service"
  }
}

A backend service would simply specify any hydra-router available instance in your network - in the to field. Your service would then identify itself in the frm field. It would then use the fwd (forward) field to specify the client instance that should receive the message. The bdy of the message would include whatever JSON payload your service would like to send. The receiving hydra-router instance would ensure that the message is routed to the appropriate client.

This routing mechanism also allows clients to send messages to one another:

{
  "to": "hydra-router:/",
  "frm": "1objkd63kfd@client:/",
  "fwd": "27ce6oxplm55@client:/",
  "mid": "5cc4e3f5-ad72-41f3-a23f-212bdabc331f",
  "ts": "2018-02-17T16:02:48.902Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "msg": "Hello from 1objkd63kfd"
  }
}

So again a client would send the message intended for another client via hydra-router.

It's important to note that clients are not speaking directly to one another but rather through a hydra router.

Because Hydra-Router is designed to speak with other hydra-routers, messages can be routed to clients and services regardless of which hydra-router they're connected to. Naturally, the hydra-routers and services in question need to be on the same network or network accessible.

So in this example the same message above would be routed despite the fact that clients 1objkd63kfd and 27ce6oxplm55 are not connected to the same Hydra-Router.

The following scenarios are supported:

  • clients connect to hydra-router and send messages to backend services
  • backend services can send async messages back to specific clients
  • clients can send messages to one another via a hydra-router.

results matching ""

    No results matching ""