Thursday, April 03, 2008

Silverlight on Rails

My “spare-time” project is to make a Silverlight plugin for Rails, which allows your controller/view code to either run on the server or the client. It's not available yet, but if you want it faster maybe making a big stink about it to my boss would work. Here's a messy contrived example of what you could do with it, but it makes the point.
class FooController < ApplicationController
  client :time

  def index
    render :text => <<-EOS
      <%= link_to_remote 'Show time', :url => {:action => 'time'} %>
      <br /><div id=”time_div”></div>
    EOS
  end
 
  def time
    @time = Time.now
    render :update do |page|
      page.insert_html :bottom 'time_div', "#{@time.to_s}<br />"
    end
  end
end

If someone visited /foo, it would show them a link saying “Show time”. The line that makes all the difference is client :time, so ...

  • Without client :time
    • link_to_remote call would generate a javascript Ajax.Request(‘/foo/time’)
    • time would be run on the server
    • render :update block would generate javascript to add the “server-generated” time to the bottom on the time div, and then be send back to the client to be run.
  • With client :time
    • a copy of this controller would be sent to the client when someone visits /foo.
    • link_to_remote call would use Silverlight to call the time action on the client
    • render :update block would execute just as it says, without needing to generate javascript.

The beauty of this is with one line you’ve decided to run a bunch of server-side code on the client, and it just happens for you.

This is better than sliced bread!

The Rails way of doing AJAX is by generating HTML on the sever and sending it back to the client with JavaScript that knows how to insert the HTML into the page. This is an awesome way to do it, but can be pretty heavy-weight if you're schlepping around a lot of HTML. In those cases it doesn't save much “response size” over just sending the whole page back again.

People overcome this by pushing some logic to the client. However, this leads to duplicate their Rails logic in JavaScript, and handle serializing/deserializing their ActiveRecord object by hand. This is just flat-out painful, and by the end of it you realize all this server-side Rails code you wrote is wasted.

This pattern of pushing server-side logic to the client is the approach big sites like Twitter and GMail have taken, and it’s really the best way to make web applications feel more responsive ... it’s the whole RIA thing and why Silverlight is cool. Twitter went through a ton of growing pain getting their app to scale well, and I can bet much of it was attributed to “what should we do on the client, and what should we do on the server” (and what should be cached and what should be stored in a database, but that's a different topic altogether).

I’d like to live in a world where you can write your entire app in Ruby, and not have to throw away a ton of code to get some of it running on the client. That’s what I’m trying to accomplish with this project.

You're right, this is better than slided bread!

:-) Let me know what you think about this, and I'll get some code into your hands soon.

As you can probably tell, this personally hit me hard. We had this problem with Assistment. The tutor just wasn’t scaling, and we decided to port the whole thing to JavaScript, eagerly load data onto the client, etc ... all the things we expected our web framework to do for us. This pissed me off to no end, and Ruby in Silverlight is a way to undo those wrongs and make all this possible.

Update: By the way, I got this example working today! Without "client :time" it works as usual, making an AJAX request when clicking on the "Show time" link. But when you add "client :time", clicking on "Show time" simply runs the code on the client! Awesome!

I'm probably going to put this up on RubyForge ... just not sure whether I should make my own project or stick it in the IronRuby? Regardless, code is coming =)

Pidgin and Twitter

I have been searching far and wide for something to turn my Pidgin status messages into Twitter tweets. My search, as well as your, is over: http://arstechnica.com/reviews/apps/pidgin-2-0.ars/4 Scroll down, and you'll see this block of code:
#!/usr/bin/env python

import gtk, dbus, gobject, dbus.glib
import base64, httplib, urllib

TWITTER_USERNAME = "segphault"
TWITTER_PASSWORD = ""

PIDGIN_ACCOUNT = "segphault"
PIDGIN_PROTOCOL = "AIM"

def updateTwitter(username, passwd, statusmsg):
# Generate Twitter authentication header string
auth = {"Authorization": "Basic %s" %
    base64.encodestring("%s:%s" % (username, passwd)).strip()}

# Create a connection to the Twitter web site

connection = httplib.HTTPConnection("twitter.com", 80)
# Use Twitter's REST API to post a status update
connection.request("POST", "/statuses/update.xml",
    urllib.urlencode({"status":statusmsg}), auth)

# Initiate a connection to the Session Bus
bus = dbus.SessionBus()


# Associate Pidgin's D-Bus interface with Python objects
obj = bus.get_object(
  "im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")

def onStatusChanged(acctID, old, new):
# Only update the Twitter status for one specific Pidgin account
if purple.PurpleAccountGetUsername(acctID) == PIDGIN_ACCOUNT and \
    purple.PurpleAccountGetProtocolName(acctID) == PIDGIN_PROTOCOL:
  # Retrieve the current Pidgin status message
  message = purple.PurpleSavedstatusGetMessage(
      purple.PurpleSavedstatusGetCurrent())

  # Update Twitter status with current Pidgin status message
  if message: updateTwitter(TWITTER_USERNAME, TWITTER_PASSWORD, message)

# Bind the onStatusChanged function to Pidgin's AccountStatusChanged event
bus.add_signal_receiver(onStatusChanged,
  dbus_interface="im.pidgin.purple.PurpleInterface",
  signal_name="AccountStatusChanged")


# Start the main loop
gobject.MainLoop().run()

Just paste that into a twitter.py file (for God sakes make sure you don't mess up the white space, this is Python!), set the Twitter/Pidgin configuration info at the top, and run it. Now, whenever your status changes, your Twitter is updated. Oh the magic of Dbus and REST

Wednesday, April 02, 2008

Exploring Silverlight with Dynamic Languages

Last Wednesday all the language teams* in Redmond got together to eat food, drink beer, and talk about plans that are further out than all the time I've been programming. For the more short-sighted individuals like myself, we did some demos of technology that is right around the corner ... the next couple of years in Microsoft-land. Anyway, I did a demo of dynamic languages in the browser, and then did a screencast of it so everyone could see it! It's posted on http://dynamicsilverlight.net/learn, and you can view it using Silverlight, or download it in Quicktime or Windows Media format. Enjoy! * This includes the folks who make C#, VB, IronRuby, IronPython, and F# ... Managed JScript is in-fact made by Microsoft but those guys are from India, so they didn't get to be part of the fun =(