Wave Robots API: Behind the Scenes

Robots, Gadgets, Embed »
Pamela Fox

"events": [
        {
            "type": "WAVELET_SELF_ADDED",
            "modifiedBy": "pamela.fox@wavesandbox.com",
            "timestamp": 1269400482868,
            "properties": {
                "blipId": "b+FYYeTpCXJ"
            }
        }
    ],
    "wavelet": {
        "creationTime": 1269400451853,
        "lastModifiedTime": 1269400482868,
        "version": 14,
        "participants": [
            "pamela.fox@wavesandbox.com",
            "emo-bot@appspot.com"
        ],
        "creator": "pamela.fox@wavesandbox.com",
        "rootBlipId": "b+FYYeTpCXJ",
        "title": "Dear Diary,",
        "waveId": "wavesandbox.com!w+FYYeTpCXI",
        "waveletId": "wavesandbox.com!conv+root"
    },
  {"params": {
            "blipId": "b+FYYeTpCXJ",
            "waveletId": "wavesandbox.com!conv+root",
            "waveId": "wavesandbox.com!w+FYYeTpCXI",
            "modifyAction": {
                "modifyHow": "REPLACE",
                "elements": [
                    {
                        "type": "IMAGE",
                        "properties": {
                            "url": "http://emo-bot.appspot.com/smile.gif"
                        }
                    }
                ]
            },
            "modifyQuery": {
                "textMatch": ":)",
                "maxRes": -1
            }
        },
        "method": "document.modify",
        "id": "op2"
    }
Events
Operations
Robot
Wave
Wave
Building the Wave Robots API
import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com/'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  appengine_robot_runner.run(emobot, debug=True)
Profiles
http://emo-bot.appspot.com/_wave/robot/profile
{"profileUrl": "http://emo-bot.appspot.com", 
"imageUrl": "https://emo-bot.appspot.com/public/thumbnail.png", 
"name": "Emo Bot"}
app.yaml
application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
  script: main.py
- url: /public/(.*)
  static_files: public/\1
  upload: public/(.*)
import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://wave-skimmy.appspot.com'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  appengine_robot_runner.run(emobot, debug=True)
main.py

....

class ProfileHandler(webapp.RequestHandler):

  def __init__(self, method, contenttype):
    self._method = method
    self._contenttype = contenttype

  def get(self):
    self.response.headers['Content-Type'] = self._contenttype
    self.response.out.write(self._method())

def create_robot_webapp(robot):
  return webapp.WSGIApplication([
                                 ('.*/_wave/robot/profile',
                                  lambda: ProfileHandler(
                                                     robot.profile_json,
                                                     'application/json')),
                                 ('.*/_wave/capabilities.xml',
                                  lambda: CapabilitiesHandler(
                                                     robot.capabilities_xml,
                                                     'application/xml')),
                                 ('.*/_wave/robot/jsonrpc',
                                  lambda: RobotEventHandler(robot)),
                                 ('.*/_wave/verify_token',
                                  lambda: RobotVerifyTokenHandler(robot)),
                                ])

def run(robot):
  app = create_robot_webapp(robot)
  run_wsgi_app(app)
appengine_robot_runner.py
robot.py
...
def profile_json(self):
    data = {'name': self.name,
            'imageUrl': self.image_url,
            'profileUrl': self.profile_url}
    return simplejson.dumps(data)
...
Capabilities
which protocol version?
which events?
Incoming JSON
Outgoing JSON
http://emo-bot.appspot.com/_wave/capabilities.xml
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0"> 
<w:version>0xc5d908e</w:version> 
<w:protocolversion>0.2</w:protocolversion> 
<w:capabilities> 
  <w:capability name="BLIP_SUBMITTED"/> 
  <w:capability name="DOCUMENT_CHANGED"/> 
  <w:capability name="OPERATION_ERROR"/> 
</w:capabilities> 
</w:robot> 
application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
  script: main.py
- url: /public/(.*)
  static_files: public/\1
  upload: public/(.*)
import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  appengine_robot_runner.run(emobot, debug=True)
appengine_robot_runner.py
robot.py
class CapabilitiesHandler(webapp.RequestHandler):

  def __init__(self, method, contenttype):
    self._method = method
    self._contenttype = contenttype

  def get(self):
    self.response.headers['Content-Type'] = self._contenttype
    self.response.out.write(self._method())

def create_robot_webapp(robot):
  return webapp.WSGIApplication([
                                 ('.*/_wave/robot/profile',
                                  lambda: ProfileHandler(
                                                     robot.profile_json,
                                                     'application/json')),
                                 ('.*/_wave/capabilities.xml',
                                  lambda: CapabilitiesHandler(
                                                     robot.capabilities_xml,
                                                     'application/xml')),
                                 ('.*/_wave/robot/jsonrpc',
                                  lambda: RobotEventHandler(robot)),
                                 ('.*/_wave/verify_token',
                                  lambda: RobotVerifyTokenHandler(robot)),
                                ])

def run(robot):
  app = create_robot_webapp(robot)
  run_wsgi_app(app)
app.yaml
main.py
 def capabilities_xml(self):
    """Return this robot's capabilities as an XML string."""
    lines = []
    for capability, payloads in self._handlers.items():
      for payload in payloads:
        handler, event_class, context, filter = payload
        line = '  <w:capability name="%s" >/\n' % capability
        lines.append(line)
    return ('<?xml version="1.0"?>\n'
            '<w:robot xmlns:w="http://.../robots/1.0">\n'
            '<w:version>%s</w:version>\n'
            '<w:protocolversion>%s</w:protocolversion>\n'
            '<w:capabilities>\n'
            '%s'
            '</w:capabilities>\n'
            '</w:robot>\n') % (self.capabilities_hash(),
                               ops.PROTOCOL_VERSION,
                               '\n'.join(lines))
[
    {
       "method": "robot.notifyCapabilitiesHash",
        "params": {
            "capabilitiesHash": "0xc5d908e"
        }
    }
]
cache: 
emo-bot.appspot.com
0x10962d0
Outgoing JSON
http://emo-bot.appspot.com/_wave/capabilities.xml
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0"> 
<w:version>0xc5d908e</w:version> 
<w:protocolversion>0.2</w:protocolversion> 
<w:capabilities> 
  <w:capability name="BLIP_SUBMITTED"/> 
  <w:capability name="DOCUMENT_CHANGED"/> 
  <w:capability name="OPERATION_ERROR"/> 
</w:capabilities> 
</w:robot> 
Problem
Solution
Auto Generation
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0"> 
<w:version>0xc5d908e</w:version> 
<w:protocolversion>0.2</w:protocolversion> 
<w:capabilities> 
  <w:capability name="BLIP_SUBMITTED"/> 
  <w:capability name="DOCUMENT_CHANGED"/> 
  <w:capability name="OPERATION_ERROR"/> 
</w:capabilities> 
</w:robot> 
http://emo-bot.appspot.com/_wave/capabilities.xml
Problem
Solution
  def register_handler(self, event_class, handler, context=None, filter=None):
    payload = (handler, event_class, context, filter)
    self._handlers.append(payload)
    self._capability_hash = (self._capability_hash * 13 +
                             hash(ops.PROTOCOL_VERSION) +
                             hash(event_class.type) +
                             hash(context) +
                             hash(filter)) & 0xfffffff 

  def process_events(self, json):
    parsed = simplejson.loads(json)
    pending_ops = ops.OperationQueue()
    event_wavelet = self._wavelet_from_json(parsed, pending_ops)

    for event_data in parsed['events']:
      for payload in self._handlers.get(event_data['type'], []):
        handler, event_class, context, filter = payload
        event = event_class(event_data, event_wavelet)
        handler(event, event_wavelet)

    pending_ops.set_capability_hash(self.capabilities_hash())
    return simplejson.dumps(pending_ops.serialize())

appengine_robot_runner.py
main.py
application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
  script: main.py
- url: /public/(.*)
  static_files: public/\1
  upload: public/(.*)
app.yaml
import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  appengine_robot_runner.run(emobot, debug=True)
class RobotEventHandler(webapp.RequestHandler):

  def __init__(self, robot):
    self._robot = robot

  def post(self):
    json_body = self.request.body
    json_response = self._robot.process_events(json_body)
    self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
    self.response.out.write(json_response.encode('utf-8'))

def create_robot_webapp(robot):
  return webapp.WSGIApplication([
                                 ('.*/_wave/robot/profile',
                                  lambda: ProfileHandler(
                                                     robot.profile_json,
                                                     'application/json')),
                                 ('.*/_wave/capabilities.xml',
                                  lambda: CapabilitiesHandler(
                                                     robot.capabilities_xml,
                                                     'application/xml')),
                                 ('.*/_wave/robot/jsonrpc',
                                  lambda: RobotEventHandler(robot)),
                                 ('.*/_wave/verify_token',
                                  lambda: RobotVerifyTokenHandler(robot)),
                                ])

def run(robot):
  app = create_robot_webapp(robot)
  run_wsgi_app(app)
Auto Generation
robot.py
Capabilities Hash
  {"params": {
            "blipId": "b+FYYeTpCXJ",
            "waveletId": "wavesandbox.com!conv+root",
            "waveId": "wavesandbox.com!w+FYYeTpCXI",
            "modifyAction": {
                "modifyHow": "REPLACE",
                "elements": [
                    {
                        "type": "IMAGE",
                        "properties": {
                            "url": "http://wave-skimmy.appspot.com/smile.gif"
                        }
                    }
                ]
            },
            "modifyQuery": {
                "textMatch": ":)",
                "maxRes": -1
            }
        },
        "method": "document.modify",
        "id": "op2"
    }
Outgoing JSON
Problem
Solution
Outgoing JSON
  {"params": {
            "blipId": "b+FYYeTpCXJ",
            "waveletId": "wavesandbox.com!conv+root",
            "waveId": "wavesandbox.com!w+FYYeTpCXI",
            "modifyAction": {
                "modifyHow": "REPLACE",
                "elements": [
                    {
                        "type": "IMAGE",
                        "properties": {
                            "url": "http://wave-skimmy.appspot.com/smile.gif"
                        }
                    }
                ]
            },
            "modifyQuery": {
                "textMatch": ":)",
                "maxRes": -1
            }
        },
        "method": "document.modify",
        "id": "op2"
    }

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  emobot.set_verification_token_info('AOijR2fFR5awOGHmU...', '4203')
  appengine_robot_runner.run(emobot, debug=True)

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  emobot.setup_oauth('TOPSECRETKEY', 'TOPSECRETSECRET')
  appengine_robot_runner.run(emobot, debug=True)
 def make_rpc(self, operations):
    data = simplejson.dumps(queue.serialize())

    oauth_request = oauth.OAuthRequest.from_consumer_and_token(
       self._consumer, http_method='POST', http_url=self._server_rpc_base)
    oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer)

    headers = {'Content-Type': 'application/json'}
    headers.update(oauth_request.to_header());
    status, content = self._http_post(
      url=self._server_rpc_base, data=data, headers=headers)
class RobotVerifyTokenHandler(webapp.RequestHandler):

  def __init__(self, robot):
    self._robot = robot

  def get(self):
    token, st = self._robot.get_verification_token_info()
    if self.request.get('st') != st:
      self.response.out.write('Invalid st value passed')
      return
    self.response.out.write(token)


def create_robot_webapp(robot):
  return webapp.WSGIApplication([('.*/_wave/capabilities.xml',
                                  lambda: CapabilitiesHandler(
                                                     robot.capabilities_xml,
                                                     'application/xml')),
                                 ('.*/_wave/robot/profile',
                                  lambda: ProfileHandler(
                                                     robot.profile_json,
                                                     'application/json')),
                                 ('.*/_wave/robot/jsonrpc',
                                  lambda: RobotEventHandler(robot)),
                                 ('.*/_wave/verify_token',
                                  lambda: RobotVerifyTokenHandler(robot)),
                                ])


appengine_robot_runner.py
main.py
waveservice.py
main.py
OAuth Handling
Active Operations
Problem
webapp
+
+
+
__init__.py
appengine_robot_runner.py
blip.py
element.py
errors.py
events.py
oauth/
ops.py
robot.py
search.py
simplejson/
util.py
wavelet.py
waveservice.py
webapp
+
class CapabilitiesHandler(webapp.RequestHandler)
class RobotEventHandler(webapp.RequestHandler)
class ProfileHandler(webapp.RequestHandler)
class RobotVerifyTokenHandler(webapp.RequestHandler)
def appengine_post(url, data, headers)
def operation_error_handler(event, wavelet)
def create_robot_webapp(robot, debug=False)
def run(robot, debug=False, log_errors=True)
Solution
from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^_wave/*', 'testproject.testbot.wave.OnWaveAnything')
)
import logging

from waveapi import django_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass


def OnWaveAnything(request):
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  emobot.setup_oauth(credentials.KEY, credentials.SECRET)
  return django_robot_runner.handle(request, emobot)
import logging
import sys

from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.shortcuts import render_to_response

import events

def CapabilitiesHandler(request, robot):
  return HttpResponse(robot.capabilities_xml(), content_type='text/xml')

def ProfileHandler(request, robot):
  response = robot.profile_json()
  return HttpResponse(response, content_type='text/plain')

def RobotEventHandler(request, robot):
  if request.method == 'POST':
    json_body = request.raw_post_data

    json_body = unicode(json_body, 'utf8')
    json_response = robot.process_events(json_body)
    
    response = (json_response.encode('utf-8'))
    return HttpResponse(response, content_type='application/json; charset=utf-8')
  else:
    return HttpResponse('GET not implemented')


def operation_error_handler(event, wavelet):
  if isinstance(event, events.OperationError):
    logging.error('Previously operation failed: id=%s, message: %s',
                  event.operation_id, event.error_message)

def RobotVerifyTokenHandler(request, robot):
  token, st = robot.get_verification_token_info()
  if request.GET['st'] != st:
      response = 'Invalid st value passed'
      return
  response = token
  return HttpResponse(response)

def handle(request, robot):
  robot.register_handler(events.OperationError, operation_error_handler)
  if request.path.find('_wave/capabilities.xml') > -1:
    return CapabilitiesHandler(request, robot)
  if request.path.find('_wave/robot/profile') > -1:
    return ProfileHandler(request, robot)
  if request.path.find('_wave/robot/jsonrpc') > -1:
    return RobotEventHandler(request, robot)
  if request.path.find('_wave/verify_token') > -1:
    return RobotVerifyTokenHandler(request, robot)
+
urls.py
wave.py
django_robot_runner.py
Non-App Engine Robots
Behind the Scenes
Google Maps APIs
Google Wave APIs
Spreadsheets, Gadgets, App Engine, Blogger, Calendar, Picasa,
OpenSocial, Flickr, Amazon, ...
JavaScript
Python
, PHP
, JavaScript
, Java
About Me
Wave Robots API v1
Wave Developer Preview
June 1, 2009
March 1, 2010
Wave Robots API v2
Wave Consumer Preview
Oct. 1, 2009
API History
wave
wavelet
wavelet
conv+O4Fsp5kfB
conv+root
wavesandbox.com!w+YTiBcVOfA
wavelet
conv+root
blip
b+O4Fsp5kfA
b+YTiBcVOfB
blip
blip
b+YTiBcVOfD
blip
b+Dad5DLZkB
tags
participants
<body>
  <line a="c"></line>
   The pizza was awesome, 
   can't believe you missed it!
  <line></line>
  <image url="http://www.p.com/p.gif">
  <line></line>More pics here.
 </body>
(17,24) : style/fontSize=1.3em
(17,24) : style/fontWeight=bold
(72,76) : link=http://www.p.com/p.gif
(1,77) : lang=en

b+Dad5DLZkB
blip
Google Wave Conversation Model
Operational Transforms
document
items+positions
operations
skip, insert, delete
insert 'ABCDE'
skip 3, delete 1
Lessons Learned
Automation
Versioning
Authentication
Cross-Framework
Language-Appropriate
Google Wave Robot Python API v2
============================================

The :mod:`blip` Module
-------------------------
.. automodule:: blip
   :members:
   :undoc-members:

The :mod:`wavelet` Module
-------------------------
.. automodule:: wavelet
   :members:
   :undoc-members:

The :mod:`robot` Module
-------------------------
.. automodule:: robot
   :members:
   :undoc-members:
index.rst
...
class Blips(object):
  """A dictionary-like object containing the blips, keyed on blip ID."""
 
 def get(self, blip_id, default_value=None):
    """Retrieves a blip.

    Returns:
      A Blip object. If none found for the ID, it returns None,
      or if default_value is specified, it returns that.
    """
    return self._blips.get(blip_id, default_value)
...
blip.py
sphinx-build 
   -b html 
   -d _build/doctrees   
   . _build/html

+
+
Makefile
=
index.html
Documentation
Events -> Operations
 def process_events(self, json):
    parsed = simplejson.loads(json)
    pending_ops = ops.OperationQueue()
    event_wavelet = self._wavelet_from_json(parsed, pending_ops)

    for event_data in parsed['events']:
      for payload in self._handlers.get(event_data['type'], []):
        handler, event_class, context, filter = payload
        event = event_class(event_data, event_wavelet)
        handler(event, event_wavelet)

    return simplejson.dumps(pending_ops.serialize())
appengine_robot_runner.py
app.yaml
main.py
class RobotEventHandler(webapp.RequestHandler):

  def __init__(self, robot):
    self._robot = robot

  def post(self):
    json_body = self.request.body

    json_body = unicode(json_body, 'utf8')
    json_response = self._robot.process_events(json_body)

    self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
    self.response.out.write(json_response.encode('utf-8'))

def create_robot_webapp(robot):
  return webapp.WSGIApplication([
                                 ('.*/_wave/robot/profile',
                                  lambda: ProfileHandler(
                                                     robot.profile_json,
                                                     'application/json')),
                                 ('.*/_wave/capabilities.xml',
                                  lambda: CapabilitiesHandler(
                                                     robot.capabilities_xml,
                                                     'application/xml')),
                                 ('.*/_wave/robot/jsonrpc',
                                  lambda: RobotEventHandler(robot)),
                                 ('.*/_wave/verify_token',
                                  lambda: RobotVerifyTokenHandler(robot)),
                                ])

def run(robot):
  app = create_robot_webapp(robot)
  run_wsgi_app(app)
robot.py
application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
  script: main.py
- url: /public/(.*)
  static_files: public/\1
  upload: public/(.*)
import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
  ':)' : 'smile',
  ':(' : 'frown',
  '(heart)': 'heart'
  }

def ProcessBlip(event, wavelet):
  blip = event.blip
  for emoticon in emoticons:
    r = blip.all(emoticon)
    if r:
      r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
  pass

if __name__ == '__main__':
  emobot = robot.Robot('Emo Bot', 
    image_url='http://emo-bot.appspot.com/public/thumbnail.png', 
    profile_url='http://emo-bot.appspot.com/')
  emobot.register_handler(events.BlipSubmitted, ProcessBlip)
  emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
  appengine_robot_runner.run(emobot, debug=True)
Incoming JSON
  {"params": {
            "blipId": "b+FYYeTpCXJ",
            "waveletId": "wavesandbox.com!conv+root",
            "waveId": "wavesandbox.com!w+FYYeTpCXI",
            "modifyAction": {
                "modifyHow": "REPLACE",
                "elements": [
                    {
                        "type": "IMAGE",
                        "properties": {
                            "url": "http://wave-skimmy.appspot.com/smile.gif"
                        }
                    }
                ]
            },
            "modifyQuery": {
                "textMatch": ":)",
                "maxRes": -1
            }
        },
        "method": "document.modify",
        "id": "op2"
    }
"events": [
        {
            "type": "WAVELET_SELF_ADDED",
            "modifiedBy": "pamela.fox@wavesandbox.com",
            "timestamp": 1269400482868,
            "properties": {
                "blipId": "b+FYYeTpCXJ"
            }
        }
    ],
    "wavelet": {
        "creationTime": 1269400451853,
        "lastModifiedTime": 1269400482868,
        "version": 14,
        "participants": [
            "pamela.fox@wavesandbox.com",
            "wave-skimmy@appspot.com"
        ],
        "creator": "pamela.fox@wavesandbox.com",
        "rootBlipId": "b+FYYeTpCXJ",
        "title": "Dear Diary,",
        "waveId": "wavesandbox.com!w+FYYeTpCXI",
        "waveletId": "wavesandbox.com!conv+root"
    },
Outgoing JSON
Google Wave
Behind the Scenes
Google Wave Robots API
Examples
pamelafox@
@pamelafox
skip 3, delete 1
skip 1, delete 1
skip 1, delete 1
skip 2, delete 1
Ferry
Tasky
Monty+Syntaxy
Poker
http://emo-bot.appspot.com/_wave/robot/jsonrpc
http://emo-bot.appspot.com/_wave/robot/jsonrpc

Loading comments...

Please log in to add your comment.

Report abuse

More presentations by Pamela Fox

More prezis by author