]> git.scottworley.com Git - reliable-chat/commitdiff
Bidirectional communication!
authorScott Worley <sworley@chkno.net>
Mon, 30 Jul 2012 03:58:58 +0000 (20:58 -0700)
committerScott Worley <sworley@chkno.net>
Mon, 30 Jul 2012 03:58:58 +0000 (20:58 -0700)
This is actually pretty awful.  In order to fetch _data_ cross-origin,
I have to run foreign _code_ and have it window.parent.postMessage().
This seems really, really wrong.

server/server.go
webclient/rc.css
webclient/rc.html
webclient/rc.js

index 8ce96787ac89658490ab943dc2b7710db4a38a14..5c5ef50fbfd448989c3b57648f466e76ede087fa 100644 (file)
@@ -95,6 +95,48 @@ func start_store() Store {
        return store
 }
 
+const frame_html = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <script type="text/javascript"><!--//--><![CDATA[//><!--
+  var since;
+  function go() {
+   var delay = 10000;
+   var xhr = new XMLHttpRequest();
+   xhr.onreadystatechange = function() {
+    if (this.readyState == this.DONE) {
+     if (this.status == 200) {
+      var rtxt = this.responseText;
+      if (rtxt != null) {
+       var r = JSON.parse(rtxt);
+       if (r != null) {
+        window.parent.postMessage(rtxt, "*");
+        delay = 40;
+        if (r.length >= 1 && "Time" in r[r.length-1]) {
+         since = r[r.length-1]["Time"];
+        }
+       }
+      }
+     }
+     window.setTimeout(go, delay);
+    }
+   }
+   var uri = "/fetch";
+   if (since) {
+    uri += '?since="' + since + '"';
+   }
+   xhr.open("GET", uri);
+   xhr.send();
+  }
+  //--><!]]></script>
+</head>
+<body onload="go()">
+</body>
+</html>
+`
+
 func start_server(store Store) {
        http.HandleFunc("/fetch", func(w http.ResponseWriter, r *http.Request) {
                var since time.Time
@@ -128,6 +170,10 @@ func start_server(store Store) {
                        r.FormValue("text")}
        })
 
+       http.HandleFunc("/frame", func(w http.ResponseWriter, r *http.Request) {
+               w.Write([]byte(frame_html));
+       })
+
        log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
 }
 
index c878e1903e43f9c80564f28e524f283f29704a85..9459fa8842d07219645bddb8e114eed7fb4fb76e 100644 (file)
@@ -3,3 +3,7 @@ html, body, #outer-table, #history { width: 99.9%; height: 100%; margin: 0; padd
 #say { width: 100% }
 #history { vertical-align: bottom }
 img { width: 1px; height: 1px; }
+iframe { display: none }
+#status span { margin-right: 2em }
+#status span.sad { background-color: #fee }
+#status span.happy { background-color: #efe }
index bc38d0bb79422590121c07f7efe2647b8015ec14..7430f3eb2d6b0c4be1fc42eb4e3edbb293b5cbc2 100644 (file)
@@ -8,7 +8,7 @@
  <script type="text/javascript" src="rc.js"></script>
 </head>
 
-<body>
+<body onload="rcconnect()">
        <table id="outer-table">
                <tr><td id="history"></td></tr>
                <tr><td id="status">&nbsp;</td></tr>
index 8e565c588ffd93a7a5ddd171670a2becf33f2b84..6dc527e724ee1dcb4389a65f0eb7b098634267a5 100644 (file)
@@ -1,23 +1,72 @@
-var servers = ['chkno.net', 'localhost']
+var servers = ['chkno.net', 'localhost'];
 
 var session = Math.random();
+var seen = {};
 
-function addport(server) {
+function rcserverbase(server) {
        // Add the default port if server doesn't contain a port number already
        if (server.indexOf(":") == -1) {
-               return server + ":21059";
+               return "http://" + server + ":21059";
        } else {
-               return server;
+               return "http://" + server;
+       }
+}
+
+function rcaddmessagetohistory(message) {
+       var d = document.createElement("div");
+       d.appendChild(document.createTextNode(message));
+       var h = document.getElementById("history");
+       h.appendChild(d);
+       window.scrollTo(0, document.body.scrollHeight);
+       return d;
+}
+
+function make_seen_key(id, text) {
+       return id.replace(/@/g, "@@") + "_@_" + text.replace(/@/g, "@@");
+}
+
+function receiveMessage(server, time, id, text) {
+       var seen_key = make_seen_key(id, text);
+       if (!(seen_key in seen)) {
+               seen[seen_key] = true;
+               rcaddmessagetohistory(text);
+       }
+}
+
+function receiveMessageEvent(event)  
+{  
+       for (i in servers) {
+               if (event.origin === rcserverbase(servers[i])) {
+                       messages = JSON.parse(event.data);
+                       for (j in messages) {
+                               if ('Time' in messages[j] &&
+                                   'ID'   in messages[j] &&
+                                   'Text' in messages[j]) {
+                                       receiveMessage(servers[i], messages[j]['Time'], messages[j]['ID'], messages[j]['Text']);
+                               }
+                       }
+               }
+       }
+}
+
+function rcconnect() {
+       window.addEventListener("message", receiveMessageEvent, false);  
+       for (i in servers) {
+               // Create a hidden iframe for same-origin workaround
+               var iframe = document.createElement("iframe");
+               iframe.setAttribute("src", rcserverbase(servers[i]) + "/frame");
+               document.body.insertBefore(iframe, document.body.firstChild);
        }
 }
 
 function rcsend(d, message) {
        var id = new Date().getTime() + "-" + session + "-" + Math.random();
+       seen[make_seen_key(id, message)] = true;
        var path = "/speak" +
                "?id=" + encodeURIComponent(id) +
                "&text=" + encodeURIComponent(message);
        for (i in servers) {
-               var uri = "http://" + addport(servers[i]) + path;
+               var uri = rcserverbase(servers[i]) + path;
                var img = document.createElement("img");
                img.setAttribute("src", uri);
                d.appendChild(img);
@@ -26,11 +75,7 @@ function rcsend(d, message) {
 
 function rckeydown(event) {
        if (event.keyCode == 13) {
-               var d = document.createElement("div");
-               d.appendChild(document.createTextNode(document.input.say.value));
-               var h = document.getElementById("history");
-               h.appendChild(d);
-               window.scrollTo(0, document.body.scrollHeight);
+               var d = rcaddmessagetohistory(document.input.say.value);
                rcsend(d, document.input.say.value);
                document.input.say.value = "";
                return false;