There are two things that I still do not have working in my Dart WebSocket implementation: sub-protocols and a scheme for different CRUD operations. The first is (hopefully) just an implementation detail of websockets. The latter is more a matter of me choosing something.
First up sub-protocols, which is an optional means to allow the server to specialize how to handle certain kinds of traffic. In the backend, I might specify the "comics-protocol" to handle changes to my comic book data store:
wsServer.on('request', function(request) {
var connection = request.accept("comics-protocol", request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) { /* ... */ }
}(this is still using WebSocket-Node in my node.js backend)Back in Dart I try variations of:
WebSocket ws;
main() {
HipsterSync.sync = wsSync;
ws = new WebSocket("ws://localhost:3000/", protocols: ["comics-protocol"]);
// ...
}But I only end up with variations of:Internal error: 'http://localhost:3000/scripts/main.dart': Error: line 14 pos 21: invalid arguments passed to constructor 'WebSocket' for interface 'WebSocket'
ws = new WebSocket("ws://localhost:3000/", protocols: ["comics-protocol"]);Digging through the source code a bit, it really seems that the Dart constructor only accepts a single argument. In other words, this seems like a TODO for Dart. No matter, I can live with that in my one-protocol app and can always make a notation that this is not baked when I discuss it in Dart for Hipsters.After reverting, I change my attention to operations other than "read". In the client, I update my websocket-based Hipster MVC sync layer to send specialized messages depending on the CRUD method being used:
wsSync(method, model) {
final completer = new Completer();
String message = "$method: ${model.url}";
if (method == 'delete') message = "$method: ${model.id}";
if (method == 'create') message = "$method: ${JSON.stringify(model.attributes)}";
print("sending: $message");
ws.send(message);
// ...
}On the back end, I then parse these messages with simple regular expressions:connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
if (/^read/.test(message.utf8Data)) {
connection.sendUTF(jsonComics());
}
else if (/^create: (.+)/.test(message.utf8Data)) {
var comic = createComic(JSON.parse(RegExp.$1));
connection.sendUTF(comic);
}
}
});
And amazingly, that just works. When I create a new comic book, the JSON representation of that new object comes back over the websocket, which is already sending the message to the collection via a Future:wsSync(method, model) {
final completer = new Completer();
String message = "$method: ${model.url}";
if (method == 'delete') message = "$method: ${model.id}";
if (method == 'create') message = "$method: ${JSON.stringify(model.attributes)}";
print("sending: $message");
ws.send(message);
// Handle messages from the server, completing the completer
ws.
on.
message.
add((event) {
print("The data in the event is: " + event.data);
completer.complete(JSON.parse(event.data));
});
return completer.future;
}Hitting one out of two goals ain't bad for tonight. I have never used websocket sub-protocols directly, so I have no real idea how important they are. They do seem like a nice-to-have. Regardless, it is good to see my Hipster MVC library holding up so far.Day #326
No comments:
Post a Comment