Monday, March 30, 2009

Shared Object gotchas

If you don't understand how something works, bugs will ensue.

Experience is what you get when you don't get what you want.

I've got a zillion of these sayings.

Anyway.

The SharedObject is a Flash-cookie way to cache data locally. If one's not there when you reference it, it's created, automagically, in memory until you flush it to disk.

Here's the fun part. We have persisted data that goes stale regularly, and we want to test our caches to make sure they're fresh. We have a GUID for general tests, but we also just test to see if the cache "exists"... and that's a problem. How do you know a cache "exists" if it's created the first time you look at it?

Our fix is to check the object's size. If its size is 0 (zero), then it was just created and doesn't in fact "exist". Therefore we know to go to the database to fetch our data.

Tuesday, March 24, 2009

TFTP Packet Factory

Straightforward, but fun.


class PacketFactory # TFTP = RFC 1350, 2347, 2348 (not needed here)
# #
# 2 bytes string 1b string 1b string 1b string 1b ... #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> #
# | 01 |filename| 0 | mode | 0 | opt1 | 0 | value1 | 0 | < #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> #
# string 1b string 1b #
# >-------+---+---~~---+---+ #
# < optN | 0 | valueN | 0 | #
# >-------+---+---~~---+---+ #
# #
# RRQ packet #
# #
# The mode field contains the string "netascii", "octet", or "mail" #
# #
def buildRRQ( filename, mode, *opts )
packet = "\0\1" + filename + "\0" + mode + "\0"
opts.each { |o| packet += o + "\0" }
return packet
end

# #
# 2 bytes string 1b string 1b string 1b string 1b ... #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> #
# | 02 |filename| 0 | mode | 0 | opt1 | 0 | value1 | 0 | < #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> #
# string 1b string 1b #
# >-------+---+---~~---+---+ #
# < optN | 0 | valueN | 0 | #
# >-------+---+---~~---+---+ #
# #
# WRQ packet #
# #
def buildWRQ( filename, mode, blocksize, octets )
packet = "\0\2" + filename + "\0"
+ mode + "\0"
+ blocksize + "\0"
+ octets + "\0"
return packet
end
# #
# 2 bytes 2 bytes n bytes #
# ---------------------------------- #
# | 03 | Block # | Data | #
# ---------------------------------- #
# #
# DATA packet #
# #
def buildDAT( blocknum, data )
return "\0\3" + [blocknum, data].flatten.pack("n*")
end
# #
# 2 bytes 2 bytes #
# --------------------- #
# | 04 | Block # | #
# --------------------- #
# #
# ACK packet #
# #
def buildACK( blocknum ) return "\0\4" + [blocknum].pack("n") end

def buildACKfromDAT( packet )
packet = packet[0..3]
packet[1] = "\04"
return packet
end
# #
# 2 bytes string 1b string 1b...string 1b string 1b #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ #
# | 06 | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | #
# +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ #
# #
# OACK packet [RFC 2347] #
# #
def buildOACK( opt_hash )
packet = "\0\6"
opt_hash.each_pair { |k,v| packet += k + "\0" + v + "\0" }
return packet
end

# #
# 2 bytes 2 bytes string 1 byte #
# ----------------------------------------- #
# | 05 | ErrorCode | ErrMsg | 0 | #
# ----------------------------------------- #
# #
# ERROR packet #
# #
# Error Codes #
# #
# Value Meaning #
# #
# 0 Not defined, see error message (if any). #
# 1 File not found. #
# 2 Access violation. #
# 3 Disk full or allocation exceeded. #
# 4 Illegal TFTP operation. #
# 5 Unknown transfer ID. #
# 6 File already exists. #
# 7 No such user. #
# 8 Invalid option value requested. [RFC 2347] #
# #
def buildERR( errcode, errmsg )
packet = "\0\5" + [errcode, errmsg].pack("na*x")
return packet
end
end

Hiding components functionally

We came up with a neat idea for hiding UI Components. We can apply a Flex version of the Apache Java commons "Predicate" interface, like so:


package blah.blah.blah
{
interface IPredicate
{
function evaluate(): Boolean;
}
}


Then we can pass an implementing object to a subclass of UIComponent, which will trigger its visibility based on the evaluation of the object:


package blah.blah.blah
{
class UIVanishingComponent extends UIComponent
{
var predicateObject:IPredicate;

UIVanishingComponent( po:IPredicate )
{
super();
this.predicateObject = po;
}


.... but now what? The "visible" boolean triggers the dispatch of a SHOW event, which appears to simply alert the listener that the component is now visible... in other words, someone else controls the rendering of this object? So we either create a handler that listens for the Predicate to change its state, or we have to figure out how to intercept or redirect the renderer for this component... or do something else.

Maybe the answer is in using Flex's event model. Anyone know? More to come.

Tuesday, March 17, 2009

Try/Catch with Shared Objects

I've done a bazillion Try/Catches in Java, so in a way this is not a big deal... but I'm a Flex tyro, so in another way this is a big deal.

We store a lot of data locally, as Shared Objects. This reduces the burden on the server and SQL Server. For the first time, though, some data schema changed, which means locally cached data now fails to load, and therefore throws an error. This was easily fixed, with try/catch.


// let's not assume the data is in good condition...
// if it's corrupted or the schema's been changed
// then we throw an error.
try {
cache[cacheName]
= SharedObject.getLocal(cacheName);
}
catch( err:Error ) {
... flag this data to be re-fetched ...
}


Problem solved.

UDP.rb

First step for my TFTP app is to build a simple UDP class.

UDP is a connectionless datagram protocol. You can bundle up some data, send it off to a target machine, and forget about the whole thing. It might not even make it to the destination; nobody cares. This has led the masses to assume that UDP is Unreliable. Consider, however, that UNIX uses UDP for internal messaging protocols. Also consider that, with just a small amount of effort, one can make lock-step communications with ACKing. This is how most networked games push their data around -- TCP would be unacceptable; it's a resource hog. And I always prefer to conserve my resources.


require "socket"

class UDP

def send( msg, host, port, flags=0 )
sock = UDPSocket.new
sock.send( msg, flags, host, port )
sock.close
end

def recv( port, maxblocksize )
sock = UDPSocket.new
sock.bind( "localhost", port )
msg = sock.recv( maxblocksize )
p sock.addr
sock.close
return msg
end
end


Two methods: send() and recv(). How much simpler can you get? I think the lack of a "connection" is a strength of UDP: the thing is just bare bones. I love that.

Here's some quick-and-dirty test code:


client = UDP.new
client.send( msg, server_addr, server_port )

server = UDP.new

loop do
msg = server.recv( server_port, maxbytes )
p msg
exit if msg.chomp.eql?( 'exit' )
sleep 1
end

Monday, March 16, 2009

Old Protocols for a New Web

When I say "New Web" I mean a hypothetical, non-existent internet that uses existing technology in novel ways to improve efficiency and presentation. And Ruby's a great language for prototyping this.


My first project with Ruby is an implementation of TFTP. TFTP is a poor man's FTP. It has three RFC's, all short and sweet. Here are the things that makes it nice:

(1) simple. It's a small protocol, and so anyone can implement it. It's so small and so useful that it's used to boot up routers.

(2) proven. Again, it's one of the first applications ported to a new server. It's how servers get upgraded. That should tell you something about its utility.

(3) relatively non-hackable. Again, due to its simplicity. Especially if it's read-only, i.e. doesn't support writing files.

(4) fast. Because it's built on UDP, there's very low overhead, and no expensive handshaking, TCP nailup costs, etc.

(5) svelte. Again, because it uses UDP, there's no TCP nailup cost, and other associated expensive processing.

(6) synchronous. Because UDP has a willy-nilly transmission style, TFTP synchronizes transfer with numbered packets and does its own ACKs, retransmits, etc. If you thought UDP was unreliable, well, there's ways around that, and those ways are easy.

I'm still working on the implementation, but preliminary results are encouraging. The only discouraging thing is that servers generally lock down UDP transmissions as a rule. That's just something I'm going to have to face: it's not secure as-is, what with the ability to write files at will into the target file system.

BUT, what I want to do is implement browser functionality using TFTP as the transport mechanism. This means it's a read-only protocol... or, more correctly, "writes" are translated as "posts" rather than file transfers. So, no writing files directly into the file system. This puts security on par with current browsers.

Of course, on top of TFTP would have to be a new kind of browser, but that's a nontrivial task that I'll leave for the future. Perhaps it can just be a plugin for Firefox. And then, there's the question of what the presentation layer is going to be. CSS and HTML? Sure, but the scientific community is not served by these hacked styles. I want a TeX display layer. Once again, that's another nontrivial task that I'll have to leave for the future. I'll be happy just to get TFTP working.

The Button and the Event

So there's a Button that triggers a complex event. In short, it calls a remote object thru Granite to JBoss, and does some neato stuff.

Problem: users have (accidentally) double-clicked (and even triple-clicked) that Button, resulting in multiple event dispatches, bad data, and some server-side exceptions.

Normally, I'd disable the Button.

 button.enabled = false; 

Then, when processing is done, I'll re-enable it. Easy, right?

 button.enabled = true;

But, in this case, that's not fast enough -- the user can click that button five or six times before the Button's disabled! (I didn't think that was possible, but it is).

OK then, I'll cut it off at the source: first, I removed the ActionScript inside the "click" attribute of the MX element:


< id="bntCreateMan">


...and I put the code into an explicit handler, like this:


// this method is triggered ONLY by clicking
// the "Create Manifest" button
private function
handleCreateNewManifest(event:MouseEvent):void
{
this.btnCreateMan.removeEventListener(
MouseEvent.CLICK,handleCreateNewManifest);
...
createNewManifest();
}


Add that handler in the creationComplete() method, and voila!

Note the sneaky call in the handler: as soon as we click the Button, the handler removes itself. Thus, subsequent button clicks fall on deaf ears.

Now to put the handler back. We want it back when the manifest data is handled... we have a handler for that of course. So we have:


private function
handleManifestData(event:ResultEvent):void
{
(...some code...)
this.btnCreateMan.addEventListener(
MouseEvent.CLICK,handleCreateNewManifest);
}


How clever of us.

New Problem: That handler, shown above, is invoked by other processes as well. So what really happens is that the event handler gets attached to that Button multiple times, and only removed when the Button is pressed. Aiigh!

The solution is mundane and so old school: instead of manipulating the event listener, we add a Boolean value that the Button's listener uses. If it's false, we go ahead and kick off a manifest creation. Then, back in the ManifestData handler, if the boolean is true then we re-set it.

It's not pretty, it feels a bit kludgy, but it seems to work best.