EmailLinkedInGoogle+TwitterFacebook

https://github.com/devasur/node_webkit_tutorials

Today let us talk about blasphemy. Direct data inserts into databases, listening for messages on message queues, Streaming data between random sockets over custom protocols. None of this is blasphemy. However coded in an HTML page and run on a browser it is nothing less than the demonstration of darkest of dark arts. And I endorse it.

Few days back my colleague and I were discussing the direction client side computing should take. While we did not agree on everything, we had a general consensus that there is a lot more that needs to be done on the client side considering the computing power each device carries. Differing computations back to another machine should only be a last resort – a well deserved bonus for an application. This aligns very well in enterprise products. Here users don’t really care whether application is cross browser compatible in all aspects or whether it is not breaking any browser imposed security bullshit. The application is developed in a controlled environment, there is no rogue code and users want most bang for their buck. From this argument base ditching browser based applications and moving to native, compiled executable seemed the right path to take. However in the engineering world more people are choosing to master only web technologies. So it is a Catch-22 situation when more complex code gets written in native technologies targeting a particular OS – the maintenance will become a nightmare. Moreover, the visible trends from Microsoft and Google with their OS strategies is to use HTML5 predominantly for its own UI rendering. Those signals should not be ignored. Also HTML5 can create some of the most beautiful and responsive user interfaces. This is a plus. But the clincher remains that only so much can be done from the browser!

My devious mind suggested – “Why not we fork chromium and mod it to provide a bunch of hooks to do everything we want?”

The silence ensued was overwhelming. It was not the first time my devious mind had suggested things that sounded simple and straight forward but had proved to be an utter PITA to implement. But in theory it sounded like a possible solution. So we agreed to do some hacking on that front.

The first task of any complex task is to ask Google what it thinks of it. And voilà! It answered in the affirmative that there are other radicals out there who not only are preaching but putting some productive work into such solutions. I was in luck! One project stood out as the perfect match for my quest. So I decided to zero in on it.

Roger Wang’s Node-Webkit :https://github.com/rogerwang/node-webkit

What this gentleman has done is remarkable. He recognized that both node on the server side and chromium on the browser front are using the same Google V8 JavaScript engine to do all the heavy lifting. So, it is not very difficult to make nodejs do its heavy work on a slightly modified chromium. What it means is that everything that you can do from nodejs on the server side, now you can do on the client side. At the same time you have a full access to the browser DOM as well. Hence you can render UI right there where nodejs is executing. That is a great hacker mind.

And what can nodejs do? As of now a lot of things.

- Threads [Check]
- Socket connections to ports talking stuff other than HTTP [Check]
- Database connectivity [Check]
- Communing cating with message Queues [Check]
- Image Processing [Check]

You should checkout the available modules at https://npmjs.org/. All those are easily usable from the browser. Some of those are irrelevant. For example ‘express’ – a great tool to setup a web framework for server side request processing but quite unlikely that you would want to run that on the browser. But if you ever want to, you know you can!

Now with the theory in check I wanted to verify that it actually worked.

Problem 1:

From the browser (don’t cringe I know I am using that term quite loosely here) connect to an image server (written in java) running on my local box and fetch back a series of PNG images and render it on a grid. The clincher here of course is that my server does not talk HTTP. It streams plain png image bytes. Not a problem said node. Let us see.

First I wrote the image Server. That I thought would be the easy part. It is simple server that replies back to any client connection with a random generated image. It is well behaved. You should be able to compile it easily with ‘javac’ alone without any external dependencies.

javac srcorgentelligentsiaimage*.java -d .bin
java -cp .bin  org.entelligentsia.image.Server
Server started and listening on PORT:4444
^C
Initiating orderly shutdown
No pending requests in queue.  Closing socket
Server socket is closed.  Good Bye!
Server Socket is no more accepting connections :socket closed
package org.entelligensia.image;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.imageio.ImageIO;

public class Server {
	ServerSocket serverSocket = null;
	private static final ExecutorService clientThreadExecutors = Executors.newCachedThreadPool();
	private static final ExecutorService serverThreadExecutor = Executors.newSingleThreadExecutor();

	public Server(final int port) throws Exception{
		serverThreadExecutor.submit(new Runnable(){
			public void run() {
				try {
					serverSocket = new ServerSocket(port);
					System.out.println("Server started and listening on PORT:" + port);
					while(!serverSocket.isClosed()){
						try {
							Socket clientSocket = serverSocket.accept();
							System.out.println("New Client connection");
							clientThreadExecutors.submit(new ImageSpitter(clientSocket));
						} catch (java.net.SocketException e) {
							System.out.println("Server Socket is no more accepting connections :" + e.getMessage());
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
	}

	public void shutdown() throws Exception{
		System.out.println("Initiating orderly shutdown");
		clientThreadExecutors.shutdown();
		while(!clientThreadExecutors.isShutdown()){
			System.out.println("Waiting for pending tasks to finish");
		}
		System.out.println("No pending requests in queue.  Closing socket");
		serverSocket.close();
		System.out.println("Server socket is closed.  Good Bye!");
		serverThreadExecutor.shutdown();

	}

	class ImageSpitter implements Runnable{
		Socket clientSocket = null;
		public ImageSpitter(Socket socket){
			this.clientSocket = socket;
		}
		public void run() {
			try {
				OutputStream os = clientSocket.getOutputStream();
				BufferedImage bi = getRandomImage();
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				ImageIO.write(bi, "PNG", bos);
				byte[] image = bos.toByteArray();
				System.out.println("Writing " + image.length + " bytes to output");
				os.write(image);
				os.flush();
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		private BufferedImage getRandomImage(){
			BufferedImage off_Image = new BufferedImage(250, 20,BufferedImage.TYPE_INT_RGB);
			Graphics2D g2 = off_Image.createGraphics();
			g2.drawString(UUID.randomUUID().toString(), 10, 15);
			return off_Image;
		}
	}

	public static void main(String[] args) throws Exception{
		final Server s = new Server(4444);
		Runtime.getRuntime().addShutdownHook(new Thread(){
			@Override
			public void run() {
				try {
					s.shutdown();
				} catch (Exception e) {
					System.out.println("Unable to shutdown server:" + e.getMessage());
				}
			}
		});
		while(true){
		}
	}
}

Now the exciting client part. Here I needed something that can make a socket connection to localhost:4444, and then read the returned byte[] into a local variable. This is my image. I also needed this little something to have the ability to put it as an image on the browser UI.

<!DOCTYPE html>
<html>
<head>
    <title>Image fetcher</title>
</head>
<body>
    <script type="text/javascript">
      var net = require('net');
      var images = []
      for (var i =0 ; i < 5 ; i++){
        var socket = net.createConnection(4444,"localhost");
        socket.on('data',function(data){
            document.write('<img alt="Embedded Image" src="data:image/png;base64,' + data.toString('base64') + '" /> <br>');
        });
        socket.on('error',function(err){
          console.log(err);
        })
      }
    </script>
</body >
</html>

That is it. Here I am using the nodejs base library ‘net’. It has ‘createConnection’ that connects to a ‘HOST’ at a ‘PORT’. It can also send data in but my image server does not need that. As soon it is connected in it starts streaming back an image. Now I connected a listener for ‘data’ event on the ‘socket’. Data comes back as a ‘Buffer’, a native JavaScript object in nodejs world. Converting it into a base64 encoded image data stream was easy once again with a call to ‘Buffer.toString(‘base64′) ‘. Then I am using the omnipresent ‘document.write()’ to put the image on the browser.

To run this code you need node-webkit binary for your platform. Currently it comes in Win32, Linux and MacOS flavors. I could test it only on a Windows 7 (64bit) machine as that was the machine I was using today. Basically you pass either a zip of your client code or the directory containing your client code itself to nw executable.

nw socket_image_fetch

And it should open up your nw browser, which looks and feel just the normal chromium, and assuming the image server is running will show you 5 random images pasted one below the other.

demo

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Post Navigation