Saturday, April 9, 2011

Bad, hairy, dangerous and irresponsible node+now+couch example

What I feel is lacking many times when I want to learn a new piece of technology is smallest possible complete examples. I find many time how to interact with a new fancy database, or maybe how to communicate between client and server in a simpler, cooler way.

Very seldom do I find examples that do everything I need. What I want, ideally, when toying with a new piece of tech is the following;

1. Full instructions on how to set up any requirements, or at least pointers to good sources.
2. Example of client code, or at least how to get a basic web page up through or in parallel to this new something.
3. Example of how to call the service from whatever client should be used.
4. Example of how to take care of the client requests send on the server-side
5. Example on how to persist information and get it back again, even if that is not really part of the new tech.

What I like to convey, I think,  is that there is need for examples that give a newbie a fully working service for all examples, since even a very simple assumption can be to hard to grok if you are new to a certain scene.

In general I'd think it is better to have working, fully stand-alone examples that one does not understand one bit, than to have an example that is a partial service that is easy to understand. The newbie is a coder after all, and as long he or she have a working example that can be thrown rocks at, eventually he or she will figure the stuff out.

As it happens I've just manages to create (what I hope is) such a thing. What I wanted was to use the new now.js  socket.io client->server and server->client communications proxy.  It's really sweet since it makes JSON-RPC calls really simple. it's like this;

1. Your web page loads the now.js script from your now-powered node.js serverside JavaScript server.
2. The server-script on the node side adds any property to the global 'everyone.now. object.
3. JavaScript in your page gets any property changes propagated to a proxy object called just 'now' on the client.
4. If the properties are functions, the client can call them, and the function call will be executed on th server. No setup code, no nothing. Just call the bloody function, thanks.
5. If the client (your webpage JS code) adds a function of its own the server can call that.
6. This is what you really, really want.

If the browser doesn't support socket.io, a flash wrapper will be used, but all else remain equal.

But then again, you really would want to have some database running wouldn't you? On the server-side, I mean. Couchdb, for example.

What I just did was create a very small, not very clean example that uses now.js, couchdb and cradle on node and a small index.html file which load the now.js script and shows how to call functions exposed back and forth.

The code looks like this;

 var url = require("url");  
 var sys = require("sys");  
 var path = require("path");  
 var fs = require("fs");  
 var inspect = require('eyes').inspector({styles: {all: 'magenta'}});  
 var cradle = require("cradle");  
 cradle.setup({host: "127.0.0.1", port: 5984});  
 var conn = new(cradle.Connection)();  
 var db = conn.database("abc");  
 db.create();  
 var yourHttpServer = require('http').createServer(function(req, response)  
 {  
  /* Serve your static files */  
  var uri = url.parse(req.url).pathname;  
   var filename = path.join(process.cwd(), uri);  
   path.exists(filename, function(exists) {  
     if(!exists) {  
       response.writeHead(404, {"Content-Type": "text/plain"});  
       response.write("404 Not Found\n");  
       response.end();  
       return;  
     }  
     fs.readFile(filename, "binary", function(err, file) {  
       if(err) {  
         response.writeHead(500, {"Content-Type": "text/plain"});  
         response.write(err + "\n");  
         response.end();  
         return;  
       }  
       response.statusCode =200;  
       response.write(file, "binary");  
       response.end();  
     });  
     });  
 });  
 yourHttpServer.listen(8080);  
 var everyone = require("now").initialize(yourHttpServer);  
 everyone.now.msg = "Welcome to TEH wicked nowjs JSON-RPC";  
 everyone.now.foo = function(arg,cb)  
 {  
     sys.puts("Foo called.. arg and everyone.now is...\n");  
     inspect(arg);  
     inspect(everyone.now);  
     db.get('clientlog', function(err, doc)  
     {  
         inspect(doc);  
         if(!doc)  
         {  
             db.save('clientlog', {log: []});  
         }  
         else  
         {  
             var arr = doc.log || [];  
             inspect(arr);  
             arr.push({date: new Date(), message: arg});  
             doc.log = arr;  
             db.save('clientlog', doc,  
             function(err, res)  
             {  
             // Handle success  
                 sys.puts("Error after save was : "+err);  
             })  
         }  
     });  
     cb( "server callback yo!");  
 }  
 everyone.now.bar = function(arg)  
 {  
     sys.puts("now.js function 'bar' called from client. args are..");  
     inspect(arg);  
 }  



What you need to do to get this working is;


0. Don't have a lossy operating system.
1. Install couchdb and create a database named 'abc'
2. git clone node.js + npm;

git clone https://github.com/ry/node.git
./configure and make install first node, then npm

3. npm install cradle (couchdb helper library)
4. npm install now (that thing I just talked about, sheesh)
5. npm install eyes (logging/inspect library)
6. Unzip the nowtest example zipfile somwhere and do 'node nowtest.js'


Ta-daa! :)

Or possibly not, since I just slammed this together. It's bound to have ugly, warty, beer-guzzling bugs. Please tell me about them so I can update the code and links. Thx!

2 comments:

PanosJee said...

Cannot download the .zip :)
Permissions issue

Peter Svensson said...

Typical! Sorry about that. Should be fixed now.