project-openausbot

Posted by wave_admin
Printer-friendly versionPrinter-friendly version

When I first started looking at Google Wave I thought I would try and build a bridge between Wave and Plone via a project I called ploniebot. However once I had a look at the api documentation and the fact that I'd be talking to Plone via xmlrpc, I figured it might be a good idea to have a go at something simpler.

OpenAusBot is this something simpler. It's a Robot that allows users to query the Open Australia web site, via http and parses the returned XML into pretty format for the other participants of the Wave.

If you want to have a play with it the source is at the repo below:

Source: http://code.google.com/p/openausbot/source/checkout

The other reason I'm putting this page up is to help those people who are trying their hand at building their own robots. I'll go through some of the code and explain it as best as I can.

First off I thought I would go through the entry point for the robot:

if __name__ == '__main__':
    myRobot = robot.Robot('openausbot',
      image_url='http://openausbot.appspot.com/icon.png',
      version='89',
      profile_url='http://openausbot.appspot.com/')
    myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
    myRobot.RegisterHandler(events.BLIP_SUBMITTED, onBlipSubmitted)
    myRobot.RegisterHandler(events.FORM_BUTTON_CLICKED, follow_rep)
    myRobot.Run()

This is the code that sets the robot up. It tells the Wave service what the Robot is called, what icon it's using and what url to use for its profile. As well as this, it also tells the Robot service what actions it needs to watch for and what functions it needs to call when those actions are performed.

In the case of OpenAusBot the Robot is looking for the following actions:

  • WAVELET_SELF_ADDED: This action is reported when the Robot is added to a new wave. The function OnRobotAdded is called which then creates a new Blip and prints a basic help message.
  • BLIP_SUBMITTED: Everytime a Blip is submitted to the Wave server, the Robot is notified. It then calls the onBlipSubmitted function which scans the text contained within the Blip and trys to match it against a list of expected commands. If it gets a match it then attempts to run the associated function.
  • FORM_BUTTON_CLICKED: When a button is clicked this action is registered. For the moment, this is limited to only one part of the Robot, which will be explained later.

Let's have a look at those functions called by the actions:

OnRobotAdded

def OnRobotAdded(properties, context):
    """Invoked when the robot has been added."""
    root_wavelet = context.GetRootWavelet()
    text = "I am the Open Australia Bot. Please find how to use me below."
    text += "Available commands:\n"
    text += "-----------------------------------------------------\n"
    text += "search_rep reps SEAT\n"
    text += "    Find the House Of Representatives Member for SEAT\n"
    text += "search_rep senate STATE\n"
    text += "    Find the Senators for STATE (NSW, QLD, VIC, TAS, SA, WA, ACT, NT) \n"
    text += "-----------------------------------------------------\n"
    root_wavelet.CreateBlip().GetDocument().SetText(text)

This is a pretty simple function. It sets root_wavelet to point to the Root Wavelet of the Wave the Robot has been added to. Assigns the help text to the text variable and then creates the new Blip and sets the Blip contents to that of the text variable.

onBlipSubmitted

def onBlipSubmitted(properties, context):
    """Invoked when a new wavelet blip is created"""
    oakey = "F8c6oBD4YQsvEAGJT8DUgL8p"
    blip = context.GetBlipById(properties['blipId'])
    user = blip.GetCreator()
    words = blip.GetDocument().GetText()
    logging.debug("user: %s" % user)
    logging.debug("words: %s" % str(words))
   
    commands = []
    commands.append(Command("help", r"^[hH][eE][lL][pP]$", help))
    commands.append(Command("search_rep", r"^search_rep ?(?P<HOUSE>[\w]+)? ?(?P<SEAT>[\w\s\w]+)?$", search_rep))
    commands.append(Command("search_party", r"^search_party ?(?P<PARTY>[\w]+)?$", search_party))
    commands.append(Command("search_hansard", r"^search_hansard ?(?P<HOUSE>[\w]+)? ?(?P<STYPE>[\w]+)? ?(?P<SEARCH>[w\s\w]+)?$", search_hansard))
   
    for command in commands:
        pat = re.compile(command.pattern)
        m = pat.search(words)
        if m:
            logging.debug("groupdict: %s" % str(m.groupdict()))
            command(properties, context, user, **m.groupdict())
            return 
    return

This function is a bit more complicated than the OnRobotAdded function.

The first thing that we do is set our variables. Specifically we set the following:

  • oakey: This is the API key that allows the Robot to interact with the Open Australia web API.
  • blip: We set this to point at the blip that has just been submitted
  • user: This is set to the creator of the blip
  • words: This is the text of the just submitted blip

Once we have our variables set we can start working with them to determine whether they match any of our commands. Our commands are in essence a list of regexp that we use to match up against the functions we have written to complete various tasks. Once we have setup this list of commands we then run the words value through the list and if we get a match we perform the associated function and return out of the loop.

follow_rep:

I've included this function for completeness, however it is not in a working state at the moment. This function is called when the FORM_BUTTON_CLICKED action is recieved by the Robot. It is meant to then perform a check to see if there is an already existing wave that is tracking a particular representative and if there is, add the user who clicked the button, or if there isn't create one, and then add the user. However the Wave API has issues with returning the correct waveID of waves created by Robots.

def follow_rep(properties, context):
    #  This function will allow the participant to join an existing wave or create a new one
    member_id = properties['button']
    does_track_wave_exist(member_id, context)