Strophe JS subscribe callback gets called only once - xmpp

I am using Strophe JS & Openfire to do simple pubsub.
Setup :
OS: Windows 7
Openfire : 3.7.0
Strophe JS,Strophe plugin for pubsub.
Tomcat 6:Serving webpage
Use case:
Two browser Window with two different user session(xmpp session)
Firefox(user1)---->Publisher
Chrome(user2)---->Subscriber
Code:
//XConn represents Strophe Connection
//creating PUBSUB NODE (Firefox)
XConn.pubsub.createNode(
XConn.jid,
'pubsub.localhost',
'PUBSUB_NODE',
{},
function (){
}
);
//Adding subscriber to created node (Chrome)
XConn.pubsub.subscribe(
XConn.jid,
'pubsub.localhost',
'PUBSUB_NODE',
[],
function(msg){ console.log(msg);},
function(sub){ }
);
//publishing item to node (Firefox)
XConn.pubsub.publish(XConn.jid,'pubsub.localhost','PUBSUB_NODE',[ '<item><book xmlns="pubsub:test:book"><title>Book1</title></book></item>']);
XConn.pubsub.publish(XConn.jid,'pubsub.localhost','PUBSUB_NODE',[ '<item><book xmlns="pubsub:test:book"><title>Book2</title></book></item>']);
I am expecting that both the messages published by publisher(firefox) should get printed on chrome(subscriber) console. But it just prints the first one, looks like Subscribe-callback gets called only once.

I figured out the problem with subscription call back.
Strophe JS plugin(pubsub) requires to return 'true' from callback if interested to get more triggers.
So changing call-back to return true worked.
Code change to above snippet :
//Adding subscriber to created node (Chrome)
XConn.pubsub.subscribe(
XConn.jid,
'pubsub.localhost',
'PUBSUB_NODE',
[],
function(msg){ console.log(msg); return true; },
function(sub){ return true;}
);

Related

Why does Pusher update the UI only after navigating to another tab?

I used pusher to add real-time updates to my web app. Like if a user hits the like button on a post, the number of likes increases instantaneously in the UI.
That works fine when I run the app locally (illustrative GIF).
But when I deployed the app to Vercel, Pusher doesn't update the UI, unless I navigate to another tab and then return back to my app tab (GIF).
Vercel logs show that everything works as expected. The React component subscribes properly to Pusher channel and gets the new data. However, the UI never updates while I'm viewing the tab.
// Setting up pusher
import Pusher from "pusher";
const pusher = new Pusher({
appId: PUSHER_APP_ID,
key: PUSHER_KEY,
secret: PUSHER_SECRET,
cluster: us2,
useTLS: false,
});
export default pusher;
// Subscribing the component to Pusher channel
useEffect(
function subscribeToPusher() {
const pusher = new Pusher(PUSHER_KEY, {
cluster: us2,
forceTLS: true,
});
const channel = pusher.subscribe("reviews");
channel.bind("updated", updateReview);
},
[]
);
// Listen to MongoDB's ChangeStream
changeStream.on("change", async (change) => {
console.log("change: ", change);
switch (change.operationType) {
case "update": {
const document = change.fullDocument;
pusher.trigger(collectionName, "updated", document);
break;
}
}
});
Note: the deployed version works as expected when I run npm run dev locally which is a bit strange.
It was Vercel. It worked once I tried Heroku.

WebSockets won't Send data from Vue app - error states 'send' is undefined, Stack: Vue Express Mongo WebSockets

Here is my code that is not working:
connectSocket: function () {
this.socket = new WebSocket('ws://144.0.0.0:8080'); //IP Changed
this.socket.onopen = function(event) {
console.log("Connected to the Web Socket Server");
this.socket.send("Opponent has joined.");
};
alert("You're now connected to the server. Be careful out there.");
this.socket.onmessage = function(event) {
console.log("Message Received From Server :", event);
//This is the time to interact with this specific
};
}
The code I am referencing is a method in my vue called upon authentication. I am merely trying to send and receive basic data to the Web Socket Server. However somewhere this is flawed... How could I fix this and maintain authentication?
Your event handlers are losing context (this) when declared. Use arrow functions to preserve the current context, so the this there references the Vue instance:
connectSocket: function () {
this.socket = new WebSocket('ws://144.0.0.0:8080'); //IP Changed
this.socket.onopen = (event) => { // changed to arrow function
console.log("Connected to the Web Socket Server");
this.socket.send("Opponent has joined.");
alert("You're now connected to the server. Be careful out there.");
};
this.socket.onmessage = (event) => { // changed to arrow function
console.log("Message Received From Server :", event);
//This is the time to interact with this specific
};
}
Also it seemed you had unbalanced curly brackets, so I changed them too. But the important part is really the use of arrow functions.

Kill the page from loading feather

I am using Ionic 2 and would like to kill the page from feather loading similar to PHP die(); function
Below is the method that I currently working with.
fetch_data() {
let loader = this.loadingCtrl.create({ content: 'Loading...' });
loader.present();
this.bank.types().subscribe( response => {
this.linkBankTypes = response.results;
loader.dismiss();
}, err => {
loader.dismiss();
loader = this.loadingCtrl.create({ content: 'No Internet connection. Make sure Wi-Fi or cellular data is turned on, then try again.' });
//Kill the page from here
});
}
PHP's die() function stops creation of the page and lets PHP run environment to return a nasty error message to the client browser.
You can cause the Ionic to crash by throwing exceptions, but that is not a pleasant user experience and not recommended.
Instead you either navigate to an error page or show a message indicating the error.
The NavController's push or popcan be used to navigate to an error page or back to the previous page.

Ionic Worklight Page not displaying after HTTP request

I'm having an issue displaying the content in the page after the Worklight http request has been executed.
The weird thing is that when I go to another page and I come back, the content gets displayed. It's like if it needs to be refreshed or something. I can see the console.log() data was received, but page was not refreshed.
This is my code:
$stateProvider.state('accounts', {
url: "/accounts",
templateUrl: 'views/accounts.html',
controller: function($scope, $ionicScrollDelegate, $rootScope){
var req = new WLResourceRequest("/adapters/JavaMQ/bankmq/getAccounts/"+$rootScope.globalReqUserId, WLResourceRequest.GET);
req.send().then(function(resp){
var x2js = new X2JS();
resp.responseText = x2js.xml_str2json(resp.responseText); //to JSON
$scope.reqUserId = resp.responseText['ASI_Message']['Riyad_Bank_Header']['Requestor_User_ID'];
$scope.accountsList = resp.responseText['ASI_Message']['Repeating_Group_Section']['Repeating_Group'];
console.log($rootScope);
})
}
});
UPDATE:
I noticed that I also keep getting the following when I moved the project to Windows (Never happened in my mac)
Deviceready has not fired after 5 seconds
Channel not fired: onCordovaInfoReady
Channel not fired: onCordovaConnectionReady
I don't really know Worklight but the documentation indicate that the send().then() handles both the onSuccess and onFailure.
Maybe the then() is expecting 2 parameters like this:
var request = WLResourceRequest(url, method, timeout);
request.send(content).then(
function(response) {
// success flow
},
function(error) {
// fail flow
}
);
If that doesn't work, can you put a breakpoint at the start of var x2js = new X2JS(); and tell us what happens?

jQuery live with the ready or load event

I'm using the jQuery Tools tooltip plugin, which is initialized with $('selector').tooltip(). I'd like to call this on any current or future .tooltipper element. I figured that the following would work:
$('.tooltipper').live('ready', function(){
$(this).tooltip()
}
But it was unsuccessful---the ready event did not fire. The same for load. I've read that livequery can produce the result of I'm looking for, but surely there is a way to use jQuery .live() to pull it off, considering the documentation says that it works for all jQuery events, of which I believe ready is one.
Quoted from the jQ API (http://api.jquery.com/live/):
In jQuery 1.3.x only the following JavaScript events (in addition to custom events) could be bound with .live(): click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events.
As of jQuery 1.4.1 even focus and blur work with live (mapping to the more appropriate, bubbling, events focusin and focusout).
As of jQuery 1.4.1 the hover event can be specified (mapping to "mouseenter mouseleave").
.live() does not appear to support the ready event.
To add to HurnsMobile's excellent answer; Looking at bindReady(), which is the internal call that jQuery makes to bind to the document load event every time you call $(some_function) or $(document).ready(some_function) we see why we cannot bind to "ready":
bindReady: function() {
if ( readyBound ) {
return;
}
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", DOMContentLoaded);
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) { //and silently drop any errors
}
// If the document supports the scroll check and we're not in a frame:
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
To sum it up, $(some_function) calls a function which binds to:
DOMContentLoaded
onreadystatechange (DOMContentLoaded)
window.load / onload
Your best bet would be to bind to those actions that might create new .tooltipper elements, rather than trying to listen for the ready event (which happens only once).
HurnsMobile is right. JQuery live does not support the ready-event.
This is why I created a plugin that combines the two. You register your callback once, and then you will need to call the plugin once for content you add manually.
$.liveReady('.tooltipper', function(){
this.tooltip()
});
Then when creating new content:
element.html(somehtml);
element.liveReady();
or
$('<div class="tooltipper">...').appendTo($('body')).liveReady();
A demo is available here: http://cdn.bitbucket.org/larscorneliussen/jquery.liveready/downloads/demo.html
Check out the introductory post here: http://startbigthinksmall.wordpress.com/2011/04/20/announcing-jquery-live-ready-1-0-release/
Also have a look at http://docs.jquery.com/Plugins/livequery, which listenes for changes on the dom.