summaryrefslogtreecommitdiffhomepage
path: root/web/agent-bridge.js
blob: 776e78a6d57364f96f94b03bd0ca9a411ae262c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* Jamstack web agent bridge (W2): injected into game.html by the relay
 * (tools/agent-bridge/server.js). Polls the relay for Ruby commands, runs them in
 * the live game via the wasm export (Module.jamstack), and posts results back, so
 * the desktop .live/bin/eval interface works against this browser tab. Forwards
 * console output to the relay's game-console. No-ops quietly if no relay is present
 * (e.g. the page is served by a plain static server). Dev-only. */
(function () {
  'use strict';

  function ready() { return window.Module && typeof window.Module.jamstack === 'function'; }

  function post(url, obj) {
    return fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(obj),
    }).catch(function () {});
  }

  // Tee console.* to the relay (this also carries the Ruby Log stream, since
  // Log -> puts -> Module.print -> console.log on web).
  ['log', 'info', 'warn', 'error'].forEach(function (lvl) {
    var orig = console[lvl] ? console[lvl].bind(console) : function () {};
    console[lvl] = function () {
      orig.apply(null, arguments);
      try {
        var line = Array.prototype.map.call(arguments, String).join(' ');
        post('/jamstack/console', { line: line });
      } catch (e) {}
    };
  });

  var relayUp = false;

  function loop() {
    if (!ready()) { setTimeout(loop, 100); return; }
    fetch('/jamstack/poll').then(function (r) {
      if (!r.ok) throw new Error('relay ' + r.status);
      relayUp = true;
      return r.json();
    }).then(function (cmd) {
      var had = cmd && cmd.code != null && cmd.code !== '';
      if (had) {
        var out;
        try { out = window.Module.jamstack(cmd.code); }
        catch (e) { out = JSON.stringify({ ok: false, error: 'jamstack: ' + String(e) }); }
        post('/jamstack/result', { id: cmd.id, result: out });
      }
      setTimeout(loop, had ? 0 : 50);
    }).catch(function () {
      relayUp = false;          // no relay (static server) -> back off quietly
      setTimeout(loop, 1000);
    });
  }

  setInterval(function () {
    if (relayUp && ready()) post('/jamstack/status', { connected: true, ts: Date.now() / 1000 });
  }, 1000);

  loop();
})();