Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send SocketIO message on unload or upon confirmation onbeforeunload

I have a server application that performs firmware update on remote devices via radio.

Sometimes the update may continue like forever (if there is disturbance in the radio network). In that case the user may wish to interrupt the update by refreshing or leaving the page. In this case I have to:

  1. Alert the user that he is about to interrupt the update (which is not recommended), and if the user is sure about his decision (and confirm):

  2. Send a socketIO event to the server to inform that the update should be canceled.

I searched through the internet and came across to different solutions. The best of them are assigning handlers to the global object events onbeforeunload and onunload.

  • Using onbeforeunload I don't have choice. Can't send the SocketIO message only if the user confirm, and do nothing if the user decide to wait the update to finish. I can send the SocketIO message to the server, but what if the user decide to wait? The harm is already done.

  • Using onunload - it seems that doesn't work for me. I see that the socket event is being send by the browser, but before handled by the server the connection is closed.

Is there any way keep the SocketIO connection or delay the browser refresh so the server can handle the event?

I think that this is problem in the server because it runs on CPU with very limited resources, even CPU speed. It is ARM A7 architecture.

like image 334
Hairi Avatar asked Nov 01 '25 18:11

Hairi


2 Answers

There is a way:

Server: Create a user id with:

var custom_id = 0;
io.engine.generateId = (req) => {
    let id = custom_id++;
    return id++; // very basic but unique id
  }

Server: Create a listener to an attempt to close event and store the user id attempt:

var userAttempt = 0;

socket.on('attempt to close', function(data){
  userAttempt = socket.id;
  console.log(data)
})

Server: Modify disconnect event to check which id user is disconnected:

socket.on('disconnect', function(){
    if(userAttempt === socket.id){
      console.log("user attempt and close");
     //the update should be canceled !!!!
    }
    console.log('user disconnected');
  });

Client: Create the event emitter attempt to close inside onbeforeunload, this event is always going to be fired if user attempt to close or reload the page.

window.onbeforeunload = function (e) {
      e.returnValue = " ";
      var socket = io();
      socket.emit('attempt to close', "user attempt to close");
    };

If user try to close the tab, we fire the event attempt to close, we check if user close or not the tab checking the disconnect event. If user disconnected is the same as user attempted to close, the update should be cancelled.

like image 104
Emeeus Avatar answered Nov 03 '25 08:11

Emeeus


What I did is place the socket event in window.addEventListener('unload', function (e) {});

    window.addEventListener('beforeunload', function (e) {
        e.preventDefault();
        e.returnValue = ' ';
    });


    window.addEventListener('unload', function (e) {
        socket.emit('some event', {data to be sent});
    });

it worked fine to accomplish the task

like image 42
Pradeep Parmar Avatar answered Nov 03 '25 07:11

Pradeep Parmar