I have an ember application where users are stored in a MySQL database. When a user exits (ie. closes their browser window), they need to be deleted from the database. I have the following code in one of my route files:
setupController: function () {
$(window).on('beforeunload', () => {
this.get('currentUser').delete();
});
},
In my testing this only seems to delete the user from the database maybe 70-80% of the time, and somehow it seems to be random whether it works or not. I'm guessing this is because sometimes the function isn't run in time before the browser has closed the window. How can I ensure the code to delete a user is executed every time a user exits?
It wouldn't work this way. Reason: browser interrupts any requests (even ajax) to backend when user closes window/tab.
I suggest to implement cleanup on backend side. What you need is store last time when user performed some action and delete those who did not make any requests in some period of time (for example, if there was no requests in 1 hour, you can be pretty sure that user closed browser window). You can also perform "ping" requests from your ember app to your backend once in a while, so idle users will not be deleted.
Related
When user visit my webpage his is connected to socket on port 3000
var socket = io('http://localhost:3000');
Now I included this code so every page have it. How is there a way to pass second parameter here so even if user refresh page or go to a different page he still have some unique identifier ? My problem is that I got node.js app that respond to event.
socket.on('myevent', function (data) {
Some code is executed here.....
Well now I want to emit response back to the single user who sent it, but what if in meantime user decide to refresh or switch page ? That will give him new connection.
I consider two scenarios:
User clicks on "log out" hyperlink, which call "logout.php" (that is easy)
User closes tab (window) or closes browser.
And here I do not know, what should I do.
There is a event: window.onunload which can be used perhaps like this (not tested):
<script>
var logout_php = function () {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "logout.php", true);
xhttp.send();
}
window.onunload = logout_php ;
</script>
But when the user opens more tabs and closes just one of them, he will be logged out. Probably it will log out even, when somebody refreshes the same page.
I considered to count all opened tabs with the same domain address, and if there is only one left, then will be the final logout. But this is not possible, because you can not access another windows (tabs) opened in browser.
I am sure, it must be a common problem, but I can not find appropriate answer.
thanx
Sessions are used to handle these kind of things. If you logout then your session is destroyed and if someone closes the window directly then in that case their session is destroyed as well. So, as long as you are using sessions, there is nothing to worry about.
You can try a keep_live ajax function that calls your server every 1 minute or so updating the last_checkin variable in database or so. If the tab is closed, said function is no longer being called.
In the beginning of every request check if last_checkin is within the last minute (+ some time for connection). If not, redirect to log out (and destroy session if it exists).
This is similar to session timeout. You can have this done every 5 seconds or so. If someone closes his tab and then (for some weird reason) someone else sits on the PC and opens previously closed tabs. Most likely the x time has passed since last check in and user is now logged out.
The down side is the traffic between user and server but it's not a big deal. This is how you check for chat updates anyway so it is done in many services.
On my website, I have built a chatroom with support for multiple rooms. When a user joins the room, a session is placed into the database so that if they try to join the room again in another browser window, they are locked out.
It works like this
1. Join the chatroom page
2. Connect to chatroom #main
If the user has a session in the database for #main
--- Block user from joining
else
--- Load chatroom
When the chatroom is closed client side or the user terminates there connection with the /quit command, all of their sessions are deleted, and this works fine.
However
There is a possibility that users will just close the browser window rather than terminating their connection. The problem with this is that their session will stay in the database, meaning when they try to connect to the room, they are blocked.
I'm using this code onbeforeunload to try and prevent that
function disconnect() {
$.ajax({
url: "/remove-chat-sessions.php?global",
async: false
});
};
This is also the function called when the user types the /quit command
The problem
The problem with this is that when I reload the page, 5 times out of 10 the sessions have not been taken out of the database, as if the ajax request failed or the page reloaded before it could finish. This means that when I go back into the chatroom, the database still thinks that I am connected, and blocks me from entering the chatroom
Is there a better way to make sure that this AJAX call will load and if not, is there a better alternative than storing user sessions in an online database?
Edit:
The reason users are blocked from joining rooms more than once is because messages you post do not appear to you when the chatroom updates for new messages. They are appended to the chatroom box when you post them. This means that if users could be in the same chatroom over multiple windows, they would not be able to see the comments that they posted across all of the windows.
In this situation you could add some sort of polling. Basically, you request with javascript a page every X time. That page adds the user session to the database. Then there's a script executing every Y time, where Y > X, that cleans old sessions.
The script that is called every X time
...
// DB call (do as you like)
$All = fetch_all_recent();
foreach ($All as $Session)
{
if ($Session['time'] < time() - $y)
{
delete_session($Session['id']);
}
}
The script that javascript is calling every X time
...
delete_old_session($User->id);
add_user_session($User->id, $Chat->id, time());
The main disadvantage of this method is the increment in requests, something Apache is not so used to (for large request number). There are two non-exclusive alternatives for this, which involve access to the server, are:
Use nginx server. I have no experience in this but I've read it supports many more connections than Apache.
Use some modern form of persistent connection, like socket.io. However, it uses node.js, which can be good or bad, depending on your business.
I would like to keep track of how long visitors spend reading a page. If they tab away, or minimize the window, time should not count towards the time on page until they look at the tab again.
I assume some combination of javascript and server side work will be necessary.
A couple of issues I'm struggling with:
What's the best way to store this information in the database?
How do I, with Javascript, capture the time on page with a reasonable degree of accuracy? Do I store events like "page loaded", "user idle", "user returned", "page unloaded", and then separately process all the events in the DB to come up with a time on page?
I've put some work into a small JavaScript library that times how long a user is on a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignores time that a user switches to different tabs, goes idle, minimizes the browser, etc. The Google Analytics method suggested has the shortcoming (as I understand it) that it only checks when a new request is handled by your domain. It compares the previous request time against the new request time, and calls that the 'time spent on your web page'. It doesn't actually know if someone is viewing your page, has minimized the browser, has switched tabs to 3 different web pages since last loading your page, etc.
https://github.com/jasonzissman/TimeMe.js
An example of its usage:
On loading your page:
document.onload = function() {
TimeMe.setIdleDurationInSeconds(30);
TimeMe.setCurrentPageName("my-home-page");
TimeMe.initialize();
}
Retrieving time spent on the page, and sending it to your server when the user leaves your page:
window.onbeforeunload = function (event) {
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",false);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
};
First, you need to detect when a user has moved away from a tab or is inactive. When this happens, start a timer, when they come back, stop the timer. Counting time with setTimeout/setInterval can be innacurate because of blocking, so I made myself an accurate javascript timer based on the actual difference in datetime: https://gist.github.com/4600726
So your code would look something like this:
timer = new Timer;
window.addEventListener('focus', function() {
timer.start();
}, false);
window.addEventListener('blur', function() {
timer.stop();
// send timer.msecs() to the server maybe??
// if so, also call timer.reset();
}, false);
window.addEventListener('beforeunload', function() {
timer.stop();
// send timer.msecs() to the server via jquery post, or better yet websocket
}, false);
Then you can get the elapsed time with timer.secs(). I guess it depends on your preference how often you want to send info to the server. You could do it on blur.
Another option could be to decree that no mouseover means inactivity. Start the timer and then do a setTimeout, then on the window's mousemove event cancel the setTimeout and start another setTimeout , after which you stop the timer.
As far as sending data to the server, I'd probably opt for sending it on blur and of course beforeunload. My preferred method would be with socket.io since it is fast and always connected, so you could use it to track lots of user events in real time, but you could just to an ajax call to your server. If you just send them as mini user sessions, { user: userId, page: pageId, elapsedTime: msecs } then you could then aggregate the data on the server end when you are doing analysis.
I'm developing a chat module for my application...
I'm opening a window for users to chat, is there way that when users close the chat window, I can update status of that record...i mean event for the closed browser?
I know that default session time is 24mins,
so after 24mins of inactivity, user will be kicked out from the site and will asked to login once again.
How to delete/flush the data in my database, when user has no activity for 24mins (when user is logged out from the session due to inactivity)?
1) You'll need javascript onUnload event for this one. It'll send an asynchronous query to your webserver, setting the offline status of the user. However, you should not rely solely on this event and also set up the 24 mins auto-offline timeout because it is not guaranteed that the user is using javascript.
2) I think your best option here is running a cron job (every 30 mins or so?) that queries your database, identifies the users whose last activity was more than 24 mins ago and then deletes the associated data.
Store every chat entry's timestamp in UNIX_TIMESTAMP. When a new chat entry incoming check every entries timestamp where timestamp is smaller than now - 24 mins. Kick users.
1) use the unload event
2) if you are developing a chat, i guess that you have a periodical function that calls the server constantly to retrieve the messages. Each time this function is called, the inactivity time will be reset, even if the user haven't sent a message. If you want to logout the user when he doesn't write anything in 24min you cant rely on the php sessions.
What you can do is: save in the db, the last time the user wrote a message on the chat, and each time you use your periodical function, validate if the user hasn't wrote anything in the last 24 mins
Use a javascript function for the event
window.onbeforeunload = myLogoutFunction;
Note: This javascript will not work on browser crash.
Have a user_log database table and fill the login and "logout" dates in it.
When there is a user with not updated logoff date, then you can assume there was something wrong with his connection.
$where = " AND `users_id`='".$response['userfound']['id']."'";
$where .= " AND `logoffdatetime`='0000-00-00 00:00:00'";
After 24min php session is gone (default php.ini settings). It wont be much usable. But you can still save into the user_log table.
You should not need the flush database.
Keeping the chat users via database alive is bad idea. Instead use a small file with timestamp in it.
Here some other useful tips
Detect if the user coming back without logout
$user_navigates = false;
if(isset($_SERVER['HTTP_REFERER']) && basename($_SERVER['HTTP_REFERER']) != _PAGE)
$user_navigates = true;
save also page refreshes into session
if(isset($_GET['pagerefreshed']))
$_SESSION['pagerefreshed'] = $_GET['pagerefreshed'];
save the logging out user_id into session, so you can use it restore things. For instance no need to reload page.
$_SESSION['loggedout']['user_id'] == $login->user_id