eddorre

Extending XMPP and Ruby

August 26, 2008 — 3 Comments

After writing up my XMPP Agent written in Ruby, my friend Billy wrote a comment about a similar system written by Michael Still the author of Practical MythTV. His system for controlling MythTV over XMPP is the gtalkbot.

Curious as to how he worked around some issues, I downloaded the Python source code and stumbled my way through it. I was struck by the fact that he used a plugin architecture that would allow other authors to extend the functionality of his original program.

After seeing that, I decided that I would try something similar.

Without worrying about the XMPP Agent, I set out to code a plugin architecture. In a directory I have the following files:

  • init.rb (should probably be called plugin_loader.rb or something more descriptive)
  • test.rb
  • /plugins (this is a directory)
    • network.rb (inside the plugins directory)
    • system.rb (inside the plugins directory)

The code inside the test.rb file is simple enough:


require 'init'

puts “This is the allowed command set”

puts ALLOWED_COMMANDS

The first line of the code, loads the init.rb file which does the heavy lifting. The init.rb file has a plugin class defined. Other plugins will inherit from this class.

The plugin class is defined as:


require 'find'

class Plugin
  
  attr_reader :allowed_commands
  
  def initialize
    @allowed_commands = %w{ iisreset }
  end
  
  def load_plugins(dir, name="/^[a-z]+.rb/")
    plugins = []
    Find.find(dir) do |path|
        Find.prune if [".",".."].include? path
        plugins << path if File.basename(path).include? ".rb"
    end
    
    plugins.each do |item|
      puts "Loading plugin => #{item}"
      #Load the file
      require File.join(File.dirname(__FILE__), item)
      
      #Extract the file name from the directory name (without .rb extension)
      file_name = File.basename(item, ".rb")
      
      #Create a new object and instantiate it and find the allowed_methods attribute
      c = Object.const_get(file_name.capitalize).new
      puts "Loading command set for plugin #{file_name.capitalize} "
      puts c.allowed_commands
      
      #Add it to the array for allowed_commands
      @allowed_commands << c.allowed_commands
    end
  end
  
  def run_command(command)
    #Strip the command part out of the string - we don't need it anymore
    command.slice!("command: ")
    
    #Create an array for the arguments
    arguments = command.split(" ")
    arguments.delete_at(0) #Delete the first index, this is the command itself without arguments
    
    #Loop through the arguments and then delete them from the command string
    arguments.each { |item| command.slice!(item) }
        
    if @allowed_commands.include? command
      puts "#{command} is an allowed command"
      result = `#{command} #{arguments.join(" ")}` #Backticks are a shortcut for system(yourcommand).
    else
      result = "#{command} cannot be run"
    end
    return result
  end
end

At the end of the init.rb file is the code that actually starts loading the plugins:


app_plugins = Plugin.new app_plugins.load_plugins("./plugins") ALLOWED_COMMANDS = app_plugins.allowed_commands

Now it’s easy to extend the test.rb script by instantiating a new System object (one of our plugins) just by this simple code in the test.rb file:

tester = System.new

I can then call methods defined in the System.rb file (shown below):


tester.test

System.rb file:


class System < Plugin
  
  attr_reader :allowed_commands
  
  def initialize
    @allowed_commands = %w{ set shutdown }  
  end
  
  def test
    "This is a test"
  end
end

Now all of this was just really another proof of concept to find out if it could be done. I’m happy with the results even though I’m sure that there is a better way of doing it.

Site Updates

August 28, 2008 — 0 Comments

Over the past few days, I fell in love with updating my blog engine again. I go through these cycles where after an update, I won’t touch it for a while. Then something comes along that I need to fix and I’ll update a whole bunch of stuff all at once.

This time I went in and added some new features, updates old pages, and fixed some bugs. One of the pages that had been published, but was not publicly accessible, is the changelog. A changelog is a simple log of changes that have occurred during a project that includes new features and bug fixes. This is the first time that it’s been publicly linked. I’ll keep updating this as I add features and continue doing bug fixes.

You can access the changelog from the updated About page which contains updated information about the blog URL name (eddorre) as well as information about the tools that I use. Someday there will be information about me but I haven’t figured out if I’m going to write (hard to write about yourself) or have someone that I know do it.

As my changelog mentions, I’ve added Twitter updates. This just simply lists out the last 5 updates that I’ve made in Twitter via a JSON call. If you’re curious there are full updates available.

I’ve also fixed a nasty bug (that I thought that I had fixed before) where the order of the comments were listed in the wrong order (latest comment first in the list instead of last).

All of those changes are visible to everyone but there are changes that aren’t available for everyone to see. The mostly involve the back end publishing part of the site. Those updates include shoring my Models by using Rails’ new named_scope options as well as including several helper methods here and there.

I’m proud of what I’ve accomplished considering that I work on this in my spare time.

Loading Twitter Badge

August 30, 2008 — 0 Comments

I’ve recently become a Twitter user and I’m starting to use the service on a more regular basis. Considering how much I’m using the service now, I wanted to integrate some of the messages posted there onto my blog.

The folks at Twitter have 3 badges for use with custom made blogging engines. The first two are Flash based and I ruled those out quickly. The third was based on HTML and Javascript. This option gives me the most flexibility as far as configuration was concerned so I chose to go that route.

The process of getting the Twitter badge/updates to render on my site is fairly simple. Include some HTML and the following Javascript files:


<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript" 
src="http://twitter.com/statuses/user_timeline/eddorre.json?callback=twitterCallback2&amp;count=5">
</script>

Usually Javascript files are loaded from the HEAD section of an HTML file, but the Twitter page specifically suggests to move the Javascript lines to the bottom of the page. The rationale behind this is simple; if Twitter is down and the their Javascript files are in the HEAD section then your page won’t load! In theory, by moving the Javascript lines to the bottom of the page they will be activated last after your page has already loaded.

Unfortunately, different browsers render Javascript and the DOM differently and there is no guarantee that a failure of the Twitter service will result in your page loading. The solution is to wait until the DOM is fully loaded before including or calling those Javascript files.

With any modern Javascript library such as Prototype (it’s what I use), jQuery, YUI, etc., it’s simple to interrogate the DOM to find out if it’s been loaded or not. The solution that I wanted was to display a “loading” graphic while the Twitter updates were loading and once they were finished, then the “loading” graphic would disappear; a standard ajax-y interface.

My solution was to render the “loading” graphic, wait until the DOM was loaded and then append the Javascript to the end of the BODY element.

Here is my implementation:


//Wait for DOM to fully load
Event.observe(window, 'load', function () {
	loadTwitterJSFiles("http://twitter.com/javascripts/blogger.js");
        	loadTwitterJSFiles("http://twitter.com/statuses/user_timeline/eddorre.json?callback=twitterCallback2&count=5");

//Hide twitter_spinner div
$('twitter_spinner').hide();
});

function loadTwitterJSFiles(url) {
      var urlRef = document.createElement('script');
      urlRef.type = "text/javascript";
      urlRef.src = url;

      if (typeof urlRef != "undefined")
          document.body.appendChild(urlRef);
};

There were a couple of adjustments that I had to make in order for it to work right. First off, notice the second Javascript line that Twitter gives you. In it, it refers to & where my code just has the & symbol. I had to make this change because I noticed when using the appendChild method it would insert a double & and therefore breaking the URL.

The second thing that I had to modify was the original DOM checking mechanism. In the Prototype documentation it says that you can observe the DOM loading by the following:


document.observe("dom:loaded", function () {
Your code here
});

This never worked out for me as it would never display the “loading” graphic even while getting the updates from Twitter was slow. I’m not sure if it hid it immediately or not, but I changed it to the code above that waits for the “window” to load and it’s worked out for me.

So that’s it. This works in IE7, Safari 3, and Firefox 3.