1

I m using timeout-dialog.JS in my application to expire session of inactive user after 5 mins. But I am having input grid wherein user can add multiple records and then after adding suppose say 10 records, he goes for a SAVE but it took more than 5 min to him enter all these details and when he went for SAVE or when he says yes keep me sign in to timeout-dialog popup the screen reloads and he loses all his data.

What I want is that the session should get reset if he moves mouse or presses a key.

To achieve this I tried adding a mousemove and keydown events in my layout page as shown below:

     <script>
    $(function () {
        var fnTimeOut = function () {
            $.timeoutDialog.setupDialogTimer({
                timeout: 300,
                countdown: 60,
                logout_redirect_url: '@Url.Action("LogOff", "Account")',
                keep_alive_url: '@Url.Action("Keepalive", "Account")'
            });
        };
        fnTimeOut();

        $(this).mousemove(function () {
            $.timeoutDialog.setupDialogTimer({
                timeout: 300,
                countdown: 60,
                logout_redirect_url: '@Url.Action("LogOff", "Account")',
                keep_alive_url: '@Url.Action("Keepalive", "Account")'
            });             
        });

        $(this).keydown(function () {
            $.timeoutDialog.setupDialogTimer({
                timeout: 300,
                countdown: 60,
                logout_redirect_url: '@Url.Action("LogOff", "Account")',
                keep_alive_url: '@Url.Action("Keepalive", "Account")'
            });          
        });
    });
</script>

but this is giving me alert saying page is not responsive with KILL or WAIT options.

So is there any way I can make session reset using timeout-dialog JS on mousemove and keydown event?

Any help would be greatly appreciated. Thanks.

NewbieCoder
  • 377
  • 3
  • 16

2 Answers2

0

A raw mousemove event listener like that would be overkill for your purpose as it can emit hundreds of events per seconds, which would definitely kill your app if you're executing a heavier operation. I can see two things you can do:

  • Throttle the events, so they only execute once per N seconds -> see Throttle
  • Find a way to only reset the internal timer of the timeout-dialog. Look inside the source code and see if there isn't anything in the API to do that, instead of setting up a completely new dialog every time (which I suspect isn't efficient). If you need any further help with that, let me know.

If you only want to keep your backend session alive, you can call your keep-alive url like so:

var callKeepAlive = _.throttle(function () {
  $.get( "<YOUR KEEP-ALIVE URL>", function( data ) {
    console.log('keep-alive called')
  });
}, 1000);

and then in your mousemove / keyup event listeners, execute callKeepAlive()

John Smith
  • 1,559
  • 1
  • 12
  • 18
  • John Smith thanks for the response. Is there any way I can just call the keep_alive_url so that it will keep my session alive. Does it sound efficient? – NewbieCoder May 18 '17 at 07:58
  • I've edited my answer, try playing around with this approach – John Smith May 18 '17 at 08:03
  • what is _.throttle in this? – NewbieCoder May 18 '17 at 10:17
  • Throttle will make sure that the keep-alive will only be able to be called ONCE every 1000 milliseconds. So you're not going to call keep-alive on every mouse-move event (which are going to be hundreds). – John Smith May 18 '17 at 10:26
-1

I came across this while checking some browser compatibility for XMLHttp and randomly browser threads on here for the sake of it. Figured i would give my working example that i came up with because i need something similar soon and figured this question could do with a larger example.

Very minimal code at bottom

Please forgive me for this being a little messy, its a raw example.

<?php
    // Do not forget session start if copying into your own code..
    if (isset($_GET['keepalive'])) {
        header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
        header("Cache-Control: post-check=0, pre-check=0", false);
        header("Pragma: no-cache");
        header('Content-Type: application/json');
        $boolStatusOfSession = TRUE;        // Something like: $boolStatusOfSession = (isset($_SESSION['MyTokenWhenSignedIn']) ? TRUE : FALSE);
        echo json_encode(array('status'=>$boolStatusOfSession));
        exit;
    }
?>
<html>
    <head></head>
    <body>
        <p>This script will throttle the mouse movement event to a rate of once per second max and perform a keep alive request to the same page along with a json response of the session status</p>
        <p id="debugbox"><b>Server Keep Alive: </b>please wait for the timer (10 seconds)</p>
        <p id="debugbox2"></p>

        <script>
            var elmDebug = document.getElementById('debugbox');
            var elmDebug2 = document.getElementById('debugbox2');
            var idleStart = Math.floor(Date.now() / 1000);

            function keepAlivePoster() {
                objHttp = new XMLHttpRequest();
                objHttp.onreadystatechange = function() {
                    var strDebug = "<b>Server Keep Alive: </b> ";
                    if (objHttp.readyState == XMLHttpRequest.DONE) {
                        idleStart = Math.floor(Date.now() / 1000);  
                        objResp = JSON.parse(objHttp.responseText);
                        if (objResp.hasOwnProperty('status') && objResp.status == true) {
                            // DO STUFF HERE WHEN SIGNED IN (Or do nothing at all)
                            strDebug += "Signed In, ";
                        } else {
                            // DO STUFF HERE WHEN SIGNED OUT (A window reload if your page can handle the session change)
                            strDebug += "Signed Out, "; // Or does not exist / error.. best to use a int status
                        }
                    }
                    elmDebug.innerHTML = strDebug + "Updated at " + Math.floor(Date.now() / 1000);
                    elmDebug2.innerHTML = '<b>Mouse Move Event: </b> Idle timer reset to ' + idleStart;
                }
                objHttp.open('GET', '?keepalive');
                objHttp.send(null);
            };


            function throttleController (callback, limit) {     // TAKEN FROM: https://jsfiddle.net/jonathansampson/m7G64/
                var wait = false;                  // Initially, we're not waiting
                elmDebug2.innerHTML = '<b>Mouse Move Event: </b> Idle timer reset to ' + idleStart;
                return function () {               // We return a throttled function
                    if (!wait) {                   // If we're not waiting
                        callback.call();           // Execute users function
                        wait = true;               // Prevent future invocations 
                        setTimeout(function () {wait = false;}, limit); // After a period of time, allow future invocations again
                    }
                }
            }           
            window.addEventListener("mousemove", throttleController(keepAlivePoster, 10000));       // Allow "idleCallback" to run at most 1 time every 10 seconds

        </script>
    </body>
</html>

Of course there is a bit of code you can remove (the debug and so on, so a bare basic script example would be)

Minimal Code

function keepAlivePoster() {
    objHttp = new XMLHttpRequest();
    objHttp.open('GET', '?keepalive');
    objHttp.send(null);
};
function throttleController (callback, limit) {     // TAKEN FROM: https://jsfiddle.net/jonathansampson/m7G64/
    var wait = false;  return function () {              
        if (!wait) { callback.call();  wait = true; setTimeout(function () {wait = false;}, limit); }
    }
}           
window.addEventListener("mousemove", throttleController(keepAlivePoster, 10000));

The last line you would duplicate for any additional events you want to cover, you would also want to make the wait variable on a higher scope / global when you use more than one event.

Why the php status / code

Well first of this would be in another file that is included well before html generation and all that.. But ideally you want the GET request to be as small as possible with a few rules and so on.. So i've disabled the ability for the page to be cached and the json response can easily be used by the browser while offering a simple check to redirect/reload if needed.

Angry 84
  • 2,935
  • 1
  • 25
  • 24