Tuesday, March 13, 2012

Dart Websockets: Take 2

‹prev | My Chain | next›

I got off to a rough start last night with Dart websockets. So tonight, I take a step back and ask, "is the problem Dart or the server?". The problem could very well lie with WebSocket-Node (or my configuration of it).

Since my websocket experience comes nearly entirely in the form of faye (which is awesome), my direct websocket experience is limited. Limited, but I am pretty sure that what I have done so far in Dart ought to work:
#import('dart:dom');
main() {
  WebSocket ws = new WebSocket("ws://localhost:3000/");

  // After open, send a message to the server
  ws.addEventListener('open', (event) {
    bool ret = ws.send("Hello");
    print("Sent: $ret");
  });

  // Handle messages from the server, printing to the console
  ws.addEventListener('message', (event) {
    print("Got an event: $event");
    print("The data in the event is: " + event.data);
  });

  // Print message to the console on WS error
  ws.addEventListener('error', (event) {
    print("whoa: $event");
  });
}
So I try something similar in the Javascript console of Chrome:
var ws = new WebSocket("ws://localhost:3000");
ws.onopen = function(e){ console.log("Connected..."); }
ws.onclose = function(e){ console.log("Disconnected."); }
ws.onerror = function(e){ console.log("ERROR: " + e.data); }
ws.onmessage = function(e){ console.log("Message: " + e.data); }

ws.send("howdy!")
Even in Javascript, I am getting no response:


The web socket just sits there and I see no response hit my onmessage handler. So clearly something is wrong in my WebSocket-node configuration. Looking back to last's work, my first thought is that maybe autoAcceptConnections: true is not doing what I think it does. I switched it under the assumption that I want all connections accepted on this local server, but the documentation seems fairly opposed to this. So I switch it back to false:
wsServer = new WebSocketServer({
  httpServer: app,
  // You should not use autoAcceptConnections for production
  // applications, as it defeats all standard cross-origin protection
  // facilities built into the protocol and the browser.  You should
  // *always* verify the connection's origin and decide whether or not
  // to accept it.
  autoAcceptConnections: false
});
After restarting, and trying the same Javascript in the console, I finally see the desired output:


That autoAcceptConnections seems broken, but again, it could just be my own misunderstanding of what it means. And, since it is incidental to my exploration of Dart websockets, I set aside that question. Instead, I switch back to Dartium to try out my Dart websocket code.

Unfortunately, I am greeted by:


Aw, snap! indeed.

The node.js / WebSocket-node server is logging messages, and it does see the message from Dartium:
Tue Mar 13 2012 23:10:58 GMT-0400 (EDT) Connection accepted.
Received Message: Hello
Tue Mar 13 2012 23:10:58 GMT-0400 (EDT) Peer 127.0.0.1 disconnected.
Ugh. It turns out that actually trying read the data from the websocket is responsible for the crash. If I comment out the line attempting to print out the data:
  // Handle messages from the server, printing to the console
  ws.addEventListener('message', (event) {
    print("Got an event: $event");
    // print("The data in the event is: " + event.data);
  });
It works.

I make a few attempts to cast this properly into a String (which it is), to no avail. Since I am getting "Aw, snap!" instead of a stacktrace, I have very little chance to figure out where things are going awry.

The only other thing that I can think to do is download the most recent build of Dartium and try again. And...
Got an event: Instance of 'MessageEventImplementation'
undefined:1The data in the event is: Hello
It works! Yay!

It is truly amazing how quickly all of this is changing, evolving and getting better. You'd have to be an idiot to even think about writing a book about it at this point. Er...

Regardless of sanity, I am not going to include websockets in the book unless they are worky in the new dart:html (dart:dom is not long for the world). Per the current documentation for dart:html WebSocket, websocket listeners are set via setters:
  // After open, send a message to the server
  ws.onopen = (event) {
    bool ret = ws.send("Hello");
    print("Sent: $ret");
  });
Only when I try that, I get:
Exception: NoSuchMethodException : method not found: 'set:onopen'
Receiver: Instance of '_WebSocketImpl@33cc944a'
Arguments: [Closure]
Stack Trace:  0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:677 col:3
 1. Function: '::main' url: 'http://localhost:3000/main.dart' line:6 col:13
Hrm... You know what? That onopen setter is not terribly darty. Perhaps the usual on.open works?
  // After open, send a message to the server
  ws.
    on.
    open.
    add((event) {
      bool ret = ws.send("Hello");
      print("Sent: $ret");
    });

  // Handle messages from the server, printing to the console
  ws.
    on.
    message.
    add((event) {
      print("Got an event: $event");
      print("The data in the event is: " + event.data);
    });

  // Print message to the console on WS error
  ws.
    on.
    error.
    add((event) {
      print("whoa: $event");
    });
And whoa! That works:


Kudos to the Dart team for that. I went from a relatively recent Dartium build in which dart:html could not even construct a websocket, let alone use it, to a fully functional websocket implementation. It seems that websockets will not be filed under "not working" in Dart for Hipsters. On the down side, that is more to write for the first edition, but those are good problems to have.



Day #324

No comments:

Post a Comment