]> git.sesse.net Git - remoteglot/blobdiff - server/serve-analysis.js
Handle streaming PGNs, like from Lichess (although this might break non-streaming...
[remoteglot] / server / serve-analysis.js
index 86f2d9083aa9c229451a42acfa9edfba62daa97b..8448cfad0c6a55f4d75d27436a4060846ccde3e0 100644 (file)
@@ -23,9 +23,11 @@ var json_filename = '/srv/analysis.sesse.net/www/analysis.json';
 if (process.argv.length >= 3) {
        json_filename = process.argv[2];
 }
+var html_filename = '/srv/analysis.sesse.net/www/index.html';
 
 // Expected destination filenames.
 var serve_url = '/analysis.pl';
+var html_serve_url = '/index-inline.html';
 var hash_serve_url = '/hash';
 if (process.argv.length >= 4) {
        serve_url = process.argv[3];
@@ -53,6 +55,7 @@ var json_lock = 0;
 
 // The current contents of the file to hand out, and its last modified time.
 var json = undefined;
+var html = undefined;
 
 // The last five timestamps, and diffs from them to the latest version.
 var historic_json = [];
@@ -134,6 +137,17 @@ var create_json_historic_diff = function(new_json, history_left, new_diff_json,
        var histobj = history_left.shift();
        var diff = delta.JSON_delta.diff(histobj.parsed, new_json.parsed);
        var diff_text = JSON.stringify(diff);
+
+       // Verify that the delta is correct
+       var base = JSON.parse(histobj.plain);
+       delta.JSON_delta.patch(base, diff);
+       var correct_pv = JSON.stringify(base['pv']);
+       var wrong_pv = JSON.stringify(new_json.parsed['pv']);
+       if (correct_pv !== wrong_pv) {
+               console.log("Patch went wrong:", histobj.plain, new_json.plain);
+               exit();
+       }
+
        zlib.gzip(diff_text, function(err, buffer) {
                if (err) throw err;
                new_diff_json[histobj.last_modified] = {
@@ -146,6 +160,23 @@ var create_json_historic_diff = function(new_json, history_left, new_diff_json,
        });
 }
 
+function read_entire_file(filename, callback) {
+       fs.open(filename, 'r', function(err, fd) {
+               if (err) throw err;
+               fs.fstat(fd, function(err, st) {
+                       if (err) throw err;
+                       var buffer = new Buffer(1048576);
+                       fs.read(fd, buffer, 0, 1048576, 0, function(err, bytesRead, buffer) {
+                               if (err) throw err;
+                               fs.close(fd, function() {
+                                       var contents = buffer.toString('utf8', 0, bytesRead);
+                                       callback(contents, st.mtime.getTime());
+                               });
+                       });
+               });
+       });
+}
+
 var reread_file = function(event, filename) {
        if (filename != path.basename(json_filename)) {
                return;
@@ -162,17 +193,34 @@ var reread_file = function(event, filename) {
        json_lock = 1;
 
        console.log("Rereading " + json_filename);
-       fs.open(json_filename, 'r', function(err, fd) {
-               if (err) throw err;
-               fs.fstat(fd, function(err, st) {
-                       if (err) throw err;
-                       var buffer = new Buffer(1048576);
-                       fs.read(fd, buffer, 0, 1048576, 0, function(err, bytesRead, buffer) {
+       read_entire_file(json_filename, function(new_json_contents, mtime) {
+               replace_json(new_json_contents, mtime);
+
+               // The HTML can go async, it's not too hopeless if it's out of date by a few milliseconds
+               read_entire_file(html_filename, function(new_html_contents, html_mtime) {
+                       var json_headers = {
+                               'X-RGLM': mtime,
+                               'X-RGNV': count_viewers(),  // May be slightly out of date.
+                               'Date': (new Date).toUTCString(),
+                       };
+                       if (MINIMUM_VERSION) {
+                               json_headers['X-RGMV'] = MINIMUM_VERSION;
+                       }
+                       let inline_json = {
+                               'data': JSON.parse(new_json_contents),
+                               'headers': json_headers,
+                       };
+                       delete inline_json['data']['internal'];
+
+                       new_html_contents = new_html_contents.replace(
+                               '/*REPLACE:inlinejson*/',
+                               'window.inline_json=' + JSON.stringify(inline_json) + ';');
+                       zlib.gzip(new_html_contents, function(err, buffer) {
                                if (err) throw err;
-                               fs.close(fd, function() {
-                                       var new_json_contents = buffer.toString('utf8', 0, bytesRead);
-                                       replace_json(new_json_contents, st.mtime.getTime());
-                               });
+                               html = {
+                                       plain: new_html_contents,
+                                       gzip: buffer,
+                               };
                        });
                });
        });
@@ -231,6 +279,24 @@ var send_json = function(response, ims, accept_gzip, num_viewers) {
        }
        response.end();
 }
+var send_html = function(response, accept_gzip, num_viewers) {
+       var headers = {
+               'Content-type': 'text/html; charset=utf-8',
+               'Vary': 'Accept-Encoding',
+       };
+
+       if (accept_gzip) {
+               headers['Content-Length'] = html.gzip.length;
+               headers['Content-Encoding'] = 'gzip';
+               response.writeHead(200, headers);
+               response.write(html.gzip);
+       } else {
+               headers['Content-Length'] = html.plain.length;
+               response.writeHead(200, headers);
+               response.write(html.plain);
+       }
+       response.end();
+}
 var mark_recently_seen = function(unique) {
        if (unique) {
                last_seen_clients[unique] = (new Date).getTime();
@@ -277,7 +343,7 @@ if (COUNT_FROM_VARNISH_LOG) {
        // Note: We abuse serve_url as a regex.
        var varnishncsa = child_process.spawn(
                'varnishncsa', ['-F', '%{%s}t %U %q tffb=%{Varnish:time_firstbyte}x',
-               '-q', 'ReqURL ~ "^' + serve_url + '"']);
+               '-q', 'ReqURL ~ "^(' + serve_url + '|' + html_serve_url + ')"']);
        var rl = readline.createInterface({
                input: varnishncsa.stdout,
                output: varnishncsa.stdin,
@@ -348,22 +414,22 @@ server.on('request', function(request, response) {
                hash_lookup.handle_request(fen, response);
                return;
        }
-       if (u.pathname !== serve_url) {
+       if (u.pathname !== serve_url && u.pathname !== html_serve_url) {
                // This is not the request you are looking for.
                send_404(response);
                return;
        }
 
-       mark_recently_seen(unique);
-
        var accept_encoding = request.headers['accept-encoding'];
-       var accept_gzip;
-       if (accept_encoding !== undefined && accept_encoding.match(/\bgzip\b/)) {
-               accept_gzip = true;
-       } else {
-               accept_gzip = false;
+       let accept_gzip = (accept_encoding !== undefined && accept_encoding.match(/\bgzip\b/));
+
+       if (u.pathname === html_serve_url) {
+               send_html(response, accept_gzip, count_viewers());
+               return;
        }
 
+       mark_recently_seen(unique);
+
        // If we already have something newer than what the user has,
        // just send it out and be done with it.
        if (json !== undefined && (!ims || json.last_modified > ims)) {