Keep track of number of viewers.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 20 Nov 2013 19:52:55 +0000 (20:52 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 20 Nov 2013 19:52:55 +0000 (20:52 +0100)
www/analysis.pl
www/css/remoteglot.css
www/index.html
www/js/remoteglot.js

index 9622623..f650bed 100755 (executable)
@@ -2,6 +2,8 @@
 use CGI;
 use Linux::Inotify2;
 use AnyEvent;
+use IPC::ShareLite;
+use Storable;
 use strict;
 use warnings;
 
@@ -24,6 +26,9 @@ my $wait = AnyEvent->timer (
        cb    => sub { $cv->send; },
 );
 
+my $unique = $cgi->param('unique');
+our $num_viewers = count_viewers($unique);
+
 # Yes, this is reinventing If-Modified-Since, but browsers are so incredibly
 # unpredictable on this, so blargh.
 my $ims = 0;
@@ -42,6 +47,38 @@ if ($time > $ims) {
 $cv->recv;
 output();
 
+sub count_viewers {
+       my $unique = shift;
+       my $time = time;
+       my $share = IPC::ShareLite->new(
+               -key => 'RGLT',
+               -create  => 'yes',
+               -destroy => 'no',
+               -size => 1048576,
+       ) or die "IPC::ShareLite: $!";
+        $share->lock(IPC::ShareLite::LOCK_EX);
+       my $viewers = {};
+       eval {
+               $viewers = Storable::thaw($share->fetch());
+       };
+       $viewers->{$unique} = time;
+
+       # Go through and remove old viewers, and count them at the same time.
+       my $num_viewers = 0;
+       while (my ($key, $value) = each %$viewers) {
+               if ($time - $value > 60) {
+                       delete $viewers->{$key};
+               } else {
+                       ++$num_viewers;
+               }
+       }
+
+        $share->store(Storable::freeze($viewers));
+        $share->unlock();
+
+       return $num_viewers;
+}
+
 sub output {
        open my $fh, "<", $json_filename
                or die "$json_filename: $!";
@@ -55,8 +92,9 @@ sub output {
 
        print CGI->header(-type=>'text/json',
                          -x_remoteglot_last_modified=>$time,
+                         -x_remoteglot_num_viewers=>$num_viewers,
                          -access_control_allow_origin=>'http://analysis.sesse.net',
-                         -access_control_expose_headers=>'X-Remoteglot-Last-Modified',
+                         -access_control_expose_headers=>'X-Remoteglot-Last-Modified, X-Remoteglot-Num-Viewers',
                          -expires=>'now');
        print $data;
 }
index e1e8ccb..186ef1f 100644 (file)
@@ -7,6 +7,7 @@ h3 {
 }
 #score {
        font-size: x-large;
+       margin-top: 0;
 }
 .window {
        position: absolute;    
@@ -60,14 +61,25 @@ p {
 .black-3c85d.nonuglyhighlight {
        background-color: #9ab6a6;
 }
-#board {
-       display: block;
-       float: left;
+#boardcontainer {
        width: 400px;
        margin-right: 1em;
        margin-bottom: 1em;
+       float: left;
+}
+#board {
+       display: block;
+       width: 100%;
        padding: 0;
 }
+#numviewers {
+       display: block;
+       width: 100%;
+       text-align: center;
+       font-size: smaller;
+       margin-top: 0.5em;
+       margin-bottom: 0;
+}
 #analysis {
        display: block;
        min-width: 400px;
@@ -77,7 +89,7 @@ p {
 /* If the board is too wide for the screen, shrink it to fit,
  * and then put the analysis below. */
 @media all and (max-width: 400px) {
-       #board {
+       #boardcontainer {
                width: 100%;
                float: none;
        }
@@ -88,7 +100,7 @@ p {
 
 /* If there is almost space for the analysis, shrink the board a bit, too. */
 @media all and (min-width: 500px) and (max-width: 810px) {
-       #board {
+       #boardcontainer {
                float: left;
                width: 50%;
        }
index 4f44105..52535fb 100644 (file)
 </head>
 <body>
 <h1 id="headline">Analysis</h1>
-<div id="board"></div>
+<div id="boardcontainer">
+  <div id="board"></div>
+  <p id="numviewers"></p>
+</div>
 <div id="analysis">
   <p id="score">Score:</p>
   <p><strong>PV:</strong> <span id="pv"></span></p>
index 671c3d0..303f148 100644 (file)
@@ -5,14 +5,16 @@ var occupied_by_arrows = [];
 var ims = 0;
 var highlight_from = undefined;
 var highlight_to = undefined;
+var unique = Math.random();
 
 var request_update = function(board, first) {
        $.ajax({
-               //url: "http://analysis.sesse.net/analysis.pl?first=" + first
-               url: "http://analysis.sesse.net:5000/analysis.pl?ims=" + ims
+               url: "http://analysis.sesse.net/analysis.pl?ims=" + ims + "&unique=" + unique
+               //url: "http://analysis.sesse.net:5000/analysis.pl?ims=" + ims + "&unique=" + unique
        }).done(function(data, textstatus, xhr) {
                ims = xhr.getResponseHeader('X-Remoteglot-Last-Modified');
-               update_board(board, data);
+               var num_viewers = xhr.getResponseHeader('X-Remoteglot-Num-Viewers');
+               update_board(board, data, num_viewers);
        });
 }
 
@@ -277,7 +279,7 @@ var update_highlight = function()  {
        }
 }
 
-var update_board = function(board, data) {
+var update_board = function(board, data, num_viewers) {
        // The headline.
        var headline = 'Analysis';
        if (data.position.last_move !== 'none') {
@@ -290,6 +292,14 @@ var update_board = function(board, data) {
 
        $("#headline").text(headline);
 
+       if (num_viewers === null) {
+               $("#numviewers").text("");
+       } else if (num_viewers == 1) {
+               $("#numviewers").text("You are the only current viewer");
+       } else {
+               $("#numviewers").text(num_viewers + " current viewers");
+       }
+
        // The score.
        if (data.score !== null) {
                $("#score").text(data.score);