Quickblox: Message Delivered and Read Status - javascript

I have implemented quickblox chat in my web application. Now I want to show status of my messages as delivered in case when they are just sent to user and as read when they have seen the message.
In your Javascript SDK I have found two functions QB.chat.sendDeliveredMessage and QB.chat.sendReadMessage but every time I call this function as :
QB.chat.sendDeliveredMessage(
QBChatHelpers.getJID(chatUser.id),
"5600f885a28f9ac7e801048c" //this is just a sample msg-id
);
It calls ajax with POST request over url http://chat.quickblox.com:8080/ while chat is running over http://chat.quickblox.com:5280/.
Also within library, I changed the port to 5280 in place of 8080 so that it can call url with port 8080 and it calls http://chat.quickblox.com:5280/ which then gives error code 405: Invalid Hostname.
Please let me know what's wrong am I doing while calling this function. If further information is required then do let me know.

We are working on this feature, in the new version of QuickBlox JS SDK messages will be sent with the markable status.
sendDeliveredStatus(params)-will be sent automatically after receiving a message with markable status, which will signalize via the function of Listener QB.chat.onDeliveredStatusListener(messageId, dialogId, userId);
sendReadStatus(params)-will be possible to send it according to an event (for example, you set up a processor, which will notice that a message has already appeared on yours monitor, after receiving a message with markable status, which will signalize via the function of Listener QB.chat.onReadStatusListener(messageId, dialogId, userId);)
parameters for status sending:
params = {
messageId: messageId,
userId: userId,
dialogId: dialogId
};

Thanks guys, this page helped me a lot.
When a message is sent could be 2 options:
A. You are the sender and another user is the addressee: YOU --> ANOTHER-USER
B. You are the addressee and another user is the sender: ANOTHER-USER --> YOU
OPTION A:
Send your message to the addressee with "markable=1" flag.
For example:
var params = {
chat_dialog_id: "56b20540f583bb7bcb00rrr6",
message: msg),
send_to_chat: 1,
markable: 1,
extension: {
save_to_history: 1
}
};
// SEND THE MESSAGE
QB.chat.message.create(params, function (err, res) {});
Add QB listener to be trigger after the addressee user had read the message:
QB.chat.onReadStatusListener = updateReadersList;
And then add such a function with this signature:
function updateReadersList(messageId, dialogId, userId){
console.log('userId has read your messageId that in dialogId');
}
OPTION B:
Add QB listener to handle new incoming messages:
QB.chat.onMessageListener = showMessage;
Add such a listener function with this signature:
In that listener you can notify the sender that his message was recived an d read (by you):
function showMessage(userId, msg) {
console.log('userId sent you this msg');
//notify sender: message was read:
if(userId != "MY-USER") {
sendReadSignalToSender(msg, userId);
console.log("You notified userId that his msg was read.");
}
}
Adding a simple function for just passing params to QB.chat.sendReadStatus function:
function sendReadSignalToSender(dialogMsg, senderId){
var params = {
messageId: (dialogMsg.id || dialogMsg._id),
userId: senderId,
dialogId: (dialogMsg.dialog_id || dialogMsg.chat_dialog_id)
};
QB.chat.sendReadStatus(params);
console.log("senderId was notified that his dialogMsg was read.");
}

Related

How do I send messages to RabbitMQ Queue, using nodejs

I am currently building a load balancing tool to take different stress measurements of how servers handle http protocol requests. Currently, I can send just a ton, but I cannot process them all. That is why I am looking to put it all into a message queue like rabbit, using AMQP.
My current code https://github.com/yugely/Stork
I am currently using an event loop and a timeout to adequately do what I am intending to accomplish.
I want to use RabbitMQ by using one of my current loggers to "emit" a message into the message queue. I don't know how to modularize it so I don't have to constantly create channels as all the tutorials seem to just copy paste each other without going into how to use it in external files.
I'm hoping someone can either lead me to what I may be duping. I'm unsure of how to even ask this question. I have been looking at RabbitMQ and AMQP to handle a message queue for a project. The issue I am facing is that I don't know how to send a message to rabbit mq. Let me illustrate what I am understanding by doing a copypasta of the first tutorial on the rabbitmq site:
send.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
var msg = 'Hello World!';
channel.assertQueue(queue, {
durable: false
});
/*
How do I do this outside the functions so receive gets it? How can I call a method/function to send a message to an existing queue through an existing channel?
*/
channel.sendToQueue(queue, Buffer.from(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() {
connection.close();
process.exit(0);
}, 500);
});
receive.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
channel.assertQueue(queue, {
durable: false
});
console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue);
/*
How do I set up a consumer outside this function?
*/
channel.consume(queue, function(msg) {
console.log(" [x] Received %s", msg.content.toString());
}, {
noAck: true
});
});
});
For the sender, do I just always create a new channel for every message?
All the tutorials accept arguments when you run the "node" terminal command. The only way I can currently see this working is to use the "child process" library, but that would be bad news bears right? As wouldn't that create another nodejs cluster?
If I have to use a client to send messages, am I able to use axios? (I've seen some people claiming they are able to but I don't know for sure). Since it will be using the amqp protocol, what is the amqp client?
Or are these queues like instantiated in the entry file? Like you set up the queue when you run your entry point command and then allow the different "events" to send messages to the queue?
How can I modularize this?
Just to illustrate, here is my current axios code
RadioFlyer.js
await axios(flight.journal.actions[modkey]).then(function (response) {
reaction.key.type = messageType.HTTPResponse.Okay
reaction.message = response === undefined ? response : "no response"
let smaug = typeof reaction.message.status === "undefined" ? reaction.message : reaction.message.status
flight.journal.reactions.push(reaction)
let pulse = {
id: flight.id + "-" + index,
timestamp: Date.now(),
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Okay,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
/*
Can I emit a messaging event to my logger
*/
//emit
seidCar.HTTPLogger.emit("logHttp", reaction)
//emit
seidCar.HeartbeatLogger.emit("pulse", pulse)
}).catch(function (error) {
reaction.key.type = messageType.HTTPResponse.Error
reaction.message = error.response === undefined ? error.code : error.response
let smaug = typeof reaction.message.status === "undefined" ? reaction.message : reaction.message.status
let pulse = {
id: flight.id + "-" + index,
timestamp: Date.now(),
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Error,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
let err = {
id: flight.id+"-"+index+"-ERROR",
timestamp : Date.now(),
fatal : false,
potentialFix : "Examine Http Call with id: " + flight.id + "-" + index,
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Error,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
flight.journal.reactions.push(reaction)
//emit
seidCar.HTTPLogger.emit("logHttp", reaction)
//emit
seidCar.ErrorLogger.emit("logError", err)
//emit
seidCar.HeartbeatLogger.emit("pulse", pulse)
})
And have my logger handler the sending to the queue?
HTTPLogger.js
/*
Can I now send the message to the queue here, in this file?
*/
const HTTPEventLogger = require("events")
const emitter = new HTTPEventLogger()
const errorEmitter = require("./ErrorLogger").Emitter
class HTTPLogger extends HTTPEventLogger {
logHttp(message) {
switch (message.key.type) {
case "ERROR":
if (message !== undefined) {
console.log(message)
} else {
errorEmitter.emit("tossIt", {
error:"HTTP error Message is undefined in ~/Homestasis/Agent/HTTPLoggerjs.",
poi:"check for recent additions to pilot agents in ~/Pilots/Agent",
timestamp: Date.now(),
potentialFix:"look to where you are emitting the message. Function Scope"
})
}
break;
case "OKAY":
if (message !== undefined) {
console.log(message)//bState.message.status)
} else {
errorEmitter.emit("tossIt", {
error:"HTTP okay Message is undefined in ~/Homestasis/Agent/HTTPLoggerjs.",
poi:"check for recent additions to pilot agents in ~/Pilots/Agent",
timestamp: Date.now(),
potentialFix:"look to where you are emitting the message. Function Scope"
})
}
break;
default:
errorEmitter.emit("tossIt", "this is a tossIt error log. No http key type was caught bSate = " + bState)
}
}
}
var logger = new HTTPLogger()
emitter.on("logHttp",logger.logHttp)
exports.Emitter = emitter
Thats how I'd like to send the message.
I'd like to be able to receive it much the same way
I'm not sure how to implement it given how I perceive it currently working and I am missing a key part of the equation. Thank you for your time!
I decided to not use RabbitMQ.
For node, RSMQ is what I am going with. I realized I fundamentally needed to shift how I viewed message queues working practically to get them to work practically. I am using RSMQ, as I can understand how it fits into how I built my project out. I was going with ZeroMQ at first (I still may, the pliability of sockets on steroids). But, I do like the actual features and stuff when I actually think about using it like a "mainline nerve".
The way I want to build it out goes as such:
Axios Makes the call, fires off an event to the httplogger which fires off an event to the message queue. So:
RadioFlyer.js > HttpLogger.js > RSMQ-Messagequeue.js > next things > and next...
RSMQ-Messagequeue.js acts as a "middle man" or an intermediary to put the stops on the wheels when overloaded.
The pros of RSMQ is that I also intend to implement a Redis Cache (I could implement ZeroMQ and do much the same), but I like that RSMQ allows for more queue options, instead of 1 queue with many topics.
There is a more fleshed out answer.

Strophe.js on-message handler doesn't trigger

The Strophe onMessage handler that I added to the connection doesn't seem to trigger whenever a message gets send. I can't seem to find the problem. I can't find a lot of other info either and the info I do find seems to suggest my code is correct. I can send messages, so I know the connection works, but I cannot receive messages.
I create the connection like this, and then call the login function if a new connection is made:
XMPPChatConnection() {
if (this.#connection === undefined) {
this.#connection = new XMPPHelper.Strophe.Connection(
"wss://xxxxxxxxxxxxxxxxxxxxxxx",
{protocol: "wss"}
);
this.login();
}
return this.#connection;
}
The login function calls the chatListeners function which should setup all the listeners that are required when the user is logged in:
login() {
let jid = this.composeJabberIdentifier();
let token = this.getXMPPToken();
this.#connection.connect(jid, token, (status) => {
if (status === XMPPHelper.Strophe.Status.CONNECTED) {
this.chatListeners();
}
});
}
The messageListener is an imported function and currently only contains a console log:
import messageListener from "../classes/listeners/xmpp/chat/messageListener";
chatListeners() {
this.XMPPChatConnection().addHandler(messageListener, null, 'message', 'chat');
}
messageListener:
export default function messageListener(message) {
console.log(message);
}
What did I do wrong?
So I found the cause of my problems. I was using the Xabber client to send messages back, but it turned out Xabber sent the messages to the wrong resource.
On top of that I should have set my presence after login with a priority of >= 0.
this.XMPPChatConnection().send($pres().c("priority").t("0"));

How to get variable on submit mongodb and meteor

So I am working on a wait list type application. When a user submits their information into the list (using autoform) they should be sent a messsage through the Twilio service.
I currently have a hard coded variable working with twilio
Method to send sms
Meteor.methods({
sendSMS: function (phoneNumber) {
var authToken = 'token value here';
var accountSid = 'sid value here';
twilio = Twilio(accountSid, authToken);
twilio.sendSms({
to: phoneNumber, // Any number Twilio can deliver to
from: '+18.....', // A number you bought from Twilio and can use for outbound communication
body: 'You have been added to the waitlist' // body of the SMS message
}, function (err, responseData) { //this function is executed when a response is received from Twilio
if (!err) { // "err" is an error received during the request, if any
// "responseData" is a JavaScript object containing data received from Twilio.
// A sample response from sending an SMS message is here (click "JSON" to see how the data appears in JavaScript):
// http://www.twilio.com/docs/api/rest/sending-sms#example-1
console.log(responseData.from); // outputs "+14506667788"
console.log(responseData.body); // outputs "word to your mother."
}
});
}
});
Here is the event I have working with hard coded number:
Template.home.events({
"submit #student-form": function(event) {
event.preventDefault();
var phoneNumber = '+18.....';
Meteor.call("sendSMS", phoneNumber);
// alert("You have been added to the WaitList");
swal("Success!", "You have been added to the WaitList", "success")
}
});
My quickform
{{>quickForm id="student-form" collection="Students" type="insert" template="bootstrap3-horizontal" label-class="col-sm-3" input-col-class="col-sm-9"}}
What I want to know is how do I get the phone number value that was just submitted into the mongodb collection so that I can send a message to that specific phone number with twilio?
OP found the answer here: Find Value in Meteor Mongo
If you are looking to retrieve a field out of the returned document,
you can specify as much using the fields option:
database.findOne({}, {sort: {'timeStamp' : -1}, limit:1, fields: {'myField': 1, _id: 0})
That will retrieve an object in format like this:
{'myField': 'value of myField'}

Quickblox sigBytes error - authentication for chat

Another quickblox question - I am getting the following error when trying to run my application:
Uncaught TypeError: Cannot read property 'sigBytes' of undefinedquickblox.js:10707 c.HMAC.i.extend.initquickblox.js:10703 i.Hasher.a.extend._createHmacHelperquickblox.js:101 signMessagequickblox.js:35 createSessionquickblox.js:867 QuickBlox.createSessionchat.html:122 (anonymous function)
This error prevents successful authentication of the user. The code being executed is below(insecure as hell - proof of concept only!):
var chatToUser = window.localStorage.getItem("chatToUser");
var username = window.localStorage.getItem("user");
var password = window.localStorage.getItem("pwd");
var params = {login:username,password:password};
console.log("PARAMS: ",params);
$(document).ready(function(){
var chatService = new QBChat(params);
});
// JavaScript SDK initialization
QB.init(QBAPP.appID, QBAPP.authKey, QBAPP.authSecret);
// QuickBlox session creation
QB.createSession(params, function(err, result) {
if (err) {
console.log("ERROR:", err.detail);
} else {
chatUser = {
id: result.user_id,
pass: params.password
};
connectChat();
}
});
function connectChat() {
chatService = new QBChat({
onConnectFailed: onConnectFailed,
onConnectSuccess: onConnectSuccess,
onConnectClosed: onConnectClosed,
onChatMessage: onChatMessage
});
console.log("Chat Service: ", chatService);
console.log("Chat User: ", chatuser);
// connect to QB chat service
chatService.connect(chatUser);
}
/* Callbacks
------------------------------------------------------*/
// Connection is failed
function onConnectFailed() {
alert("We're having some difficulty talking to the server. Please try again later, or get in touch if th eproblem persists.")
}
// Connection is success
function onConnectSuccess() {
//green dot - live - status
alert("Connected.")
}
// Connection is closed
function onConnectClosed() {}
What do i need to do differently in order to successfully log the user in for chat?
If it helps, I have previously generated a session for them based on their 'user' credentials (username/password). Is it possible to simply reuse this session instead of creating a fresh one?
It just hit me! (adding a few console.logs helped...)
The app is looking for QBAPP.(etc) and the case/underscore formatting of those parameters did not line up after copying from an examples, hence the 'undefined'-s coming back and the sigbytes thingy falling over itself. So note to anyone else having this error - check your code carefully, for case and style before nagging the community with stupid questions!
I hope someone might learn from this.

Wait for callback to finish on during pubnub history() call on client reconnect

I have two channels for my subscribers: Broadcast and Unique channel. On the Broadcast channel I have all the Subscribers listening to. The Unique channel is for One-To-One communication between the Publisher and the Subscriber.
I need to achieve the following solution: If the Subscriber goes offline/loses connection, after he comes back online he needs to poll the two channels for the single latest message on each of them and determine if the message is still valid based on the property in the message object:
//HERE IS THE MESSAGE OBJECT THAT THE PUBLISHER SENDS ON THE BROADCAST AND THE UNIQUE
//CHANNELS TO THE SUBSCRIBERS.
message = {
alarm: null, //BOOLEAN: DESIGNATES IF THE ALARM IS ON/OFF
body: null, //STRING: SOME MESSAGE/ALARM TEXT
image: null, //STRING: SOME IMAGE IF YOU WANT TO APPEAR WITH THE ALARM TEXT
createdAt: null, //UNIX TIMESTAMP OF WHEN THE MESSAGE WAS CREATED/SENT
validUntil: null //UNIX TIMESTAMP - AFTER THIS PERIOD THE MESSAGE IS CONSIDERED INACTIVE AND THE SUBSCRIBER SHOULD IGNORE THIS MESSAGE ON RECONNECT
};
Here is my sample code for the Subscriber(The problem is marked in the comments in the code):
$(document).ready(function(){
var uuid = PUBNUB.uuid(),
id = 'vlatkorun-' + uuid,
controlChannel = 'vlatkorun-control',
broadcastChannel = 'vlatkorun-broadcast',
uniqueChannel = 'vlatkorun-unique-';
var state = {
id: id,
uniqueChannel: uniqueChannel
};
//INIT PUBNUB
var pubnub = PUBNUB.init({
subscribe_key : 'YYY',
keepalive: 30
});
//SUBSCRIBE TO THE CONTROL CHANNEL FIRST
//THE CONTROL CHANNEL IS FOR MAINTENANCE BETWEEN PUBLISHER
//AND THE SUBSCRIBERS
pubnub.subscribe ({
channel: controlChannel,
message: function(m){console.log(m)},
state: state,
heartbeat: 30,
connect: function(m){/*console.log(JSON.stringify(m))*/},
reconnect: function(m){console.log(JSON.stringify(m))}
});
//NOW SUBSCRIBE TO THE BROADCAST AND THE UNIQUE CHANNELS
pubnub.subscribe ({
channel: [broadcastChannel, uniqueChannel],
state: state,
message: function(data){
//SHOW THE ALARM IN THE BROWSER WHEN MESSAGE ARRIVES
//OUTPUT OMMITED
},
connect: function(m){
//THIS ARRAY IS GOING TO HOLD THE LATEST MESSAGES FROT THE BOTH CHANNELS
var channelLatestMessages = [];
//GET THE MOST RECENT MESSAGE ON THE BROACAST CHANNEL
pubnub.history({
channel: broadcastChannel,
count: 1,
callback: function (m) {
if(m[0].length > 0)
{
//GO OVER THE RETURNED MESSAGES AND PUT THEM IN THE ARRAY FOR COMPARING LATER
$.each(m[0], function(index, value){
channelLatestMessages.push(value);
});
}
//I HAVE THE VARIABLE POPULATED WITH THE MESSAGES FROM THE CHANNEL IN THE CALLBACK
console.info(channelLatestMessages);
},
});
//GET THE MOST RECENT MESSAGE ON THE UNIQUE CHANNEL
pubnub.history({
channel: uniqueChannel,
count: 1,
callback: function (m) {
if(m[0].length > 0)
{
//GO OVER THE RETURNED MESSAGES AND PUT THEM IN THE ARRAY FOR COMPARING LATER
$.each(m[0], function(index, value){
channelLatestMessages.push(value);
});
}
//I HAVE THE VARIABLE POPULATED WITH THE MESSAGES FROM THE CHANNEL IN THE CALLBACK
console.info(channelLatestMessages);
},
});
//I HAVE THE VARIABLE POPULATED WITH THE MESSAGES FROM THE CHANNEL IN THE CALLBACK, BUT HERE THE ARRAY IS EMPTY BECAUSE THE CALLBACKS ARENT
//FISHED.
//HERE IS MY QUESTION: HOW CAN I WAIT FOR THE CALLBACKS TO FINISH SO I CAN CONTINUE WITH MY CODE BELLOW???
console.info(channelLatestMessages);
//IF THERE ARE NO MESSAGES DO NOTHING
if(channelLatestMessages.length == 0) return;
//ASSUME THAT THE FIRST MESSAGE IN THE ARRAY IS THE MOST RECENT
latestMessage = channelLatestMessages[0];
//NOW FIGURE OUT THE MOST RECENT MESSAGE
$.each(channelLatestMessages, function(index, message){
if(latestMessage.createdAt < message.createdAt)
{
latestMessage = message;
}
});
//GET THE CURRENT DATE IN UNIX TIMESTAMP
var currentDate = parseInt(moment().format('X'));
//CHECK IF THE MESSAGE VALIDITY IS EXPIRED
if(currentDate > latestMessage.validUntil) return;
//HERE WE CAN SHOW THE LATEST MESSAGE IN THE BROWSER
//OUTPUT OMMITED
},
reconnect: function(m){//THE SAME LOGIN LIKE IN THE CONNECT METHOD APPLIES HERE}
});
});
How to wait for the callbacks to finish so I can have the channelLatestMessages filled with the latest messages from the Broadcast and Unique channels so I can further determine which message is more recent and if the more recent message is still active?
Can your logic run like this:
historyCall-1's callback calls historyCall-2.
historyCall-2's callback calls "Message Age Detection" logic.
This way, we make the async act synchronously, and the only way "Message Age Detection" logic runs is if we know for a fact that history calls 1 and 2 are complete.
?
geremy

Categories