Configuring Topic Alias for MQTT 5.0 feature Using nodejs - node.js

I am trying to implemented shared topic concept using Nodejs code.
Now I am planning to implement Topic Alias using the Nodejs Code.
I have tried with below code but I didn't get proper out:
const mqtt = require('mqtt')
const clientThree = mqtt.connect('mqtt://192.168.x.xx:1883')
var options={
topicAliasMaximum:1,
};
clientThree.on('connect', () => {
let i = 0
clientThree.publish('test', "hello",options);
})

Shared topic is share topic prefix + topic like:
# single topic
t/#
# share topic
$queue/t/#
# or
$share/group1/t/#
Topic Alias is the property of MQTT 5.0, See mqtt.js properties options:
const client = mqtt.connect({
properties: {
topicAliasMaximum: 10
}
})
// Now sub topic and set the topic subscription id
client.subscribe('t/#', { properties: { subscriptionIdentifier: 2 } })
// Now using subscription id to publish
// wait me try..

Related

Cannot find documentation for botframework-connector functions examples

I'm using the botframework-connector npm package. And I want to use the sendOperationRequest & sendRequest methods from the ConnectorClient instance.
I have searched for the method examples here but can not find them.
Can anyone help me, please?
Edit:
I know how to use the create/update conversations via Conversations methods. I'm trying to scope whether I can use the package for other operations such as createChannel, add members to a group etc.
You should explore code samples in
https://github.com/microsoft/BotBuilder-Samples/tree/main/samples
rather than trying to understand how to use the SDK through the class references.
sendOperationRequest & sendRequest aren't really meant to be used explicitly, ConnectorClient uses it to send the request.
In order to send your message you first need a conversation reference (otherwise, how would the bot know which conversation to send the message to?) For example, look at the sample code on the documentation page of the NPM package you linked :
var { ConnectorClient, MicrosoftAppCredentials } = require('botframework-connector');
async function connectToSlack() {
var credentials = new MicrosoftAppCredentials('<your-app-id>', '<your-app-password>');
var botId = '<bot-id>';
var recipientId = '<user-id>';
var client = new ConnectorClient(credentials, { baseUri: 'https://slack.botframework.com' });
var conversationResponse = await client.conversations.createConversation({
bot: { id: botId },
members: [
{ id: recipientId }
],
isGroup: false
});
var activityResponse = await client.conversations.sendToConversation(conversationResponse.id, {
type: 'message',
from: { id: botId },
recipient: { id: recipientId },
text: 'This a message from Bot Connector Client (NodeJS)'
});
console.log('Sent reply with ActivityId:', activityResponse.id);
}
The botID and recipientID is dependent on the channel you use.
Edit : As I misunderstood the intent of the question.
If you want to create a channel, check out
https://github.com/howdyai/botkit/blob/main/packages/docs/core.md
There are officially supported channels with adapters that you can utilize. But if you are looking to connect to a custom app, look at https://github.com/howdyai/botkit/blob/main/packages/docs/reference/web.md#webadapter
for the generic web adapter that you can use to send and receive messages.

Sending Notification With Firebase Cloud Functions to Specific users

I am using firebase cloud function in my firebase group chat app, Setup is already done but problem is when some one send message in any group then all user get notification for that message including non members of group.
I want to send notification to group specific users only, below is my code for firebase cloud function -
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const _ = require('lodash');
admin.initializeApp(functions.config().firebase);
exports.sendNewMessageNotification = functions.database.ref('/{pushId}').onWrite(event => {
const getValuePromise = admin.database()
.ref('messages')
.orderByKey()
.limitToLast(1)
.once('value');
return getValuePromise.then(snapshot => {
const { text, author } = _.values(snapshot.val())[0];
const payload = {
notification: {
title: text,
body: author,
icon: ''
}
};
return admin.messaging()
.sendToTopic('my-groupchat', payload);
});
});
This will be really help full, if anyway some one can suggest on this.
As per our conversation on the comments I believe that the issue is that you are using a topic that contains all the users, which is the my-groupchat topic. The solution would be to create a new topic with the users that are part of this subtopic.
As for how to create such topics, there are a couple of examples in this documentation, in there you can see that you could do it server side, or client side. In your case, you could follow the examples for the server side, since you would need to add them in bulk, but as new users are added it could be interesting to implement the client side approach.

Add QnA users questions and answers to Insights telemetry in Node JS

I need to send QnA users questions and answers to my Azure bot insights using telemetry. Already tried this tutorial :
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=javascript
And this SO posts:
How to get the Qna Maker "Q" from Analytics Application Insights?
How can I save some custom qna maker data in azure app insights?
Thing is, first it's done for LUIS and gives no additional info to Insights, also nothing for QnA...second ones are written for C#...
I need to send question and answer to customEvents logs on Azure insights using NodeJS but I can't find how, any help ?
Thanks in advance.
///// EDIT:
Here's what I got so far (only posted the code related to the telemetry and QnA that's already working fine):
Index.js
const { ApplicationInsightsTelemetryClient, TelemetryInitializerMiddleware } = require('botbuilder-applicationinsights');
const { TelemetryLoggerMiddleware } = require('botbuilder-core');
function getTelemetryClient(instrumentationKey) {
if (instrumentationKey) {
return new ApplicationInsightsTelemetryClient(instrumentationKey);
}
return new NullTelemetryClient();
}
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
var telemetryClient = getTelemetryClient(process.env.InstrumentationKey);
var telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(telemetryClient);
var initializerMiddleware = new TelemetryInitializerMiddleware(telemetryLoggerMiddleware);
adapter.use(initializerMiddleware);
const mybot = new MYBOT(conversationState,userState, telemetryClient);
mybot.js
class MYBOT extends ActivityHandler {
constructor(conversationState,userState,telemetryClient) {
super();
this.conversationState = conversationState;
this.userState = userState;
this.telemetryClient = telemetryClient;
}
}
//This is how I get my qna result:
console.log(this.telemetryClient);
var result = await this.qnaMaker.getAnswers(context);
As You can see, I pass the telemetryClient to the bot file, and if I console log that item I get the complete telemetry object, but how I pass it the user question and answer so its save on insights customevents ??
Found a way to it, in case people that's looking for one of the possible solutions for Node may need it :
Basically, We use the same telemetry code process described in oficial documentation for instancing telemetry on index.js :
const { ApplicationInsightsTelemetryClient, TelemetryInitializerMiddleware } = require('botbuilder-applicationinsights');
const { TelemetryLoggerMiddleware } = require('botbuilder-core');
function getTelemetryClient(instrumentationKey) {
if (instrumentationKey) {
return new ApplicationInsightsTelemetryClient(instrumentationKey);
}
return new NullTelemetryClient();
}
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
var telemetryClient = getTelemetryClient(process.env.InstrumentationKey);
var telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(telemetryClient);
var initializerMiddleware = new TelemetryInitializerMiddleware(telemetryLoggerMiddleware);
adapter.use(initializerMiddleware);
const mybot = new MYBOT(conversationState,userState, telemetryClient);
Then, we pass it to the bot file (bot.js or the one you´re using):
class MYBOT extends ActivityHandler {
constructor(conversationState,userState,telemetryClient) {
super();
this.conversationState = conversationState;
this.userState = userState;
this.telemetryClient = telemetryClient;
}
}
And later in code, You can use telemetry.trackEvent method (Official docs are only in C#), but basically, it allows you to create a custom event you want to track in specifics events in your code, like when You're bot has an error or doesn´t found an answer to user. Code according to previous lines would be like this:
this.telemetryClient.trackEvent(
{name: "myEvent",
properties: {my_user_question: 'Context activity text here or your captured question',
my_bot_answer: 'bot reply or whatever'}
}
); // name and properties are part of the sintaxys, values inside properties object as you may need.
That way, on Azure insights customEvents model You will see records captured with the event name you used, also, with the properties objects as a dict in customdimensions field.

Sending proactive messages to a channel in Teams

So,
I searched far and wide, read everything I could find on the topic and I am still failing at this. I have managed to send proactive message to user, reply to a topic in team, etc. but I am unable to send a proactive message (create new post) in a team channel.
Is there an available example (I was unable to find any)? MS Docs for NodeJS seem to show an example of messaging each user in the team, but not the channel itself.
I explored the source code, and channelData is hardcoded to null inside botFrameworkAdapter.js, which only adds to the confusion.
So, basic code is:
const builder = require('botbuilder');
const adapter = new builder.BotFrameworkAdapter({
appId: 'XXX',
appPassword: 'YYY'
});
const conversation = {
channelData: {
//I have all this (saved from event when bot joined the Team)
},
...
// WHAT THIS OBJECT NEEDS TO BE TO SEND A SIMPLE "HELLO" TO A CHANNEL?
// I have all the d
};
adapter.createConversation(conversation, async (turnContext) => {
turnContext.sendActivity('HELLO'); //This may or may not be needed?
});
Has anyone done this with Node ? If so, can anyone show me a working example (with properly constructed conversation object)?
* EDIT *
As Hilton suggested in the answer below, I tried using ConnectorClient directly, but it returns resource unavailable (/v3/conversations)
Here is the code that I am using (it's literally only that, just trying to send demo message):
const path = require('path');
const { ConnectorClient, MicrosoftAppCredentials } = require('botframework-connector');
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
const serviceUrl = 'https://smba.trafficmanager.net/emea/';
async function sendToChannel() {
MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
var credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
var client = new ConnectorClient(credentials, { baseUri: serviceUrl });
var conversationResponse = await client.conversations.createConversation({
bot: {
id: process.env.MicrosoftAppId,
name: process.env.BotName
},
isGroup: true,
conversationType: "channel",
id: "19:XXX#thread.tacv2"
});
var acivityResponse = await client.conversations.sendToConversation(conversationResponse.id, {
type: 'message',
from: { id: process.env.MicrosoftAppId },
text: 'This a message from Bot Connector Client (NodeJS)'
});
}
sendToChannel();
What am I doing wrong?
Okay, so, this is how I made it work. I am posting it here for future reference.
DISCLAIMER: I still have no idea how to use it with botbuilder as was asked in my initial question, and this answer is going to use ConnectorClient, which is acceptable (for me, at least). Based on Hilton's directions and a GitHub issue that I saw earlier ( https://github.com/OfficeDev/BotBuilder-MicrosoftTeams/issues/162#issuecomment-434978847 ), I made it work finally. MS Documentation is not that helpful, since they always use context variable which is available when your Bot is responding to a message or activity, and they keep a record of these contexts internally while the Bot is running. However, if your Bot is restarted for some reason or you want to store your data in your database to be used later, this is the way to go.
So, the code (NodeJS):
const path = require('path');
const { ConnectorClient, MicrosoftAppCredentials } = require('botframework-connector');
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
const serviceUrl = 'https://smba.trafficmanager.net/emea/';
async function sendToChannel() {
MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
var credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
var client = new ConnectorClient(credentials, { baseUri: serviceUrl });
var conversationResponse = await client.conversations.createConversation({
bot: {
id: process.env.MicrosoftAppId,
name: process.env.BotName
},
isGroup: true,
conversationType: "channel",
channelData: {
channel: { id: "19:XXX#thread.tacv2" }
},
activity: {
type: 'message',
text: 'This a message from Bot Connector Client (NodeJS)'
}
});
}
sendToChannel();
NOTE: As Hilton pointed out, serviceUrl also needs to be loaded from your database, along with the channel id. It is available inside the activity which you receive initially when your Bot is added to team / channel / group along with channelId which you will also need, and you need to store those for future reference (do not hardcode them like in the example).
So, there is no separate createConversation and sendActivity, it's all in one call.
Thanks Hilton for your time, and a blurred image of my hand to MS Docs :)
Hope this helps someone else
(I'm replacing my previous answer as I think this fits the situation much better).
I've looked more into this and done a Fiddler trace to get you a more complete answer. I'm not a Node guy, so I'm not sure this will translate 100%, but let's see.
Basically, you're wanting to send to the following endpoint:
https://smba.trafficmanager.net/emea/v3/conversations/19:[RestOfYourChannelId]/activities
and you'll be posting a message like the following:
{
"type": "message",
"from": {
"id": "28:[rest of bot user id]",
"name": "[bot name]"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:[RestOfYourChannelId]"
},
"text": "Test Message"
}
However, to post to that endpoint, you need to authenticate to it properly. It's possible to do that, and communicate with the endpoint directly, but it's actually easier to just use the built-in mechanisms. This means getting and storing the conversationreference when the bot is first installed to the channel. This file shows how to do that (see how it gets and stores the conversationReference in the this.onConversationUpdate function). In that same sample, in a different file, it shows how to use that conversation reference to actually send the pro-active message - see here, where it uses adapter.continueConversation.
One of the Microsoft bot team members also shows this in similar detail over here. He also adds MicrosoftAppCredentials.trustServiceUrl(ref.serviceUrl); which can be necessary under certain circumstances (if you're having security issues, give that a try).
That -should- cover what you need, so give it a go, and let me know if you're still having difficulties.

Sending message to a specific group of subscriber in azure service bus topic with masstransit

I'm new to azure service bus and masstransit. I'm looking for a solution to a specific situation.
I have a azure service bus topic with multiple subscribers. Subscriber will receive message based on filters. I've created the topic and subscriber with code below
class Program
{
static void Main(string[] args)
{
string connectionString = "Endpoint connection string";
// the names of topics and subscriptions we'll be working with
const string topicName = "MyTestTopic";
const string allMessagesSubName = "AllMessages";
const string filteredSubName1 = "Filtered1";
const string filteredSubName2 = "Filtered2";
// let's create the topic if it doesn't already exist...
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.TopicExists(topicName))
{
var td = new TopicDescription(topicName);
namespaceManager.CreateTopic(td.Path);
}
if (!namespaceManager.SubscriptionExists(topicName, allMessagesSubName))
{
namespaceManager.CreateSubscription(topicName, allMessagesSubName);
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName1))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName1),
new Microsoft.ServiceBus.Messaging.SqlFilter("From LIKE '%Smith'"));
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName2))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName2),
new Microsoft.ServiceBus.Messaging.SqlFilter("sys.Label='important'"));
}
var message1 = new BrokeredMessage("Hello World");
var message2 = new BrokeredMessage("Second message");
message2.Label = "important";
var message3 = new BrokeredMessage("Third message");
message3.Properties["From"] = "Kelly Smith";
message3.Label = "information";
var client = TopicClient.CreateFromConnectionString(connectionString, topicName);
client.Send(message1);
client.Send(message2);
client.Send(message3);
client.Close();
}
}
Here in the code we're adding Message custom properties like From.
Now I want to send such message using masstransit. In masstransit I cannot find any option of adding Message custom properties using the Publish() method. Is there any way that I can send these messages using masstransit where these filters can be used?
NB: I've read the answer of this question But the anwer here tells us to filter the messages in subscriber side. What I want is that this filtering will occur before reaching the subscriber.
When using Azure Service Bus with MassTransit, you can add subscription endpoints in additional to regular endpoints. When configuring a subscription endpoint, you should be able to specify rules and/or filters as part of the subscription. Which is exactly what you're doing above, so that is handled.
The other part, adding properties to the message, can be done by adding text headers to the SendContext. Those headers are copied to the message Properties collection, which I believe can be used to filter messages using a "SQL" filter (which is configured on the subscription endpoint, or the topic subscription on a receive endpoint).

Resources