software

Magic: Ruby 1.8.5 + 1.9.1/Rails/Sinatra and Lighttpd

Ladies and gentlemen, gather ’round! The Great Panini is going to perform an incredible illusion before your very eyes! You will tell your grandchildren of this day and they will not believe you! Take pictures!

The Great Panini will start with a pre-steam machines era CentOS 4 server. He will install two versions of Ruby and they will coexist peacefully! He will then use the blazing fast Lighttpd server to proxy queries to various Ruby frameworks and he will even make it look easy!

Hrm…Sorry.
I am going to tell you how I quickly updated a couple servers with Ruby 1.9.1 and Lighttpd. And it will look easy because it is, in fact, easy.
This article’s aim is to be practical but I will explain as we go along.

The first thing I did was update CentOS to a more recent version. This could take a while but it’s always a good idea to keep a server software up-to-date so I’m sure that your already are almost there:

yum update

In my case, after a couple hours (oops), the update was complete and I rebooted the servers.

Ruby 1.8.5

That’s the easy part because it’s the version of Ruby that currently comes with CentOS. Therefore you can install it using yum:

yum install ruby ruby-devel ruby-irb ruby-rdoc ruby-ri

Ruby 1.9.1

Download the package from ruby-lang.org:

wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p0.tar.bz2
tar zxvf ruby-1.9.1-p0.tar.bz2
cd ruby-1.9.1-p0

The trick, here, is to give all 1.9.1 binaries a different name. Fortunately, configure offers an option for that:

./configure --program-suffix=19

Build and install:

make && make install

Rubygems

Get rubygems from Rubyforge:

wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz
tar zxvf rubygems-1.3.5.tgz
cd rubygems-1.3.5

Note that we are now using our brand new 1.9.1 binaries:

ruby19 setup.rb

Now, make sure your gems are up to date:

gem19 update

Let’s see. We want to use two frameworks: Rails and Sinatra. Installing them could not be simpler:

gem19 install rails
gem19 install sinatra

We will use thin to run our programs:

gem19 install thin

Let’s make sure that thin is run when the server boots up:

thin install

This will create /etc/init.d/thin which we can then link to the appropriate runlevels using chkconfig

We will, when creating Ruby applications, tell thin about the instances it needs to run. This will be done by adding yml files to /etc/thin/

I am going, in this article, to create these applications in /home/yourdirectory/. Of course, use your own directory.

Rails

Let’s create a Rails application:

rails myrailsapp

In the application’s config/ directory, let’s create our thin yml file (thin_myrailsapp.yml)

chdir: /home/yourdirectory/myrailsapp
address: 127.0.0.1
port: 3000
servers: 4
max_conns: 1024
timeout: 30
max_persistent_conns: 512
user: www
group: www
environment: development
pid: tmp/pids/thin.pid
log: log/thin.log
daemonize: true

chdir tells thin where our document root is located. Rails serves documents from document root/public/
address is localhost because that’s what will be used when proxying through Lighttpd
servers is ‘4′ which means that four servers will be instantiated, starting at , i.e. 3000, 3001, 3002, 3003
User and group: I am using the same user and group that Lighttpd runs as for simplicity sake.

Let’s tell Lighttpd about this new application. Edit /etc/lighttpd/lighttpd.conf, or wherever your configuration file is:

$HTTP["host"] =~ "myrailsapp\.yourdomain\.com$" {
        $HTTP["url"] =~ "^/((images|javascripts|stylesheets)/(.*)$)" {
                server.document-root = /home/yourdirectory/myrailsapp/public"
        }
        proxy.balance = "fair"
        proxy.server =  ("" =>
                (
                        ( "host" => "127.0.0.1", "port" => 3000 )
                )
        )
}

I am using the “fair” load balancer because, as the default option, it tries to be…fair, obviously, and isn’t too greedy: it does not compute a hash for each url.

Let’s now tell thin about this application by simply creating a symbolic link in /etc/thin/:

ln -s /home/yourdirectory/myrailsapp/config/thin_myrailsapp.yml /etc/thin/

Restart Lighttpd and start thin:

/etc/init.d/lighttpd restart && /etc/init.d/thin start

I know…supposedly I should be able to simply type ‘lighttpd reload’ and it will reload its configuration files but that does not always seem to work.

Now, the fun stuff:

Go to http://myrailsapp.yourdomain.com:3000 and you should be greeted by Rail’s welcome page.

Now, go to http://myrailsapp.yourdomain.com and you should see the same page, except this time it was proxyied by Lighttpd.

Sinatra

Create your application; e.g. the ubiquitous “hi” application. Again in /home/yourdirectory/mysinatraapp, create hi.rb:

require 'rubygems'
require 'sinatra'
get '/' do
    'Hello world! I love kittens.'
end

Create a config/ subdirectory:

mkdir config && cd config

In the config/ directory, let’s create our thin yml file (thin_mysinatraapp.yml)

rackup: /home/yourdirectory/mysinatraapp/config/mysinatraapp.ru
chdir: /home/yourdirectory/mysinatraapp
address: 127.0.0.1
port: 4567
servers: 4
max_conns: 1024
timeout: 30
max_persistent_conns: 512
user: www
group: www
environment: development
pid: /home/yourdirectory/mysinatraapp/thin.pid
log: /home/yourdirectory/mysinatraapp/thin.log
daemonize: true

Starting at port 4567 because, by convention, it’s Sinatra’s default port when started standalone.

Notice the main difference? Sinatra will rely on rack for its setup, hence the ‘rackup‘ keyword.
Let’s create that rack file (mysinatraapp.ru)

require 'sinatra'
 
Sinatra::Application.default_options.merge!(
  :run => false,
  :env => :development
)
 
require 'hi.rb'
run Sinatra.application

Do not forget Lighttpd:

$HTTP["host"] =~ "mysinatraapp\.yourdomain\.com$" {
         proxy.balance = "fair"
         proxy.server =  ("" =>
                 (
                         ( "host" => "127.0.0.1", "port" => 4567 )
                         # room for more instances
                 )
         )
}

Of course, if you know that some directories will be dedicated to static content you can also check for these directory names and have Lighttpd serve them statically, as shown in myrailsapp’s example.

Restart Lighttpd and thin:

/etc/init.d/lighttpd restart && killall -HUP thin

Test it:

Go to http://mysinatraapp.yourdomain.com:4567 and you should see the message returned by hi.rb.

Now, go to http://mysinatraapp.yourdomain.com and you should see the same page, except, again. it was proxyied by Lighttpd.

Conclusion

As I wrote earlier, this is easy and actually fairly straightforward. It some of this is not working for you, it is likely because I glossed over something I really shoudln’t have. Post a comment and describe your issue and I will gladly help.

If you enjoyed this post, make sure you subscribe to my RSS feed!


S2ajax v1.0 connects simply PHP and JavaScript

S2ajaxHere comes S2ajax v1.0!
And it was long overdue. Six months already since I posted S2ajax says “hi()” I can hardly believe it.

What I think of as v1.0’s main feature is that it is now possible to simply export classes in PHP and these classes can be instantiated in JavaScript. Whenever these instances are modified through asynchronous method calls, these modifications are transparently persisted server-side.

The concept

Is it a PHP class? Is it a JavaScript class? Why, it’s both! The class is defined in PHP on the server. Instances of the class are created on demand using JavaScript on the client. Whatever modifications are made to an instance are serialized on the server.
You can create a complex application using as many classes and instances as you need.

100

Under the hood

The PHP class is exported; the proxy JavaScript code is generated.
Whenever the client needs to access one of the class’ properties/methods, the proxy transparently talks to the class; the class lives server-side.

99

The Client’s point of view

An arbitrary number of instances of the class can be created in JavaScript.
The only hint that you are using a client-server architecture is the fact that when invoking a method, its return value is obtained through a callback. This mechanism allows your client interface to remain responsive while the server is preparing a response.

101

The server’s point of view

S2ajax automatically persists your instances’ state and data between consecutive asynchronous calls. You still get the benefits of the “shared nothing” approach of PHP but complex objects can be manipulated through an unlimited number of clients requests.

102

A code sample

Server-side

Let’s create a class that will increment an instance variable every time a method is invoked. Let’s keep it as simple as possible:

class CounterTester
{
    private $counter;
 
    function __construct() {
        $this->counter = 0;
    }
 
    public function increment_counter() {
        $this->counter++;
        return $this->counter;
    }
}

Clearly, every time increment_counter() is invoked, $counter will be incremented and its new value returned.

Client-Side

First, an instance of our class is created. Then, when a user click on the button labeled ‘Increment counter’, the instance’s increment_counter() method will be invoked and the new $counter value returned to our callback and displayed.

?View Code JAVASCRIPT
<script>
function display_result(val) {
    alert(val); // Display new counter value
}
var counter = new CounterTester();
</script>
<button onclick="counter.increment_counter(display_result);">Increment counter</button>

Note that we could create as many instances of our class as we wish and provided we display the matching buttons, we could independently increment multiple counters.

Get it now!

Click our valiant friend “Octocat”, artistically represented below, to go to S2ajax’s Github page. If you just wish to use the library, look for the [Download] button:

Git!

Git!

If you enjoyed this post, make sure you subscribe to my RSS feed!


Rich-text editor in Sharepoint with Firefox

If, like me, your company’s insistence on using Sharepoint as an Intranet tool contributes to rapid neurons death, there is as least a glimmer of hope: you can still use Firefox without being punished by having to type raw HTML code when editing a page (Sharepoint, unsurprisingly, only likes IE)

Simple steps to use your own rich-text editor:

  1. Install Xinha
  2. Edit SharePoint page
  3. Right-click, select “Open Xinha here!”
  4. Edit! then click [OK]
  5. Now, submit page with all its HTML code. Note: You can edit existing pages as well.

Done!

If you enjoyed this post, make sure you subscribe to my RSS feed!


“n2″ Message Board Software: Update

This is a cross-posting with the nextBBS support board.

Some of you already know about this but keep reading…

Development of nextBBS v2 was steered in a new direction about two months ago and this is for the better.

“n2″ is the software’s new code name. And the change is more than skin-deep because it is actually the result of the merger of three different pieces of software:

+ wtcBB
+ nextBBS v2 “current”
+ My own PHP framework called “Lenses”

The result is a very fast, very user and admin-friendly board with easy install and localization across the board.

This new direction is very exciting for at least two reasons:

1. It allows me to work without being hindered by “youthful” mistakes I had made when developing nBBS v1 such as SEO being an afterthought and an Admin Control Panel that was too intimidating

2. wtcBB and nextBBS share a common philosophy on many levels and integrating both programs allows me to pick the best implementation. A few examples are BBCode editor, sub-sub forums, micro-caching, high logging granularity, editing look and feel in the admin cp…

You can follow progress through my submits and the issues tracker.

Go to my original post to see a few screenshots. I should bring a demo online soon.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Wordpress FLV Player Plugin v2.0

Cat  reloadedClose to two years ago, after quickly putting together my own FLV Player plugin for Wordpress (original post) I added it to Wordpress.org’s already impressive list of plugins. Who knows? Someone else might find it useful (it’s been downloaded more than 4,500 times since then so I guess that means someone did)

Yesterday a few people commented on that original post, thus reminding me of that plugin. It shamed me when I revisited its packaging to find out that it required from its users to download more pieces left and right. So, here it is, brand new v2.0, with everything included, and this means brand new SWF wrapper and brand new Flash file. Hope you forgive the fact that it took me all this time to provide a real self-contained archive.

wordpress-e280ba-flv-player-c2ab-wordpress-pluginsGo to the Plugin Page

Oh, and there is something I would like to address about this plugin. It’s actually a reply to one of the comments I received recently:

What do you mean by “a flash stream”? Does it stream an flv or use progressive download? To stream flash, you need a streaming media server. You should be clear and say what you mean – stop contributing to peoples’ ignorance.

Well, I hope it helps you feel a little less ignorant to know that the answer is “both.” This plugin can stream both types, depending on your use of a http-type or a rtmp-type URI. It can also play live streams. More information can be found here.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Twitterified Client now fully Open-Source

Twitterified Client - Open Sourced!Well, this title says it all!

Find the announcement here.

And, of course, find the source code at GitHub: here.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Bespin in Titanium: From The Jaws Of Victory…

bespin is really an intriguing project. Since I’ve grown frustrated with the inconsistencies between the various code editors that I have been using — I work on Leopard at home and Ubuntu at work — I thought that creating my own editor would be the answer to that. Nothing fancy, mind you. Just something consistent.

My first impulse was to use Flex. And it almost worked! Using mx:html I was able to wrap a nice web page in an otherwise very ActionScript-y application.
And then, catastrophe! Flex Webkit’s canvas implementation is subpar and I could only get a very mamed version of bespin. Nothing usable, anyway.

Thus, I turned to Titanium.
After some light trial and error, I got it to work!

Unfortunately, the result is less than awesome: Titanium’s Webkit gets easily overwhelmed and, worse, crashes reliably ( :g: ) as soon as I ask it to do some medium lifting.

This video shows the original victory followed by the vexing defeat:

Note that, to get it to work, I replaced embed.js with my own version that works around any dojo.request()/eval issue:

?View Code JAVASCRIPT
(function() {
    // -- Load Script
    var loadme = new Array();
    var loadScript = function(src, onload) {
        var embedscript = document.createElement("script");
        embedscript.type = "text/javascript";
        embedscript.src = src;
        embedscript.onload = onload;
        document.getElementsByTagName("head")[0].appendChild(embedscript);
    }
    var onScriptLoaded = function() {
        var src = loadme.shift();
        if(src)
            loadScript(src, onScriptLoaded);
    }
 
    var componentRequires = function() {
        dojo.require("bespin.bespin");
 
        dojo.require("bespin.util.canvas");
        dojo.require("bespin.util.keys");
        dojo.require("bespin.util.navigate");
        dojo.require("bespin.util.path");
        dojo.require("bespin.util.tokenobject");
        dojo.require("bespin.util.util");
        dojo.require("bespin.util.mousewheelevent");
        dojo.require("bespin.util.urlbar");
 
        dojo.require("bespin.client.filesystem");
        dojo.require("bespin.client.settings");
        dojo.require("bespin.client.status");
        dojo.require("bespin.client.server");
        dojo.require("bespin.client.session");
 
        dojo.require("bespin.editor.actions");
        dojo.require("bespin.editor.clipboard");
        dojo.require("bespin.editor.cursor");
        dojo.require("bespin.editor.editor");
        dojo.require("bespin.editor.events");
        dojo.require("bespin.editor.model");
        dojo.require("bespin.editor.toolbar");
        dojo.require("bespin.editor.themes");
        dojo.require("bespin.editor.undo");
 
        dojo.require("bespin.syntax.base"); 
        dojo.require("bespin.syntax.simple._base");
 
        dojo.require("bespin.cmd.commandline");
        dojo.require("bespin.cmd.commands");
        dojo.require("bespin.cmd.editorcommands");
 
        dojo.require("th.helpers"); // -- Thunderhead... hooooo
        dojo.require("th.css");
        dojo.require("th.th");
        dojo.require("th.models");
        dojo.require("th.borders");
        dojo.require("th.components");      
    }
 
    loadScript("js/dojo/dojo.js.uncompressed.js", function() {
        dojo.require = function(src) {          
            loadme.push('js/' + src.replace(/\./g, '/') + '.js');
        }
        componentRequires();
        dojo.require("bespin.editor.component");
        loadScript(loadme.shift(), onScriptLoaded);
    });
})();

As you can see, I override dojo.request() with my own, stack up all the component names, then load them one by one, waiting for each to be fully loaded before moving on.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Twitterified v1.3 is out: bug fixes, usability improvements, Present.ly support

Well, the title pretty much says it all: v1.3 is out and it’s an evolutionary release.

Get it while it’s hot!
(If you are confused as to where to get it, all you need is to go to http://twitterified.com, log in and follow this link)

If you enjoyed this post, make sure you subscribe to my RSS feed!


Twitterified Client v1.3 Almost Ready

I should be able to release this new client tomorrow or day after tomorrow.

I am currently battling a couple bugs with beta support for Present.ly:

If you enjoyed this post, make sure you subscribe to my RSS feed!


Wordpress Toolbar Plugin and Wordpress Prefixes: A Fix

BandaidFirst of all, that’s an awesome plugin that will allow your visitors to have a look at external links while retaining the ability to comment locally on your blog. Get it!

Unfortunately, if you have modified your Wordpress database prefix, for instance because you are using Wordpress MU or the Virtual Module, the toolbar will fail to display.

Here is my very modest fix that will make it work.

1. Open wordpress-toolbar/toolbar.php

2. Find, near the top of the file:

$resultset = $wpdb->get_results("SELECT * FROM wp_options where option_name in ('wordpress_toolbar_social','wordpress_toolbar_excludedomains','wordpress_toolbar_skin','wordpress_toolbar_custom')");

Replace with:

$resultset = $wpdb->get_results("SELECT * FROM {$wpdb->options} where option_name in ('wordpress_toolbar_social','wordpress_toolbar_excludedomains','wordpress_toolbar_skin','wordpress_toolbar_custom')");

3. That’s it!

If you enjoyed this post, make sure you subscribe to my RSS feed!