Giter Club home page Giter Club logo

Comments (15)

aitte avatar aitte commented on June 10, 2024 1

Logging out from all other windows cannot be done. Windows/tabs cannot communicate with each other (this is a security feature in browsers to prevent XSS, Cross-site scripting exploits).

AjaxChat simply needs to be extended to send a "ping" to the server and detect "oh, the server says that we are no longer logged in." That solves the multi-window detection problem.

As for determining IF the client wants to log out or wants to stay logged in, here are the TWO solutions we have:

  1. Configuration GUI option.
    • Add a checkbox to the configuration GUI of AJAX-Chat, saying "[x] Logout on browser close?"
    • Make it enabled by default.
    • OnUnload, we look at the value of that box and call ajaxChat.logout() if it's checked.
    • Make all windows/tabs periodically verify that they are still connected, so that the other tabs can detect that they have been logged out.
    • This method is not very good because it has the drawback that closing any tab will default to logging you out even if you had multiple open and forgot to uncheck the box before closing the tab. Then again, how many people really have multiple tabs? This is also the EASIEST method to implement. We really don't even need to have a checkbox. We could ALWAYS default to logging you out when any one of the tabs/windows are closed. People should not be running multiple windows/tabs for the same user. That's retarded. Nobody does that.
  2. Make AJAX-Chat smarter.
    • The server can keep track of multiple connections like this:
    • Every time you load an AJAX-Chat page, it generates a RANDOM tag such as "3842384382" and sends this to the server as the "tab/window identifier".
    • The client sends a "ping" to the server containing its tag "3842384382" every 30 seconds.
    • The server receives the ping and updates the last-seen time of the tag-id, deletes any tag-ids older than 60 seconds (dead clients), and then responds with "pong" and a list of all ACTIVE tags for the logged in user.
    • The client receives the tag-list, and stores it.
    • When you are about to close the browser, we hook onbeforeunload, and run a function that checks the stored tag-list. If it contains just ourselves, we know that we are the ONLY tab/window in the whole WORLD that is connected as the current user. If so, we automatically call the ajaxChat.logout() function. But if there are more than 1 tags, we DON'T call logout.

Option two is the ONLY 100% automated method, works perfectly across multiple connections from multiple different browsers at the same time. It's the only method that properly logs you out ONLY if you truly closed the last window/tab for that user. But it's also a lot of work and requires both client and server-side changes.

from ajax-chat.

aitte avatar aitte commented on June 10, 2024 1

But, it probably makes most sense just to do <body onunload="ajaxChat.logout();"> because NOBODY runs multiple tabs/windows of AJAX-Chat. Opening multiple windows will all connect you as the exact same user, so it's useless. Nobody does that! Let's just go for the simpler option and always send the logout call when any tab/window is closed. That way, we don't have to mess around with all the complex solutions above!

from ajax-chat.

aitte avatar aitte commented on June 10, 2024

Interesting idea. Unfortunately there's no way to ask the user for confirmation. There's window.onbeforeunload but it only supports a custom message string, and relates to confirming whether you really wanted to close the window (can't be used to ask "Do you ALSO want to log out of AjaxChat?").

So the only safe option is a checkbox in the GUI (preferably in the small Configuration section so it's hidden for most users).

[x] Log out when browser is closed.

and then onunload, we check the state of that checkbox and send the logout call if it's true.

from ajax-chat.

IngwiePhoenix avatar IngwiePhoenix commented on June 10, 2024

I wonder why you just didnt realize it yet...

in a script tag:
function eLogout() {
if(confirm("Really log out?"))
ajaxChat.logout();
}

if you use jQuery, which i always recommend, just use this function in an unload method. Now you can extend the eLogout by looking for a checkbox:

if($("#logoutOnClose").checked()) { ... }

So, where is the problem? :)
Am 05.02.2013 um 16:00 schrieb aitte [email protected]:

Interesting idea. Unfortunately there's no way to ask the user for confirmation. There's window.onbeforeunload but it only supports a custom message string, and relates to confirming whether you really wanted to close the window (can't be used to ask "Do you ALSO want to log out of AjaxChat?").

So the only safe option is a checkbox in the GUI (preferably in the small Configuration section so it's hidden for most users).

[x] Log out when browser is closed.

and then onunload, we check the state of that checkbox and send the logout call if it's true.


Reply to this email directly or view it on GitHub.

from ajax-chat.

ManOnDaMoon avatar ManOnDaMoon commented on June 10, 2024

Confirmation dialog is a bit tricky.

Should selecting Cancel keep window open? Or shoult it close the window anyway, without lauching ajaxChat.logout()? In the former cas a user can't close a window without logging out, while in the latter a user still can close all windows without logging out.

Should selecting OK also log you out from other windows as well? In this case a user cannot close a window withtout logging out of all other windows.

I believe these are incompatible behaviors.

Also, even if you select OK to log out, potential other windows and other users will still receive the "X logs out"/"X logs in" messages, so this issue remains.

My first concern was about maintaining an up-to-date online users list, not really implementing a safeguard for users. ^^"

from ajax-chat.

aitte avatar aitte commented on June 10, 2024

IngwiePhoenix: Nope. When the client is closing his tab, browsers only allow you to ADD TEXT to the confirmation dialog. We are not allowed to ask for choices. This is what we can do via "onbeforeunload":

Are you sure you want to navigate away from this page?

OUR MESSAGE HERE

Press OK to continue, or Cancel to stay on the current page.

[ OK ] [ Cancel ]

My answer is the ONLY way to determine if the user really wants to log out: Have a configuration checkbox in the normal GUI, and check its value during the onunload event; if so, send the logout() call.

Again: We CANNOT ask the user "Oh, I see you are closing the window, do you ALSO want to log out or do you want to stay logged in?" - browsers will not allow that! They ONLY allow OK=Close window, Cancel=Stay on page. NOTHING custom such as extra checkboxes. The only thing they allow us to do is add more TEXT to the message box. So forget "onbeforeunload". It's not doing what we need. We must use a setting in the configuration GUI instead.

from ajax-chat.

ManOnDaMoon avatar ManOnDaMoon commented on June 10, 2024

@aitte:

My answer is the ONLY way to determine if the user really wants to log out: Have a configuration checkbox in the normal GUI, and check its value during the onunload event; if so, send the logout() call.

I see we crossed messages. I think even this option alone will not enable to log out from other potentially opened windows. This would require quite more work.

from ajax-chat.

ManOnDaMoon avatar ManOnDaMoon commented on June 10, 2024

@aitte

But, it probably makes most sense just to do because NOBODY runs multiple tabs/windows of AJAX-Chat.

Well it depends on how AJAX Chat is integrated: it is very easy to stumble on a shoutbox while you already have a popup opened. Then you want to close one of them, of course.

But I agree with the simplest solution. :)

Off topic: could you keep the font size to standard (bolded or not)? It really feels a bit... agressive. ^^"

from ajax-chat.

aitte avatar aitte commented on June 10, 2024

The shoutbox example just needs this workaround so that it doesn't perform auto-logout:

If shoutbox:
  do nothing
else:
  window.onunload=function(){ ajaxChat.logout(); }

We need to make sure there isn't already an unload-handler though, so the above code is not suitable as it would overwrite the current handler. Something like jQuery or another library would be needed to gracefully add an unload handler without overwriting what's already there.

PS: Sorry about the text size earlier. It's just that there's so much text, enough to give anyone a headache. ;) I wanted to make it easier for Frug to see the important bits when he comes to read the thread.

from ajax-chat.

aitte avatar aitte commented on June 10, 2024

An even better solution than all of this is to simply not handle logouts on the client at all. Logout-detection is really a server-side problem, not something that clients should be responsible for. Instead, switch from PHP to the current Ruby server, which runs 24/7 as a single process and keeps track of when people have disappeared. No PHP calls needed. Much faster too since it doesn't have to start the whole PHP process for every tiny message that gets passed back/forth.

Heck, even the PHP implementation can simply be improved to do the right thing, like this:

  • Currently it does the following:
    • When a client connects, it loops through the client table in MySQL and deletes anyone that has been idle for more than 2 minutes
    • It outputs a "has been logged out (timeout)" message for everyone it detects
    • It logs a "logout" event for that user in server-side chat logs, stored with the CURRENT time
  • Here is how to improve it, without needing a Ruby-server, or client-side changes, or ANYTHING:
    • When a client connects (or sends any other event such as a new incoming message or anything), loop through the logged-on clients table in MySQL
    • Delete anyone that has been idle for more than 2 minutes
    • If user-table contains 0 users: Log the timed out people server-side as "[last-seen-time] User X logged out" [ instead of the current "[current-time] User X logged out" ] - this will store them with a proper timestamp when they were really last seen!
    • If user-table contains 1+ users: Log the timed out people server-side as "[current-time] User X logged out" - this avoids timestamp order issues where people are connected and write stuff which ends up in the server logs before we write the timed-out user's logout event.
    • DON'T send any of the "User X has been logged out" events to people that are just now connecting, since people that connect don't care about seeing the ugly cleanup/maintenance stuff that goes on server-side. Only show those messages to people that are already in the chat (and would want to know when someone vanishes).
    • Add the newly connected user to the logged-on users table.
    • Return the list of online users to the user that just logged on.
    • NOW log the new user's connect-event "[current-time] User NewUser logged in" to the database, or their new message if it was a message-event, or whatever event it was "[current-time] SomeStillOnlineUser: lol that's nice!". - this ensures that the new user logon/whatever event comes AFTER the dead user's logout/timeout event in the database and avoids timestamp order issues.

Voila! Logouts will from now on be stored with a timestamp of when they were last-seen rather than when they logged out due to timeout. Clients that just connected will not get the "has been logged out (timeout)" message either.

Let's look at the scenarios:

1 user (A) is connected:

  • User A closes his browser. He remains in the logged-on users table.
  • No further log events will be written to the database since nobody else is connected.
  • User B connects.
  • Before handling/logging User B, the server loops through the logged-on users table.
  • Anyone that has been idle for more than 2 minutes is written to the log as "has been logged out" with a timestamp of last-seen-time (NOT current-time, to avoid timestamps of "user has logged out on 24th (timeout)" even though a user may have closed the site on the 1st; it's safe to use last-seen-time since nobody could have written anything after that user was last seen since nobody else has been connected).
  • Now count the number of logged on users; if it's 0 (as it would be if User B came to the server when nobody else remains on it), we don't show User B any "User A has been logged out" event (gets rid of the spam at connection time).
  • Now store User B in the logged on users table

Alright, 1 user at a time scenario works perfectly!

Now imagine Users A, B (or even more) online:

  • User A closes his browser, he remains in the logged-on users table.
  • User B remains on the site; his "ping" requests and other events (such as messages) will eventually cause the server to detect that User A is logged out and write it to the server-log using current-time (NOT last-seen-time, to avoid message-out-of-order issues, since chat between other users may have taken place since the timed-out user was last seen).
  • User B (and anyone else online) will see the "User A has been logged out (timeout)" message.
  • The server logs the new message/connect-event AFTER the timeout event, thereby preserving event order in the logs.

So actually, my simple solution should be easily doable TODAY in the PHP source, and will work for every scenario!

As for the "(timeout)" tag that sits after "user has been logged out (timeout)", it's pointless. Get rid of it. Most people "log out" by just closing a tab, and it's spammy/useless to see the tag everywhere.

The PHP changes described above are very, very easy to implement. I am tempted to do it myself but have NO time.

from ajax-chat.

ManOnDaMoon avatar ManOnDaMoon commented on June 10, 2024

Even if I agree with your comment, mine was a bit more complex as it was in a context of integration, so PHP only.

I am polling the database from within a CustomAJAXChatInterface in order to display "Who's online" on a webpage.

By following your reasoning, I figured out that the function I call, $ajaxChat->getOnlineUsers($channels), should be preceded by a call to $ajaxChat->checkAndRemoveInactive().

from ajax-chat.

aitte avatar aitte commented on June 10, 2024

Fantastic to hear that I was able to lead you in the right direction. I do hope Frug takes my advice for some general improvements to the normal PHP and Ruby backends as well.

from ajax-chat.

Frug avatar Frug commented on June 10, 2024

Hi.

Removing timed out users using a cronjob or by attaching $ajaxChat->checkAndRemoveInactive() to another page on your website is how I suggest doing it currently.
Here is a wiki article with a brief overview of the issue and how to add this function to another php page on your site: https://github.com/Frug/AJAX-Chat/wiki/Mod-remove-chatters

Here it is already integrated in the phpbb3 "display online users" mod https://github.com/Frug/AJAX-Chat/wiki/Phpbb3-display-online-chat-users
As you can see, the code is nearly the same.

It's really just a matter of firing checkAndRemoveInactive() once in a while from another page.

The idea of not displaying timeouts if you're the first person to join an empty chat room is fine and I'll look at handling it that way when I get some time, but adding checkAndRemoveInactive() to one of your other pages does the same thing and has the added benefit of keeping the number of users in your chat up to date. If you are displaying the number of people in chat anywhere on your website, it will say there is 1 person in chat even when the last person has timed out... Unless you add checkAndRemoveInactive() as described above.

None of this does anything for the case when someone closes chat when there are other people in the room. For that you'd need to hijack the unload or beforeunload events which is totally valid but I don't think it works across all browsers (if it does, let me know). I see it's common these days to alert users if they navigate away from an ajax page so perhaps it's time to consider the dialog option.

I'm not developing the ruby socket server because I don't have a test environment for it, I don't know ruby, and I'd actually like to remove flash eventually anyway. html5 audio can already make flash unnecessary for many users.

from ajax-chat.

ManOnDaMoon avatar ManOnDaMoon commented on June 10, 2024

Thanks for the clarification. I guess the current issue is no longer related to integration as it is likely to be correctly handled the way you explained.

Here is additional info if you consider that the issue remains for standalone versions. As far as I know, the onbeforeunload and onunload events are not supported by Opera. W3Schools also states that onunload is not supported by Chrome (http://www.w3schools.com/jsref/event_onunload.asp), but I doubt this is up-to-date.

from ajax-chat.

Frug avatar Frug commented on June 10, 2024

Opera tends to intentionally omit nonstandard/questionable behavior in favor of security. Personally I don't like it but I can see their logic. There seems to be a web standard these days for asking if people are sure they want to leave the page and if opera users don't get it, I don't think that's a big deal.

Calling checkAndRemoveInactive() works for standalone as well so it's not related to integration. However now I wonder if it's not being called on the login page in order to clear them whenever anyone visits the login page. If not it probably should be. I'm going to close this ticket and make a note of a pending change to look into that simple fix that would at least help clear the list in some cases.

from ajax-chat.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.