Firebase disconnects on cordova pause - javascript

A pretty major problem for my app is that roughly 50% of launches have no Firebase connection unless the app is paused. So I would:
Launch the app to have no data loaded
Pause it to load the data on the current page
Resume it to see the data.
Repeat step 2 and 3 each time I need data sent or received
code:
var onPause = function(){console.log("paused");}
var onResume = function(){console.log("resumed");}
document.addEventListener("pause", onPause, false);
document.addEventListener("resume", onResume, false);
var connectionRef = new Firebase(FB + "/.info/connected");
connectionRef.on("value", function(snap){
if(snap.val() == true){
console.log("connected -------[]------");
} else {
console.log("not connected --------[ ]------------");
}
});
logs:
resumed
not connected --------[ ]------------
paused
connected -------[]------
resumed
not connected --------[ ]------------
paused
connected -------[]------
The reason it works half the time is because it also works the opposite way, which I assume is the intended way. Is there any way to prevent it from disconnected at all? or alternatively force it to connect on resume?

I found the cause to the problem - It was a plugin called phonegap-plugin-push. When it registers for GCM it causes Firebase to go offline (or online if paused).
I still haven't found a genuine solution, but as a hack fix I have a timer on registering for GCM so the data can load initially before the disconnecting happens. After that it relies on the user not using the app for extended periods of time so it can pause to sync up on a regular basis.

Related

Period background sync does't fire after successfully registered

I'm trying to make periodic bg sync where service worker updates badge.
When I run my page and test it via Chrome DevTools, Service worker process the request. But when the page is closed, it doesnt't do anything. Same on mobile phone.
On my page (this part is working and output in console is periodic update set):
navigator.permissions.query({name:'periodic-background-sync'}).then(function(result) {
if (result.state === 'granted') {
console.log('periodic background granted');
navigator.serviceWorker.ready.then(function(registration){
if ('periodicSync' in registration) {
try {
registration.periodicSync.register('update-badge', {
minInterval: 60 * 60 * 1000,
}).then(function(ret){
console.log('periodic update set');
});
} catch (error) {
console.log('Periodic background sync cannot be used.');
}
}
});
}
});
Service worker:
async function updateBadge() {
const unreadCount = 5; //fixed value for testing
navigator.setAppBadge(unreadCount).catch((error) => {
console.log('Error setting badge.');
});
}
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'update-badge') {
event.waitUntil(updateBadge());
}
});
So when I manually fire background sync from DevTools, badge is set, but not automatically in the background as I thought it will work.
I can't find anything wrong with the code. I've seen variants where you request periodic-background-sync after navigator.serviceWorker.ready but I think that both work (especially since you can trigger the registered event manually).
I think the problem is that not all conditions for periodic background sync to fire are true. These are the conditions from the initial implementation in Chrome (2019):
Chrome version 80 or later
The PWA needs to be installed
The website needs to have an engagement score (can be viewed here chrome://site-engagement/). Websites with 0 engagement is deleted from the list and won't trigger the periodicsync event, even if it is installed. Once a user hasn’t interacted with a website for 2 hours, its engagement levels begin to decay. With minimal engagement, a periodicsync event will be triggered at an interval of 36h. source
In your case I think your code is correct and working but you haven't interacted enough with you app continuously over 36h so the engagement is purged and periodicsync fire timer cancelled (if you have installed your PWA).
For the record, here is a complete working demo (event registration) (and sw code).
The specific interval at which the periodicsync event is fired varies; what I've seen on, e.g., installed Android web apps is that you'll get periodicsync around once a day. It may be different on desktop platforms (and will only happen if your browser is actually running at the time).
Have you waited a full day or so after installing your PWA, and see if it's fired?

detect websocket loss of internet client side fast

I'm using WebSockets to connect to a server that I don't have control over. This is a chat app so I am expecting when the user's internet gets cut off for any reason I would show a "reconnecting" alert and try reconnecting every 2 sec.
The issue is the .onclose event takes up to 1 min to fire up when you turn off your modem for example and there is no way for me to know if the user still has connection to the servers.
code example :
<script type="text/javascript">
var ws = new WebSocket("wss://echo.websocket.org");
ws.onerror = function () {
console.log("error happened")
}
ws.onclose = function () {
// websocket is closed.
console.log("Connection is closed...");
};
</script>
If you want to detect whether the user went offline you can simply use the offline event.
Here's an example:
window.addEventListener('offline', e => {
console.log('offline')
})
If you insist on using the onclose/onerror handlers of WebSockets, you'd need to increase the ping interval or decrease the timeout on your WebSockets server. Judging from your OP those values seem to be set at 60 seconds.

Are there any window events triggered if user "pulls the plug" and shuts down their computer?

I have a website, and I only want the client to be able to have 1 WebSocket connection at a time (when they open another tab while there is already another connection display, I display an error to them).
I'm working on a client-side solution where I update a flag in local storage to true when the connection is requested (It won't request if the flag is already true) then I listen for the beforeunload event and set the local storage flag to false if that tab had an open connection.
This seems to be working great except for the edge case of when a user shuts down their computer abruptly and thus beforeunload never fires, so when they turn their computer back on the local storage flag is stuck at true and they are stuck not being able to connect in any tabs.
Is there an event that will be called before the shutdown where I can set my local storage flag to false?
If not is there another solution for the client to keep track that it has only 1 WebSocket connection across all tabs so it can block a connection if there is already one?
window.addEventListener('beforeunload', this.setFlagToFalse);
As correctly stated in Jaromanda's comment, a computer without power can not emit an Event to the browser (which doesn't even exist anymore...).
However, one solution to your root problem is to listen to the storage event.
This event will fire across all the Windows that do share the same Storage area, when an other Window will make any modification to this Storage.
So we can use it as a mean to communicate between Windows from the same domain, in almost real time. This means that you don't have to keep your flag up to date, you can now know directly if an other Window is already active.
Here is a basic implementation. I'll let you the joy of making it more suited to your needs.
let alone = true; // a flag to know if we are alone
onstorage = e => { // listen to the storage event
if(e.key === 'am_I_alone') {
if(e.newValue === 'just checking') { // someone else is asking for permission
localStorage.am_I_alone = 'false'; // refuse
}
else if(e.newValue === 'false') { // we've been refused access
alone = false;
}
}
};
localStorage.am_I_alone = 'just checking'; // trigger the event on the other Windows
setTimeout(()=>{ // let them a little time to answer
if(alone) { // no response, we're good to go
// so the next one can trigger the event
localStorage.am_I_alone = "true";
startWebSocket();
}
else { // we've been rejected...
error();
}
}, 500);
Live Plnkr

prevent ajax call if application cache is being updated

i am writing an offline web application.
i have a manifest files for my applicationCache. and i have handlers for appCache events.
i want to detect if the files being downloaded are being downloaded for the first time or being updated. because in case they are being updated, i would like prevent my application code from running, since i will refresh the browser after updating my app.
my specific problem here is that when the "checking" events gets fired, the applicationCache status is already "DOWNLOADING",
does anybody know how to get the applicationCache.status before any manifest or files gets downloaded?
thanks in advance for any answer
window.applicationCache.addEventListener('checking', function (event) {
console.log("Checking for updates.");
console.log("inside checking event, appcache status : %s", applicationCache.status);
}, false);
window.applicationCache.addEventListener('updateready', function (e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new version of manifest files
window.location.reload();
}
}, false);
window.applicationCache.addEventListener('downloading', function (event) {
appCommon.information("New version available", "Updating application files...", null, null);
}, false);
window.applicationCache.addEventListener('progress', function (event) {
$("#informationModal").find(".modal-body").html("Updating application files... " + event.loaded.toString() + " of " + event.total.toString());
}, false);
window.applicationCache.addEventListener('cached', function (event) {
$("#informationModal").find(".modal-body").html("Application up to date.");
setTimeout(function () { $("#informationModal").find(".close").click(); }, 1000);
}, false);
According to the specification the checking event is always the first event.
the user agent is checking for an update, or attempting to download the manifest for the first time. This is always the first event in the sequence.
I think it is a mistake to refresh the browser since that will not automatically fetch a new copy. If you look at the MDN guide for using the applicationCache you'll see that files are always loaded from the applicationCache first and then proceed to go through the cycle of events you attempted to avoid by refreshing.
Instead of refreshing you should simply make proper use of the applicationCache event life cycle in order to initialize and start your application.
i would like prevent my application code from running, since i will refresh the browser after updating my app.
You have a lot of control of when your application begins to run, if you really wanted to refresh the browser, just always start the app after updateready or noupdate events, but really instead of refreshing it seems like you should use window.applicationCache.swapCache instead.
I found this question and answer useful.

How to know if a page is currently being read by the user with Javascript?

I'm making a webpage with dynamic content that enters the view with AJAX polling. The page JS occasionally downloads updated information and renders it on the page while the user is reading other information. This sort of thing is costly to bandwidth and processing time. I would like to have the polling pause when the page is not being viewed.
I've noticed most of the webpages I have open spend the majority of their time minimized or in a nonviewed tab. I'd like to be able to pause the scripts until the page is actually being viewed.
I have no idea how to do it, and it seems to be trying to break out of the sandbox of the html DOM and reach into the user's system. It may be impossible, if the JS engine has no knowledge of its rendering environment. I've never even seen a different site do this (not that the user is intended to see it...)
So it makes for an interesting question for discussion, I think. How would you write a web app that is CPU heavy to pause when not being used? Giving the user a pause button is not reliable, I'd like it to be automatic.
Your best solution would be something like this:
var inactiveTimer;
var active = true;
function setTimer(){
inactiveTimer = setTimeOut("stopAjaxUpdateFunction()", 120000); //120 seconds
}
setTimer();
document.onmouseover = function() { clearTimeout ( inactiveTimer );
setTimer();
resumeAjaxUpdate();
}; //clear the timer and reset it.
function stopAjaxUpdateFunction(){
//Turn off AJAX update
active = false;
}
function resumeAjaxUpdate(){
if(active == false){
//Turn on AJAX update
active = true;
}else{
//do nothing since we are still active and the AJAX update is still on.
}
}
The stopAjaxUpdateFunction should stop the AJAX update progress.
How about setting an "inactivity timeout" which gets reset every time a mouse or keyboard event is received in the DOM? I believe this is how most IM programs decide that you're "away" (though they do it by hooking the input messages at the system-wide level)
I've looked at that problem before for a research project. At the time (2-3 years ago) I did not find a way to get information from the browser about whether or not you are minimized :(
First check when the window loses and gains focus.
window.onblur = function () { /* stop */ };
window.onfocus = function () { /* start */ };
Also, for various reasons, the user may stop reading the page without causing it to lose focus (e.g. he gets up and walks away from the computer). In that case, you have to assume after a period of inactivity (no mouse or keyboard events) that the users' attention has left the page. The code to do that is described in another answer.
I know you've already accepted an answer but I'd personally use a combination of several of the answers mentioned here for various reasons, including:
Using mouse events only alienates users proficient at keyboard based browsing.
Using blur/focus events don't allow for users who go make a cup of tea ;-)
I'd most likely use something like the following as a guideline:
var idleTimer, userIsIdle, pollingTimer;
document.onkeydown = document.onmousemove = resetTimer;
window.onload = function () {
pollingTimer = window.setTimeout(runPollingFunction, 30000);
resetTimer();
/* IE's onblur/onfocus is buggy */
if (window.navigator.appName == "Microsoft Internet Explorer")
document.onfocusin = resetTimer,
document.onfocusout = setIdle;
else
window.onfocus = resetTimer,
window.onblur = setIdle;
}
function resetTimer() {
if (userIsIdle)
setBack();
window.clearTimeout(idleTimer);
idleTimer = window.setTimeout(setIdle, 120000); // 2 minutes of no activity
}
function setIdle() {
userIsIdle = true;
window.clearTimeout(pollingTimer); // Clear the timer that initiates polling
window.clearTimeout(setIdle);
}
function setBack() {
userIsIdle = false;
runPollingFunction(); // call the polling function to instantly update page
pollingTimer = window.setTimeout(runPollingFunction, 300000);
}
You can listen for mousemove and keypress events. If one of those has been fired in the past X seconds, then continue with your updating. Otherwise, don't update.
It's not perfect, but I think it's the best you can do with pure JS.
If you want to venture into the world of Flash, Silverlight, or Java, you may be able to get more information from the browser.

Categories

Resources