TINN Is Not Node

TINN Is Not Node

I had other meanings for this acronym, but I like this one.

What is it then? Well, I often post snippets of code to my blog, and otherwise want to show someone how to do something. TINN is an encapsulation of a minimal environment which can quickly run interesting snippets of code.

TINN is unapologetic in its Windows only support. Although I have various Linux and Apple machines laying about the house, my primary development platform is Windows, and I want to get the most out of it without having to compromise for cross platform compatibility.

So, what’s in the box? Well, tinn.exe contains a few things.

  • LuaJIT compiler
  • LPeg Module
  • ZLib
  • Some LAPHLibs snippets
  • Http Stack
  • Win32 Interop – GDI32, User32, Kernel32

What can you do with it?

The primary project is here: TINN

Some Snippets of Example code are here:  TINNSnips

Since TINN is a Lua runtime, you can run any typical Lua script as normal:

 

— hello.lua
print("Hello, World!");

You could of course also create a fairly rudimentary static web page server as well:

local WebApp = require("WebApp")

local HttpRequest = require "HttpRequest"
local HttpResponse = require "HttpResponse"
local URL = require("url");
local StaticService = require("StaticService");

local HandleSingleRequest = function(stream, pendingqueue)
  local request, err  = HttpRequest.Parse(stream);
  local urlparts = URL.parse(request.Resource)
  local filename = './wwwroot'..urlparts.path;
  local response = HttpResponse.Open(stream);

  StaticService.SendFile(filename, response)

  -- recycle the stream in case a new request comes
  -- in on it.
  return pendingqueue:Enqueue(stream)
end

--[[ Configure and start the service ]]
Runtime = WebApp({port = 8080, backlog=100})
Runtime:Run(HandleSingleRequest);

This is the full extent of the service. By using the WebApp construct, all the connection handling is done for you. Every time there is a new http request, your routine will be called. If you’re used to using node.js, you might find a few familiar things, like async sockets by default, but you’ll also find things to be a bit different, like the fact that HttpRequest and HttpResponse are totally separable from the streams they may be dealing with.

Another strength for networking is that although the http protocol is strongly supported, there’s nothing that prevents you from just using lower level things like sockets directly, so you can support your own protocols. Having low level bit handling routines built in and easily exposed makes it relatively easy to deal with protocols, and various binary packings of data.

On the more Windows specific side, here is a typical “Game” window. Basically, a timer driven environment that also deals with mouse and keyboard events:

local GameWindow = require "GameWindow"
local GDI32 = require "GDI32"
local StopWatch = require "StopWatch"

function mouseinteraction(msg, wparam, lparam)
  print(string.format("Mouse: 0x%x", msg))
end

function keyboardinteraction(msg, wparam, lparam)
  print(string.format("Keyboard: 0x%x", msg))
end

function randomrect(win)
  local width = math.random(2,40)
  local height = math.random(2,40)
  local x = math.random(0,win.Width-1-width)
  local y = math.random(0, win.Height-1-height)
  local right = x + width
  local bottom = y + height

  local brushColor = RGB(math.random(0,255),math.random(0,255),math.random(0,255))
  win.GDIContext:SetDCBrushColor(brushColor)
  win.GDIContext:RoundRect(x, y, right, bottom, 0, 0)
end

local sw = StopWatch.new();

function ontick(win, tickCount)
  local black = RGB(0,0,0)
  win.GDIContext:SetDCPenColor(black)

  for i=1,win.FrameRate do
    randomrect(win)
  end

  local stats = string.format("Seconds: %f  Frame: %d  FPS: %f",
    sw:Seconds(), tickCount, tickCount/sw:Seconds())

  win.GDIContext:Text(stats)
end

local appwin = GameWindow({
  Title = "Game Window",
  KeyboardInteractor = keyboardinteraction,
  MouseInteractor = mouseinteraction,
  FrameRate = 120,
  OnTickDelegate = ontick,
  Extent = {1024,768},
})

appwin:Run()

Of course, I can combine things like UI with networking, as in the screenshare snip.

As a multi-tool, how does this fit in with my typical dev toolchain?  Well, I was recently trying to prototype a WebSocket implementation.  Having the bit twiddling capabilities of TINN helped me to make quick work of that prototype.  Same thing for being able to read/write .bmp files.  Then I wanted to try out a multi-connected http server, that could scale to a few hundred or thousand concurrent connections.  TINN could handle all of these tasks fairly easily.

The real beauty though comes from being rooted in LuaJIT.  LuaJIT is THE best interop mechanism for native code libraries.  I have seen nothing more efficient than LuaJIT’s ability to fairly easily just take a C header file and give you scriptable access to the represented library.  For Windows programming, this is a tremendous boon.  Now, when I want to try out some new interface, such as Kinect, I can just wrap the header, and start programming.  With other solutions, I have to actually write a fair amount of C glue code before the interop will work.  Depending on the complexity of  the library, that might be a fair amount of error prone code.  Of course, LuaJIT allows you to write your interop layer that way as well, if what you get through the ffi mechanism just doesn’t cut it for you (interop to C++ for example).

So, TINN is a nice multi-tool.  You can use it to prototype stuff, you can use it to put things into production directly if you like.  Since the code is Lua, you could even convert it to JavaScript fairly easily if you want.  At any rate, now that I have this multi-tool, and it’s readily available as a compact standalone executable, all my future examples will use TINN as the driver.

 

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s