Mqtt unsubscribe not ending topic subcription - node.js

I am able to publish and subscribe to a topic but when the unsubscribe function is not working it?
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost:1883');
var topic = 'home/machine1/lightSensor';
client .on('connect', ()=>{
client.unsubscribe(topic,console.log);
});
it returning null

From the mqttjs docs:
mqtt.Client#unsubscribe(topic/topic array, [options], [callback])
Unsubscribe from a topic or topics
topic is a String topic or an array of topics to unsubscribe from
options: options of unsubscribe.
properties: object
userProperties: The User Property is allowed to appear multiple times to represent multiple name, value pairs object
callback - function (err), fired on unsuback. An error occurs if client is disconnecting.
Returning null is the correct response if the unsubscribe succeeds.

Related

Proper way of reading messages from Kafka topic and then closing

I am building a simple node.js API using express and kafka-node that returns unread messages from requested Kafka topic and consumer group when HTTP request is received and then closes the connection. I don't need or want the consumer to keep waiting for new messages.
In kafka-node, what is the proper way of checking if the end of the topic has been reached and if yes, close the connection to broker and exit the application in order to prevent new messages being read?
Here's my consumer.js. It's pretty much the same as example given in kafka-node documentation.
"use strict";
const kafka = require("kafka-node");
let topicName = "testTopic-01",
groupName = "testGroup-01",
consumerOptions = {
kafkaHost: "localhost: 9092",
groupId: groupName,
sessionTimeout: 15000,
protocol: ["roundrobin"],
fromOffset: "earliest",
encoding: "utf8"
};
const consumerGroup = new kafka.ConsumerGroup(consumerOptions, topicName);
consumerGroup.on("message", message => {
console.log(`Message: ${message.value}`);
});
consumerGroup.on("error", error => {
console.error(error);
});
console.log(`Consumer started on topic ${topicName} on group ${groupName}`);
You can fetch the current offset of a topic partition by using #Offset. By comparing the so fetched offset of your assigned topic partition, you then know what the last message in the corresponding topic partition is.
Keep in mind, that, if you have multiple consumers in parallel, you should keep track of the topic partition that your consumer inside the consumer group was assigned to (#fetchCommits).

Autobahn identify subscription

When creating a websockets connection how can I determine the name of the subscription in the event function.
For example if I have three subscriptions I wish to be able to identify which once triggered the event.
var autobahn = require('autobahn');
var connection = new autobahn.Connection({url: 'ws://127.0.0.1:9000/', realm: 'realm1'});
connection.onopen = function (session) {
function onevent(args) {
console.log("Colour is: ", ?????);
}
["Red", "Green", "Brown"].forEach(function(colour) {
session.subscribe(colour, onevent);
}
};
connection.open();
Your onevent function actually receives three arguments: args, kwargs and details, where the first two are message payload (an array and an object). The details object contains what you are looking for: the subscription topic.

Event emitter loop not working in node-red function

I am attempting to use a node-red function to read Azure IoT Hub messages using AMQP. I have imported the azure-iothub module.
The code below connects ok and getFeedbackReceiver returns an AmqpReceiver object (I can see the object output to debug tab) which acts as an event emitter. However, the emitter loop (msgReceiver.on) doesn't seem to run. I don't even get a null output to debug tab.
Any help appreciated.
var azureamqp = global.get('azureamqp');
var iothub = azureamqp.Client.fromConnectionString(cnct);
try
{
iothub.open(function()
{
node.send({type: "connection", payload: util.inspect(iothub)});
node.status({ fill: "green", shape: "ring", text: "listening" });
iothub.getFeedbackReceiver(function(err,msgReceiver)
{
if (!err)
{
node.send({type: "receiver", payload: util.inspect(msgReceiver)});
msgReceiver.on('message',function(message)
{
node.send({payload:message});
});
}
else
{
node.send({payload: err});
}
});
node.send({type: "streamend"});
node.status({ fill: "red", shape: "ring", text: "disconnected" });
});
}
catch (err)
{}
Ok I think I see what's happening thanks to the additional comments: First of, some reference docs about messaging with IoT Hub:
https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messaging
There are 2 types of messages that are sent through IoT Hub, depending on the direction in which they go:
Cloud to Device (C2D, or commands): these messages are sent by a cloud app to one or more devices. They are stored in a device-specific queue, and delivered to the device as soon as the device connects and starts listening for messages. Once received by the device, the device can choose to send feedback about these to IoT Hub. This feedback is received using the azure-iothub.Client.getFeedbackReceiver() API. I've added more about this at the end of the answer.
Device-to-Cloud (D2C, or telemetry): these messages are sent by the devices to the cloud application. These messages are stored in Event Hubs partitions and can be read from these partitions. This happens with the Event Hubs SDK
From the question and the comments it looks like you're trying to receive D2C messages (telemetry) using the feedback API - and it's not working, because it's not meant to work that way. It's good feedback for (bad?) API design and lack of docs though.
How to receive messages sent by devices:
This sample on github shows how to set up an Event Hubs client and can be used to listen to messages sent by devices to IoT Hub.This command in iothub-explorer is also an easy reference.
Please find below a simple example:
'use strict';
var EventHubClient = require('azure-event-hubs').Client;
var Promise = require('bluebird');
var connectionString = '[IoT Hub Connection String]';
var client = EventHubClient.fromConnectionString(connectionString);
var receiveAfterTime = Date.now() - 5000;
var printError = function (err) {
console.error(err.message);
};
var printEvent = function (ehEvent) {
console.log('Event Received: ');
console.log(JSON.stringify(ehEvent.body));
console.log('');
};
client.open()
.then(client.getPartitionIds.bind(client))
.then(function (partitionIds) {
return Promise.map(partitionIds, function (partitionId) {
return client.createReceiver('$Default', partitionId, { 'startAfterTime' : receiveAfterTime}).then(function(receiver) {
receiver.on('errorReceived', printError);
receiver.on('message', printEvent);
});
});
}).catch(printError);
A little more about that code sample:
Basically, the Event Hubs client provide an AMQP connection can be used to open receivers on each partition of the Event Hub. Partitions are used to store messages sent by devices. Each partition gets its own receiver, and each receiver has a message event. Hence the need to open one receiver per partition to never miss any message from any devices. Here's a little bit more about Event Hubs and the nature of partitions: https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-what-is-event-hubs
More about C2D Feedback:
There are 3 types of feedback that a device can send about a C2D message:
accept (or complete) means the message is taken care of by the device and the IoT Hub will remove this message from the device queue
reject means that the device doesn't want this message (maybe because it's malformed, or irrelevant, that's up to you to device) and the IoT Hub will remove the message from the queue.
abandon means that the device cannot "take care" of this message right now and wants IoT Hub to resend it later. The message remains in the queue.
accept and reject are both going to be observed using the getFeedbackReceiver API, as well as timeouts if the message is never received or is abandonned too many times.

how can I make private chat rooms with sockjs?

I am trying to make a chat system where only two users are able to talk to each other at a time ( much like facebook's chat )
I've tried multiplexing, using mongoDB's _id as the name so every channel is unique.
The problem I'm facing is that I cannot direct a message to a single client connection.
this is the client side code that first sends the message
$scope.sendMessage = function() {
specificChannel.send(message)
$scope.messageText = '';
};
this is the server side receiving the message
specificChannel.on('connection', function (conn) {
conn.on('data', function(message){
conn.write('message')
}
}
When I send a message, to any channel, every channel still receives the message.
How can I make it so that each client only listens to the messages sent to a specific channel?
It appeared that SockJS doesn't support "private" channels. I used the following solution for a similar issue:
var channel_id = 'my-very-private-channel'
var connection = new SockJS('/pubsub', '')
connection.onopen = function(){
connection.send({'method': 'set-channel', 'data': {'channel': channel_id}})
}
Backend solution is specific for every technology stack so I can't give a universal solution here. General idea is the following:
1) Parse the message in "on_message" function to find the requested "method name"
2) If the method is "set-channel" -> set the "self.channel" to this value
3) Broadcast further messages to subscribers with the same channel (I'm using Redis for that, but it also depends on your platform)
Hope it helps!

Pusher binding to events regardless of channel

I am attempting to listen to a particular event type regardless of the channel it was triggered in. My understanding of the docs (http://pusher.com/docs/client_api_guide/client_events#bind-events/lang=js) was that I can do so by calling the bind method on the pusher instance rather than on a channel instance. Here is my code:
var pusher = new Pusher('MYSECRETAPPKEY', {'encrypted':true}); // Replace with your app key
var eventName = 'new-comment';
var callback = function(data) {
// add comment into page
console.log(data);
};
pusher.bind(eventName, callback);
I then used the Event Creator tool in my account portal to generate an event. I used a random channel name, set the Event to "new-comment" and just put in some random piece of text into the Event Data. But, I am getting nothing appearing in my Console.
I am using https://d3dy5gmtp8yhk7.cloudfront.net/2.1/pusher.min.js, and performing this test in the latest Chrome.
What am I missing?
Thanks!
Shaheeb R.
Pusher will only send events to the client if that client has subscribed to the channel. So, the first thing you need to do is subscribe the channel. Binding to the event on the client:
pusher.bind('event_name', function( data ) {
// handle update
} );
This is also known as "global event binding".
I've tested this using this code and it does work:
http://jsbin.com/AROvEDO/1/edit
For completeness, here's the code:
var pusher = new Pusher('APP_KEY');
var channel = pusher.subscribe('test_channel');
pusher.bind('my_event', function(data) {
alert(data.message);
});

Resources