Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Is there ANY way to run a little piece of code when the browser changes location/closes?
I know there's the javascript onunload() event, but I need a function that will work on ALL browsers (including text-only!)

I need this because I am building a little chat application on my website, and when a user logs on, the screen shows "User Username has entered."
What I want is that when a user closes the browser (without clicking a button to logoff), I can have "User Username has left the room." pop up on other users' screens.

I don't think there's a way to do this, but I'm desperate.
The only thing I can think of is storing times in a file. Everytime a user chats, their username and the current time are stored in a file. Everytime a user chats, the script opens that file, reads in all usernames/times and if the user's time in the file is more than two minutes apart from the current time, the user is removed.

Two reasons I DON'T want to do this:

  • Lots of code (A LOT!)
  • Inefficient (Is that spelt wrong?)

    So any help or ideas are welcome! See ya later! (If you're leaving a message for me, I'm probably on right now, and I'll get your message right away)

  • Replies are listed 'Best First'.
    RE: Script Unload??
    by guaguanco (Acolyte) on Apr 25, 2000 at 22:19 UTC
      The problem is that a browser doesn't generally maintain an open socket connection with a server. It makes a request, the server spits back some bytes (usually HTML), and the connect ion is closed.
    Re: Script Unload??
    by chromatic (Archbishop) on Apr 25, 2000 at 22:24 UTC
      Browser issues are all client side. Unless you're running Perl Script, your CGI (making the assumption that that's what you're writing here) only sends data over a socket and prays that it gets there.

      The timestamp idea is a pretty good one, though I'd do it a little differently. Just make a stack (an array) of users and their last message times. Hmm, you might want a hash too.

      The hash stores the username as the key and a reference to an array. The first slot could be the datestamp. The second and third slots could be links to the previous and next arrays on the stack. You might put the username in another slot.

      When a user submits a message, grab his little array through the hash, update the timestamp, and put it on the top of the stack. Every once in a while, check the item on the bottom of the stack. If it's older than X, remove it and say that the user has left the room.

      Not too tricky. It's a whole lot nicer to do it in memory, as you're not dealing with much data here.

    Re: Script Unload??
    by turnstep (Parson) on Apr 25, 2000 at 23:20 UTC
      Another idea is to have a "logoff" button that calls your script so that it knows when the person logs off. As far as encouraging/forcing them to actually *use* that button, that's social engineering. You could punish those who don't, reward those who do, or just ask real nice.
    Re: Script Unload??
    by Anonymous Monk on Apr 25, 2000 at 22:20 UTC
      Is there a better way than my stupid username/time thing?
        Not that I know of, no. Because as the first poster wrote, HTTP is stateless, meaning that your server program has no way of knowing what's going on with the client (the browser).

        The only way around this is to implement your chat program in Java--the java client can keep an open socket to the server, so when the socket closes, the server knows that the client has "logged off."

        Of course, this probably also wouldn't work w/ your text-only browsers. :)

          Actually you might be able to get away with only a 1 pixel sized java applet that could maintain a connection to the serverl. (The only purpose it would serve would eb as a presence detector.)
    Re: Script Unload??
    by Anonymous Monk on Apr 25, 2000 at 22:29 UTC
      Btrott - Are you like an administrator on this site?

      I ask because you always seem to be the one that answers my questions instantly

      (Not that I don't appreciate it! :-) As a matter of fact, I think I'll thank you for all your generous help)

        No, just someone with perhaps too much time on his hands. Or perhaps someone who creates too much time on his hands. :)

        Thanks for the thanks.

    Re: Script Unload??
    by Anonymous Monk on Apr 26, 2000 at 05:08 UTC
      I've been fiddling with a script like this and the main idea i had was a script in cron or that sleeps for a minute at a time and then reads a username/timestamp file or array/hash and logs people out if they haven't said anything. You could always do this and add the onunload event for those that support it and a logout button for those that will bother
    Re: Script Unload??
    by ZZamboni (Curate) on Apr 25, 2000 at 22:47 UTC
      There is nothing that will work on all browsers. They can't even agree on HTML specifications... :-)

      I don't think you can solve this problem from the browser side. What I would do is your last suggestion: time out the users. If a user spends more than x minutes without activity, log them out automatically. I don't think it is as hard as you think. Assuming you are writing your chat scripts in Perl (otherwise, why would you be asking here), you could keep a hash indexed by user name where you store time() every time that user says something. Then, every once in a while (like every time anyone talks, or every fixed number of seconds) go through the hash and expire those users for which (time()-$hash{user})>(x*60).

      If you want to be even more efficient, you could store the user times in a timer queue (sorted by time) so that you can remove from the start/end of the queue without having to traverse all of it.

      This reminded me of a Perl package I wrote some time ago for a project I worked on, that implemented a finite time queue. You may be able to use it as a starting point. I could not upload it to the code catacombs (too large) so you can get it here.

    Re: Script Unload??
    by little_mistress (Monk) on Apr 25, 2000 at 23:15 UTC
        I took the question to be twofold:
        1. Can this be done in Perl in this fashion?
        2. If not, is this other method (that I know I can do in Perl) a good solution?
        Even though the answer to the first question is No, I answered it because I think being honest about the limitations of Perl (or HTTP, in this case) is valuable, and because I found the implied second question interesting.

        Giving people alternate approaches which can be done in Perl is a big plus, in my book.

        That's what I also thought at first. But, although the original question was not directly perl-related, many of the answers involved discussion of Perl programming and perl data structures (the queue/stack thing). So it ended up being perl-related :-)
        Hi,
        I found a way round that ...
        It's not nice, but I keep track of the time the user posted something.
        After a that period of time it scannes the file an removes the user from the list.
        But You'll see lurkers. The script get's the ip/hostname from the users watching and not logged in.

        If you want some help, mail me...Because the script consists of several files.

        --
        My opinions may have changed, but not the fact that I am right
    Re: Script Unload??
    by mt2k (Hermit) on Apr 26, 2000 at 03:59 UTC
      Sorry, it just can't be done. (I suppose you got that from all the other messages, huh?)

      If there is a way, I'd love to see it!