jpschewe / fll-sw

FIRST Lego League scoring software
http://jpschewe.github.io/fll-sw/
GNU General Public License v2.0
10 stars 7 forks source link

Detect 2 windows open to the subjective application #1199

Closed jpschewe closed 1 week ago

jpschewe commented 3 months ago

Is it possible to recognize when a user has opened the subjective application twice and do something reasonable?

jpschewe commented 1 month ago

This looks like it might work https://stackoverflow.com/questions/42513836/detect-multiple-tabs-or-windows-of-the-same-session-in-a-web-application

jpschewe commented 1 month ago

One could write to local storage and then watch for events of another window writing to local storage. Another option is to combine a unique ID check with https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API to see if the other window is still alive.

jpschewe commented 1 month ago

I can write a UID to local storage and check for that on page load and clear it on unload. However I do have a problem if the unload handler doesn't run the user can be in a bad state because nothing will clear the localStorage. This is where I could use the broadcast API to check for another window responding and if it doesn't respond within a second, assume it's dead and continue.

jpschewe commented 1 month ago

I have a proof of concept here

"use strict";

document.addEventListener("DOMContentLoaded", () => {
    const uid = (Math.random() * 0xffffffff >>> 0);
    const bc = new BroadcastChannel("test_channel");
    let responseHandler = null;

    bc.onmessage = (event) => {
        const message = event.data;
        if(message.msg == "ping" && message.uid == uid) {
            const response = new Object();
            response.msg = "pong";
            response.uid = uid;
            bc.postMessage(response);
        } else if(message.msg == "pong" && message.uid != uid) {
            console.log("Received response from: " + message.uid);
            if(responseHandler) {
                responseHandler(message);
            }
        }
    };

    window.onunload = function () {
        const otherUid = localStorage.getItem("active-window");
        console.log("Unload called");
        if(otherUid == uid) {
            localStorage.removeItem("active-window");
            console.log("Unload cleared window");
        }
        bc.close();
    };

    const otherUid = localStorage.getItem("active-window");
    if (typeof otherUid == 'undefined' || otherUid == 'undefined' || otherUid == null) {
        console.log("No other window found");
        localStorage.setItem("active-window", uid)
    } else {
        responseHandler = function(response) {
            // clear the handler
            responseHandler = null;

            // tell the user something
            console.log("Found other window: " + otherUid);
            alert("You already have the subjective application open in another window, this is not supported, please close this window!");
            window.close();
        };

        const message = new Object();
        message.uid = otherUid;
        message.msg = "ping";
        bc.postMessage(message);
    }

});
jpschewe commented 4 weeks ago

Currently waiting for testing from others.