--- /dev/null
+#! /usr/bin/perl
+use Time::HiRes;
+use LWP::Simple;
+require 'config.pm';
+use strict;
+use warnings;
+no warnings qw(once);
+
+$SIG{ALRM} = sub { output(); };
+Time::HiRes::alarm(1.0, 1.0);
+
+open my $fh, "-|", "varnishncsa -F '%{%s}t %U %q tffb=%{Varnish:time_firstbyte}x' -q 'ReqURL ~ \"^/analysis.pl\"'"
+ or die "varnishncsa: $!";
+my %uniques = ();
+
+while (<$fh>) {
+ chomp;
+ m#(\d+) /analysis.pl \?ims=\d+&unique=(.*) tffb=(.*)# or next;
+ $uniques{$2} = {
+ last_seen => $1 + $3,
+ grace => undef,
+ };
+ my $now = time;
+ print "[$now] $1 $2 $3\n";
+}
+
+sub output {
+ my $mtime = (stat($remoteglotconf::json_output))[9] - 1; # Compensate for subsecond issues.
+ my $now = time;
+
+ while (my ($unique, $hash) = each %uniques) {
+ my $last_seen = $hash->{'last_seen'};
+ if ($now - $last_seen <= 5) {
+ # We've seen this user in the last five seconds;
+ # it's okay.
+ next;
+ }
+ if ($last_seen >= $mtime) {
+ # This user has the latest version;
+ # they are probably just hanging.
+ next;
+ }
+ if (!defined($hash->{'grace'})) {
+ # They have five seconds after a new JSON has been
+ # provided to get get it, or they're out.
+ # We don't simply use $mtime, since we don't want to
+ # reset the grace timer just because a new JSON is
+ # published.
+ $hash->{'grace'} = $mtime;
+ }
+ if ($now - $hash->{'grace'} > 5) {
+ printf "Timing out %s (last_seen=%d, now=%d, mtime=%d, grace=%d)\n",
+ $unique, $last_seen, $now, $mtime, $hash->{'grace'};
+ delete $uniques{$unique};
+ }
+ }
+
+ my $num_viewers = scalar keys %uniques;
+ printf "%d entries in hash, mtime=$mtime\n", scalar keys %uniques;
+ LWP::Simple::get('http://127.0.0.1:5000/override-num-viewers?num=' . $num_viewers);
+}
// hanging indefinitely (which might have them return errors).
var touch_timer = undefined;
+// If we are behind Varnish, we can't count the number of clients
+// ourselves, so some external log-tailing daemon needs to tell us.
+var viewer_count_override = undefined;
+
var reread_file = function(event, filename) {
if (filename != path.basename(json_filename)) {
return;
response.write('Something went wrong. Sorry.');
response.end();
}
+var handle_viewer_override = function(request, u, response) {
+ // Only accept requests from localhost.
+ var peer = request.socket.localAddress;
+ if ((peer != '127.0.0.1' && peer != '::1') || request.headers['x-forwarded-for']) {
+ console.log("Refusing viewer override from " + peer);
+ send_404(response);
+ } else {
+ viewer_count_override = (u.query)['num'];
+ response.writeHead(200, {
+ 'Content-Type': 'text/plain',
+ });
+ response.write('OK.');
+ response.end();
+ }
+}
var send_json = function(response, accept_gzip, num_viewers) {
var headers = {
'Content-Type': 'text/json',
}
}
var count_viewers = function() {
+ if (viewer_count_override !== undefined) {
+ return viewer_count_override;
+ }
+
var now = (new Date).getTime();
// Go through and remove old viewers, and count them at the same time.
var unique = (u.query)['unique'];
console.log((new Date).getTime()*1e-3 + " " + request.url);
-
+ if (u.pathname === '/override-num-viewers') {
+ handle_viewer_override(request, u, response);
+ return;
+ }
if (u.pathname !== '/analysis.pl') {
// This is not the request you are looking for.
send_404(response);