How to construct a subscription message for XMPP in NodeJS package? - node.js

I'm using node-xmpp-client package to connect to an XMPP service. The service publishes messages when it receives them from some external source. My goal:
Connect to the service
Get authenticated
Subscribe to some nodes that I'm interested in. (Node name is known)
Receive stanza from the node to know new message has come in and handle it.
I'm referencing to the sample code here.
I have managed to connect to the service with code below. Does this automatically authenticate me to the server? I don't receive any "authenticate" event. If it doesn't, how do I explicitly request for authentication?
var client = new xmpp.Client({
jid: 'someuser#somedomain.com',
password: 'somepassword',
host:'somehost',
port:5222
})
Next, how do I subscribe to a publisher node? Should I do a client.send(new xmpp.Message(..))? If yes, how the xmpp.Message should be constructed? I can see the XMPP subscription iq in XMPP's web but have difficulty in mapping it back to node-xmpp's api.
<iq type='set'
from='francisco#denmark.lit/barracks'
to='pubsub.shakespeare.lit'
id='sub1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscribe
node='princely_musings'
jid='francisco#denmark.lit'/>
</pubsub>
</iq>

Probably easiest to look at how I did this for xmpp-ftw-pubsub https://github.com/xmpp-ftw/xmpp-ftw-pubsub/blob/master/lib/pubsub.js#L111-L137

Related

Spring Integration Tcp project

I have a project that part of it is using Tcp connection, the case is as per below , I will also include a screen shot.
We have two clients, client 1 and client 2 those are conveyor belts so if we receive data on client one input we should send the reply to client 2 output and vise vers, I'm sure we can do it using Spring integration Tcp and probably getways. Am I approaching correctly Tcp integration at this case?
Yet I do not have code implementation but started to put something on it.
Sounds like you implementing a chat (or similar user-to-user) communication.
No, gateways won't help you here.
You need to have a TcpReceivingChannelAdapter and TcpSendingMessageHandler connected to the same AbstractServerConnectionFactory. The TcpSendingMessageHandler is registered as a TcpSender with that connection and all the sending connections are stored in the Map<String, TcpConnection> connections. When we produce a message to this MessageHandler, it tries to consult that registry like this:
private void handleMessageAsServer(Message<?> message) {
// We don't own the connection, we are asynchronously replying
String connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class);
TcpConnection connection = null;
if (connectionId != null) {
connection = this.connections.get(connectionId);
}
if (connection != null) {
So, on the receiving side (TcpReceivingChannelAdapter and its sub-flow) you need to ensure somehow that you really set a proper IpHeaders.CONNECTION_ID header for producing so-called reply in the end to a desired client.
You probably can react for the TcpConnectionOpenEvent via #EventListener and register some business key with the connectionId for the future correlation. When you send a message, you supply that target user business key, in the TcpReceivingChannelAdapter sub-flow you take that business key and obtain a desired connectionId from you registry. And enrich it into the IpHeaders.CONNECTION_ID header for automatic logic in the TcpSendingMessageHandler.
When TcpConnectionCloseEvent happens you have to remove its respective entry from your custom registry.
Since TCP/IP comes without headers support there is no any out-of-the-box mechanism to implement such a correlation feature.
Although TcpConnectionOpenEvent might not be enough for you since there is no any business info when connection is established. Perhaps you would need to implement some hand-shake logic in the TcpReceivingChannelAdapter flow to distinguish a real message and connection metadata for registering in the custom registry.
See more info in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/ip.html#ip-correlation
It might be also better for your use-case to look into a WebSocket support: https://docs.spring.io/spring-integration/docs/current/reference/html/web-sockets.html#web-sockets

nodejs rhea npm for amqp couldn't create subscription queue on address in activemq artemis

I have an address "pubsub.foo" already configured as multicast in broker.xml.
<address name="pubsub.foo">
<multicast/>
</address>
As per the Artemis documentation:
When clients connect to an address with the multicast element, a subscription queue for the client will be automatically created for the client.
I am creating a simple utility using rhea AMQP Node.js npm to publish messages to the address.
var connection = require('rhea').connect({ port: args.port, host: args.host, username:'admin', password:'xxxx' });
var sender = connection.open_sender('pubsub.foo');
sender.on('sendable', function(context) {
var m = 'Hii test'
console.log('sent ' + m);
sender.send({body:m});
connection.close();
});
I enabled debug log and while running the client code I see the message like this.
2020-02-03 22:43:25,071 DEBUG [org.apache.activemq.artemis.core.postoffice.impl.PostOfficeImpl] Message org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage#68933e4b is not going anywhere as it didn't have a binding on address:pubsub.foo
I also tried different variations of the topic, for example, client1.pubsub.foo, pubsub.foo::client1 however no luck from the client code. Please share your thoughts. I am new to ActiveMQ Artemis.
What you're observing actually is the expected behavior.
Unfortunately, the documentation you cited isn't as clear as it could be. When it says a subscription queue will be created in response to a client connecting it really means a subscriber not a producer. That's why it creates a subscription queue. The semantics for a multicast address (and publish/subscribe in general) dictate that a message sent when there are no subscribers will be dropped. Therefore, you need to create a subscriber and then send a message.
If you want different semantics then I recommend you use anycast.

How do I roll-back a message to Amazon MQ (AMQ) from Lambda?

So, I assume this relates to any Node.js and Active MQ installation but I am using Amazon MQ with Node.js Lambda...
Kind of a noob on ActiveMQ so please correct me where I am wrong!
After reading a message from a queue using stompit I continue processing the message and it shall then be sent over HTTPS to another server.
There is some message validation and enrichment happening on the way to the HTTPS POST, and of course the POST itself can result in an error.
How would I (best) handle a roll-back of the message in case of an error:
1) Keep the connection open and not send client.ack() until I finally got a HTTP 200 back from remote server?
2) Keep the message in a variable and put it back in case of error (sequence doesn't matter?
3) Use something other than stomp?
It is apparently not possible using STOMP so I've changed the code to use the library ampq10 instead.
import amqp10 from 'amqp10';
const AMQPClient = amqp10.Client;
const amqpClient = new AMQPClient({
receiverLink: {
attach: {
rcvSettleMode: amqp10.Constants.receiverSettleMode.settleOnDisposition
},
creditQuantum: 1
}
});
This will allow you to do a receiver.accept(message); if successfully handling the message. If you just .disconnect() whitout an .accept() the message will not be removed from the queue.

Round Robin for gRPC (nodejs) on kubernetes with headless service

I have a a 3 nodejs grpc server pods and a headless kubernetes service for the grpc service (returns all 3 pod ips with dns tested with getent hosts from within the pod). However all grpc client request always end up at a single server.
According to https://stackoverflow.com/a/39756233/2952128 (last paragraph) round robin per call should be possible Q1 2017. I am using grpc 1.1.2
I tried to give {"loadBalancingPolicy": "round-robin"} as options for new Client(address, credentials, options) and use dns:///service:port as address. If I understand documentation/code correctly this should be handed down to the c-core and use the newly implemented round robin channel creation. (https://github.com/grpc/grpc/blob/master/doc/service_config.md)
Is this how round-robin load balancer is supposed to work now? Is it already released with grpc 1.1.2?
After diving deep into Grpc-c core code and the nodejs adapter I found that it works by using the option key "grpc.lb_policy_name". Therefore, constructing the gRPC client with
new Client(address, credentials, {"grpc.lb_policy_name": "round_robin"})
works.
Note that in my original question I also used round-robin instead of the correct round_robin
I am still not completely sure how to set the serviceConfig from the service side with nodejs instead of using client (channel) option override.
I'm not sure if this helps, but this discussion shows how to implement load balancing strategies via grpc.service_config.
const options = {
'grpc.ssl_target_name_override': ...,
'grpc.lb_policy_name': 'round_robin', // <--- has no effect in grpc-js
'grpc.service_config': JSON.stringify({ loadBalancingConfig: [{ round_robin: {} }] }), // <--- but this still works
};

SignalR access hub from elsewhere in server

I'm hosting SignalR in IIS along with my application and while my remote clients can connect happily I can't get my application which has created the hubs to connect and take part itself reliably.
I have tried to connect to the hub from within the web server process which is successful but only if I know what port it is hosted on. As that can be configured from IIS to be anything then I don't know what port to try to connect to internally.
I had hoped I could make use of the IHubContext but that only seems to give me ways of sending messages but not receiving them.
I feel like I'm missing something obvious.
-- Edit --
I've moved on with my experimenting but I've hit a different brick wall now.
I'm setting up my hub like this
GlobalHost.DependencyResolver.Register(typeof(StatusHub), () => this.StatusHub);
So that I can have a single instance of the hub and hook into events on it from within my server but external to the hub itself.
I can then make use of a couple of events
public event EventHandler<string> Connected;
public event EventHandler<string> Disconnected;
And then else where
this.statusHub.Connected += (sender, connectionId) => this.UpdateServerStatus(connectionId);
this.statusHub.Disconnected += (sender, connectionId) => this.ReleaseLicense(connectionId);
And these functions get called as clients connect and disconnect when the hub makes the overidden calls to
public override Task OnConnected()
and
public override Task OnDisconnected(bool stopCalled)
What I then can't seem to do is actually send messages to the clients using the hub. I've tried to do this
var host = GlobalHost.ConnectionManager.GetHubContext<StatusHub>();
host.Clients.All.Update(args);
and while host comes back as a valid object no client function I call on it appears to get through and I can't see any clients on the object.
In the end I was missing a key point. I'm no longer connecting to my own hub internally because the callbacks call me when I need to know.
Calling the client function in the end I was trying to call a hub function Update() and not the client function heartbeat().

Resources