The Place

Last night a friend of mine linked to an article on Rand's In Repose, and naturally I opened up a few tabs to browse his past literary masterpieces. I eventually came across 'The Cave'.

And this got me thinking.

Not about my cave, but about The Place. His Place is World Of Warcraft. (My place certainly isn't a slow running train into London Paddington, but at least I have my precious intorwebnet thanks to my Nokia N95.) I've never got on with WoW. Its never quite felt right to me. Why I (don't) hear you ask? Because I'm still pinning after Ultima Online.

First some backstory of my experience of Vegemites. (A numer of years ago there was an article on Penny Arcade that decided MMOPRG is such an awkward term to use, and advocated using the term Vegemite instead. I agreed with it.Edit: web.archive.org++) I suppose the first MMO that I played was Isengard - a text based MUD - some time around 1997. 1997, when we still had dial-up-modems and had to pay per minute for the telephone calls... luckily my dad also got hooked, so when the quarterly telephone bill came in at around £300, he was equally to blame - thank god.

Around this time Ultime Online was released. And my god did I want. I'd been hooked on the Ultima series since Ultime VI (so much so that I memorized the answers to all the questions that Lord British could ask you.) And Holy of Holies! NTL also had a dial-up service where you didn't have to pay per minute to use it. I was hooked. Origin did indeed Create Worlds.

Back in 1998/9 Ultima Online was a wildly different beast to what it is today - back before EA got thier gubby mits on it. There was just the one facet (Felluca. Each server basically had two copies of the world) - non of this namby-pamby weaker monsters and no PVP that later got introduced when Trammel was introduced.

So what in particular did I like about UO? The crafting. I do think I spent too much time in that game mining near Minoc, or wondering around the forests between Yew and Skara Brae with nothing but a battle axe, some carpentry tools and barely a loin cloth for protection, hoping that I would make it back to my house alive. Yes - player owned housing!

Having a house that you could keep your stuff in, decorate how you want and keep all your possessions in (yes there was a bank like there is in WoW, but it had limited space/weight) was nice, but it wasn't the reason why I would still prefer to play UO than WoW or any of the dozen odd MMOs that I have beta-tested since (me and a housemate at uni went thru a phase of trying to get on every single closed-beta, open-beta, pre-alpha or play test we could).

Its was the leveling system. Or rather the lack of it. WoW you have skills directly related to your level - give or take variations on what skills the player chooses. Ultime Online had no concept of level. No clicking on a person and seeing they are 5 levels lower than you. Each player had a maximum of 700 skill points to distribute as they saw fit among more than around 40 different skills. Want to be proficient with both a sword and with magic? Fine, you can try it. You'd obviously not be as good as a pure mage or a pure fighter due to not having the complementary skills, but you could still kick ass if you did it right.

The other thing I miss about UO that i've not found anywhere else was its Fame and Notoriety system. In UO you'd open the person's paper (or was it papal) doll and see "The Glorious Lady Aliah, Grandmaster Stoic". (She was my guild mistress.) Or "The Dread Lord Azekial, Grandmaster Fighter".

So much more character then "Level 70 Night Elf".

Origin, you truly did create worlds. Then the Destroyer came and pandered to the wimps who complained that they got ganked and had thier silver kryss of power stolen. Didums. You ruined it for all of us.

no comments

Last modified: Tue Nov 13 14:41:15 2007

Catalyst with Lighttpd

I spent most of last week preparing a new server to deploy a project onto a nice shiny new 1&1 Dedicated Server (oh and if you buy something from that link I get a referral bonus - yay!) All the boring stuff like bootstrapping a fresh Debian install onto the disks from a rescue image; fighting the bootloader to make it work with no indication of errors when I make a mistake since I have no physical access to the machine - you know: the ususal.

So once I'd finished those mundane tasks I had to setup the webserver. Previously I'd have gone straight for Apache 2. However I'm deploying a Catalyst application to the machine, and although Catalyst will run under mod_perl, the recommended method is to use FastCGI since it turns out to be a lot less hassle in the long run.

Aims with FastCGI

What I want from my FastCGI deployment:

  • to have two seperate FastCGI managers running, so that whenever I need to upgrade the code, I can shut one down, bring it back up with the new code, then do the same for the other - thus giving me the ability to upgrade the code with no downtime (assuming of course that there are no DB changes that might require downtime etc. etc.)
  • to have the static content served via the webserver, since this is what they do well
  • to not have fastcgi show up anywhere in the URL.

Apache...?

Doing this with Apache+mod_fastcgi seems impossible though, since Apache's handling of FastCGI isn't briliant. To do this in Apache you basically have to create two vhosts (and optionally give them ServerName's that dont resolve externally) and then Alias / /path/to/fastCGI/N.socket.

Still with me? 'cos we're not done yet. In the main vhost for the server (i.e. www.myapp.com) you then have to create a balanced proxy like the following:

ProxyPass / balancer://myapp-cluster
<Proxy balancer://myapp-cluster>
  BalanceMember http://myapp-1.internal
  BalanceMember http://myapp-2.internal
  Allow from all
  Order Allow,Deny
</Proxy>

Complex, no? And whats worse, is that it doesn't even cope with one of the backend FastCGI servers being down - you just get a 500 page served to the user. Bad Apache! Try the other (FastCGI) server please!

The Solution - Lighttpd

After a bit of Googling, it seems like Apache just wont cope with this situation. I've been hearing good things about Lighttpd, particularly that its FastCGI support is native and much better.

The interesting bits of lighttpd config I've used:

server.moudles += (
    "mod_alias",
    "mod_rewrite",
    "mod_redirect",
    "mod_setenv",
)

Pretty self explanatory - load some of the modules we need. The rest of the config goes inside the $HTTP["host"] =~ "www.mysite.com" directive.

    # Let lighttpd take care of serving that static content
    alias.url = (
      "/favicon.ico" => "/var/www/mysite.com/MySite/root/favicon.ico",
      "/js/"   => "/var/www/mysite.com/MySite/root/js/",
      "/css/"  => "/var/www/mysite.com/MySite/root/css/",
      "/tour/" => "/var/www/mysite.com/MySite/root/tour/",
    )

    # rewrite-once will stop processing after the first match
    url.rewrite-once = (
      "^/((?:js|css|tour)/.*)" => "/$1",
      "^/favicon.ico" => "/favicon.ico",
      "^/(.*)" => "/fcgi/$1"            
    )
}

These two bits tell lighttpd to handle all the static content itself, and then forward everything else off to the /fcgi path, which is defined as follows:

  fastcgi.server = (
    "/fcgi" => (
      ( "host" => "127.0.0.1", "port" => 3010, "check-local" => "disable"),
      ( "host" => "127.0.0.1", "port" => 3011, "check-local" => "disable")
    )
  )

Fairly obvious - everything under /fcgi is handled by the FastCGI servers. Note however that this will make Catalyst think it is based at http://mysite.com/fcgi/ which it isn't, so we need to fix it:

    $HTTP["url"] =~ "^/" {
      setenv.add-environment = ( "SCRIPT_NAME" => "/" )
    }

That does the job - Catalyst now thinks its rooted at /, and lighttpd is now handling all the static content itself.

For the completeness-sake, I've included the full config as a single block below.

$HTTP["host"] =~ "^mysite.com" {
    url.redirect = ( "^/(.*)" => "http://www.mysite.com/$1" )
}

$HTTP["host"] =~ "www.mysite.com" {

    # dir listings are bad
    server.dir-listing = "disable"

    server.errorlog    = "/var/log/lighttpd/mysite.com.error.log"
    accesslog.filename = "/var/log/lighttpd/mysite.com.access.log"

    # Let lighttpd take care of serving that static content
    alias.url = (
      "/favicon.ico" => "/var/www/mysite.com/MySite/root/favicon.ico",
      "/js/"   => "/var/www/mysite.com/MySite/root/js/",
      "/css/"  => "/var/www/mysite.com/MySite/root/css/",
      "/tour/" => "/var/www/mysite.com/MySite/root/tour/",
    )

    # rewrite-once will stop processing after the first match
    url.rewrite-once = (
      "^/((?:js|css|tour)/.*)" => "/$1",
      "^/favicon.ico" => "/favicon.ico",
      "^/(.*)" => "/fcgi/$1"            
    )

    fastcgi.server = (
      "/fcgi" => (
        ( "host" => "127.0.0.1", "port" => 3010, "check-local" => "disable"),
        ( "host" => "127.0.0.1", "port" => 3011, "check-local" => "disable")
      )
    )

    $HTTP["url"] =~ "^/" {
      setenv.add-environment = ( "SCRIPT_NAME" => "/" )
    }

}

6 comments

Last modified: Fri Nov 16 20:22:04 2007

WWW::Mechanize::TreeBuilder

Last week at YAPC::EU I saw a few interesting talks, including Stevan's Moose introduction. I found this talk really helpful, maybe in part because I had read through Moose's documentation and cookbook examples once a month or so ago.

So I wanted to learn Moose a bit better, and I'm a firm believer of learning new technologies by actually writing something using them, so I needed a project - not to complex, but also not trivial. And I had just the thing - something I made a start on in June, but sadly only ever existed on my laptop that got stolen. I present the following code snippet for consideration taken from a test suite at work:

my $mech = WWW::Mechanize->new;

ok( $mech->get("$base/index") );
ok( $mech->content =~ m{<div id="header">Welcome To My Site</div>} );

What's wrong with it? Well for a start, it should be using Test::WWW::Mechanize which fixes a few problems. But its still parsing XHTML (you do write XHTML web sites don't you.) using a regexp, which is always a bad idea. What happens if you change the ID of the element, or add a class to it? It'll stop working and your tests will break. My solution? WWW::Mechanize::TreeBuilder:

my $mech = Test::WWW::Mechanize->new;
WWW::Mechanize::TreeBuilder->meta->apply($mech);

$mech->get_ok("$base/index");
is( $mech->look_down(_tag => 'div', id => 'header')->as_trimmed_text, 'Welcome To My Site');

Much better.

no comments


Fotango

Please direct all questions about Fotango to Gina Jones, European Corporate Public Relations Manager at Canon Europe (Ph +44 (0) 208 588 8000).

That is all.

no comments


Server Side JavaScript

So in a bit of down time today between projects, a colleague was working on modifying his blog to syndicate photos from Vox, instead of using flickr as he currently does.

Below is the perl code he used to extract the photos and associated meta-data from the Atom feed the Vox publish. It uses the best (i.e. fully featured and compliant) perl XML parser available - XML::LibXML. Take a look at the following:

my $parser = XML::LibXML->new();

my $xpc = XML::LibXML::XPathContext->new;
$xpc->registerNs('atom', 'http://www.w3.org/2005/Atom');

my $library = $parser->parse_file( $library_file )->documentElement();
my $entries = $xpc->find('/atom:feed/atom:entry',$library);

for my $entry ( $entries->get_nodelist ) {
  my $data = { 
    map { 
     $_ => $xpc->findvalue('atom:'.$_, $entry)
    } qw( id title content published )
  };

  my $link = $xpc->findvalue('atom:link[ @rel = "alternate" ]/@href', $entry);
  

  # Do stuff with the photo now...
}

The code is a bit... verbose. Or rather it seems like it should be possible to make it cleaner. But its not really - this is just how you have to process that XML to get the required data out. (Just to be clear, this is in no part a dig at Vox's atom layout.)

In glancing over his shoulder and wincing, we both agreed that it is in situations like this that E4X really comes into its own. Don't believe me? Well then consider the following JavaScript code which does the same as the above perl fragment.

default xml namespace = 'http://www.w3.org/2005/Atom';
var entries = new XML(library_file)..entry;
 

for each (let entry in entries.*) {
  var data = { };
  for each (let key in ['id', 'title', 'content', 'published'] )
    data[key] = entry[key];
 

  link = entry.link.(@rel="alternate").@href;
 

  // Do stuff with link and data
}

Much cleaner and easier to see what's going on isn't it? Not only that but its about half as many lines. If that was all that needed doing, then JavaScript would have been perfect for the job. Sadly, this was not the case - the next step alluded to by the Do stuff with link and data comment involves downloading the image and creating a thumbnail of it. Not possible with server-side JavaScript. Yet.

As I mentioned in a post about mod_js creating a JavaScript target for SWIG seemed like a good idea. It still does. We looked at Helma - a Rhino/Java based server-side JavaScript platform. It looks good, it really does.

However to me, I would be slightly loathe to use it for three reasons:

  • It's Java, and running Tomcat or some other JVM is a bit memory hungry for my co-lo box.
  • Rhino isn't quite up-to-date with features that I like using from JavaScript 1.7, such as the following:

    [a,b] = [1,2]
    


    While that example is slightly contrived, not having destructive assignment is a bit annoying.
  • It's a Framework, not just a platform. This means that if you want to do something that the framework is not designed for, it's either very hard or actually impossible. I've heard that Ruby on Rails also suffers from this problem to some extent. As Tom points out, this is my perlitism coming out again.

Back to the point of SWIG, Helma should be able to use SWIG since you can generate wrappers for Java already. Saying that, the need to use SWIG with it is reduced since you can (I assume) use native Java.

But I would still like the ability to use SWIG from Spidermonkey, my JS Engine of choice. Watch this space - I'll be working on it.

1 comment