Introducing
Your new presentation assistant.
Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.
Trending searches
http://emo-bot.appspot.com/_wave/robot/jsonrpc
Google Wave APIs
Google Maps APIs
Spreadsheets, Gadgets, App Engine, Blogger, Calendar, Picasa,
OpenSocial, Flickr, Amazon, ...
JavaScript
Python
, PHP
, JavaScript
, Java
pamelafox@
@pamelafox
Tasky
Monty+Syntaxy
Ferry
Poker
Wave Consumer Preview
Wave Developer Preview
Wave Robots API v1
Wave Robots API v2
March 1, 2010
Oct. 1, 2009
June 1, 2009
Outgoing JSON
Incoming JSON
"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"
}
wave
wavesandbox.com!w+YTiBcVOfA
wavelet
conv+root
wavelet
blip
conv+root
b+Dad5DLZkB
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)
participants
wavelet
blip
conv+O4Fsp5kfB
b+O4Fsp5kfA
blip
b+YTiBcVOfB
blip
b+YTiBcVOfD
blip
(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
<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>
tags
http://emo-bot.appspot.com/_wave/robot/jsonrpc
Outgoing JSON
Incoming JSON
document
operations
items+positions
skip 1, delete 1
skip 3, delete 1
skip, insert, delete
"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"
},
{"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"
}
skip 1, delete 1
skip 2, delete 1
skip 3, delete 1
insert 'ABCDE'
app.yaml
appengine_robot_runner.py
main.py
robot.py
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())
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)
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)
http://emo-bot.appspot.com/_wave/capabilities.xml
which protocol version?
which events?
<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>
app.yaml
appengine_robot_runner.py
main.py
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)
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)
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))
http://emo-bot.appspot.com/_wave/capabilities.xml
Outgoing JSON
http://emo-bot.appspot.com/_wave/capabilities.xml
[
{
"method": "robot.notifyCapabilitiesHash",
"params": {
"capabilitiesHash": "0xc5d908e"
}
}
]
cache:
emo-bot.appspot.com
0x10962d0
<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>
app.yaml
appengine_robot_runner.py
main.py
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)
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)
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())
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"
}
appengine_robot_runner.py
main.py
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)
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)),
])
waveservice.py
main.py
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 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)
__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
+
webapp
django_robot_runner.py
wave.py
+
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)
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)
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^_wave/*', 'testproject.testbot.wave.OnWaveAnything')
)
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
main.py
robot.py
appengine_robot_runner.py
...
def profile_json(self):
data = {'name': self.name,
'imageUrl': self.image_url,
'profileUrl': self.profile_url}
return simplejson.dumps(data)
...
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)
....
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)
index.html
blip.py
Makefile
index.rst
sphinx-build
-b html
-d _build/doctrees
. _build/html
=
+
...
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)
...
+
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:
Automation
Versioning
Authentication
Cross-Framework
Language-Appropriate