Google Wave API開発ガイド(後編)

JavaとPythonでGoogle WaveのRobotを作るには


株式会社鳥人間
郷田まり子
2009/10/22


【Python編】App Engineの利用準備

 まずは、Robot開発のための環境を整えます。Pythonのバージョン2.5以上が必要です。コマンドラインから「python --version」と入力してチェックしてください。2.5未満だったら、適宜アップデートをしてください。

 Robotの開発には、App Engine用のSDKが必要です。App Engine SDKを「Google App Engine SDK for Python」からダウンロードします(すでにインストール済みの方は、この作業は必要ありません)。Windows用・Mac OS X用・Linux用の3種類があるので、OSに合ったものを選んでください。

Windowsの場合

 ダウンロードした「GoogleAppEngine_XXX.msi」のアイコンをダブルクリックします。

 インストーラが起動するので、利用規約に同意したら指示に従って進めていきます。すると、SDKと「Google App Engine Launcher」がインストールされます(※注:Windows版にApp Engine Launcherが同梱されるようになったのは、バージョン1.2.5以降です。GUIで簡単にアプリケーションの作成・デプロイができるので、これより古いバージョンをお使いの方はぜひアップデートしてみてください)。

Google App Engine Launcher(Windows)

Mac OS Xの場合

 ダウンロードしたディスクイメージを開き、「GoogleAppEngineLaumcher.app」をアプリケーションフォルダにドラッグ&ドロップします。

Google App Engine Launcher(Mac OS X)

Robot開発用Pythonライブラリ

 SDKのインストールが済んだら、どこか適当な場所に作業ディレクトリを作ってください。 次に、Robotを開発するためのPythonライブラリを入手します。「Wave Robot Python Client Library」をダウンロードして伸張し、ディレクトリ名を「waveapi」に変更して作業ディレクトリ直下に置きます。下記コマンドのように、Subversionで取得する方法もあります。

localhost$ svn checkout http://wave-robot-python-client.googlecode.com/svn/trunk/src/waveapi waveapi

【Python編】設定ファイルを書く

 まずは、アプリケーションの設定ファイル、app.yamlを書きます。

    application: applicationName
    version: 1
    runtime: python
    api_version: 1
 
    handlers:
    - url: /_wave/.*
      script: applicationName.py
    - url: /assets
      static_dir: assets

 application要素には、アプリケーションIDを記述します。App EngineのWebインターフェイスから登録したIDを書きます。

    application: applicationName

 handlers要素の下に、スクリプトハンドラと静的ファイルハンドラを記述します。アプリケーションディレクトリ内のパスとURLを関連付けていきます。まずは、Robot本体です。

    - url: /_wave/.*
      script: applicationName.py

 ここに、Robot本体となるスクリプトのファイル名を指定します(アプリケーションIDと一致している必要はありません)。静的なファイルのマッピングをするには、script要素ではなく、static_dir要素に記述します。Robotのアイコンなどを置く場合は、ここで指定したディレクトリに格納します。

    - url: /assets
      static_dir: assets

【Python編】コード部分の実装

 PythonでRobotを実装していきます。まずは、スクリプト全体をご覧ください。

from waveapi import events
from waveapi import model
from waveapi import robot
 
def OnParticipantsChanged(properties, context):
  added = properties['participantsAdded']
  for participant in added:
    Greet(context, participant)
 
def OnRobotAdded(properties, context):
  root_wavelet = context.GetRootWavelet()
  root_wavelet.CreateBlip().GetDocument().SetText('Hi, everybody!')
 
def OnBlipCreated(properties, context):
  blip = context.GetBlipById(properties['blipId'])
  blip.GetDocument().AppendText(':-)')
 
def Greet(context, participant):
  root_wavelet = context.GetRootWavelet()
  root_wavelet.CreateBlip().GetDocument().SetText('Welcome, ' + participant)
 
if __name__ == '__main__':
  myRobot = robot.Robot('appName',
      image_url='http://appName.appspot.com/assets/icon.png',
      version='1',
      profile_url='http://appName.appspot.com/')
  myRobot.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged)
  myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipCreated)
  myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
  myRobot.Run()

 このコードの中身を追っていきます。

from waveapi import events
from waveapi import model
from waveapi import robot

 まず冒頭で、Robot開発に必要なライブラリをインポートしています。

イベント操作

 次に、main関数でRobotを定義し、イベントハンドラを追加し、Robotを起動します。

if __name__ == '__main__':
  myRobot = robot.Robot('appName',
      image_url='http://appName.appspot.com/assets/icon.png',
      version='1',
      profile_url='http://appName.appspot.com/')
  myRobot.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged)
  myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipCreated)
  myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
  myRobot.Run()

 Robotの定義には、Robotの名前(アプリケーションIDと同一である必要はありません)と、そのほかのオプションとしてアイコンのURL・バージョンを渡します。

  myRobot = robot.Robot('appName',
      image_url='http://appName.appspot.com/assets/icon.png',
      version='1',
      profile_url='http://appName.appspot.com/')

 myRobot.RegisterHandler(eventType, eventHandler)では、イベントの種類を指定して、イベントハンドラを追加しています。

  myRobot.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged)

 参加者の変更時(events.WAVELET_PARTICIPANTS_CHANGED)に、前半で定義したOnParticipantsChanged 関数を呼び出すようにしています。

 イベントの種類として、以下のようなものがあります。

表2 Pythonのイベントハンドラ
イベント種別 イベントの概要
event.BLIP_CONTRIBUTORS_CHANGED Blipの編集者の変更
event.BLIP_DELETED Blipの削除
event.BLIP_SUBMITTED Blipの送信
event.BLIP_TIMESTAMP_CHANGED Blipの更新
event.BLIP_VERSION_CHANGED Blipの更新
event.DOCUMENT_CHANGED 文書内容の変更
event.FORM_BUTTON_CLICKED フォームのボタンがクリックされたとき
event.WAVELET_BLIP_CREATED Blipの新規作成
event.WAVELET_BLIP_REMOVED Blipの削除
event.WAVELET_PARTICIPANTS_CHANGED 参加者の変更(参加・退室)
event.WAVELET_SELF_ADDED Robot自身の参加
event.WAVELET_SELF_REMOVED Robot自身の退室
event.WAVELET_TIMESTAMP_CHANGED Waveletの更新
event.WAVELET_TITLE_CHANGED Waveletのタイトルの変更
event.WAVELET_VERSION_CHANGED Waveletのバージョンの変更

注意 「使用していなかったイベントに対するハンドラを登録したくなった場合」

Robotのコードに変更を加え、いままで使用していなかった種類のイベントに対するハンドラを登録したくなった場合には、下記のようにRobotのバージョンを上げてください。

  myRobot = robot.Robot('appName',
      image_url='http://appName.appspot.com/assets/icon.png',
      version='2',
      profile_url='http://appName.appspot.com/')

Robot生成時の引数としてversionを渡していますが、これがRobotのバージョン(≠アプリケーションのバージョン)です。これを更新しないと、新たに対応しようとする種類のイベントに反応しません。

WaveサーバがRobotを呼び出したとき、まず、どの種類のイベントが発生したときにRobotとのHTTP通信を行うべきかを把握するために、「http://<appName>.appspot.com/_wave/capabilities.xml」を読み込みます。

このXMLファイルはRobotアプリケーション側が自動生成するもので、Robotの設定が書かれています。例えば、先ほどのコードからは、以下のようなXMLファイルが生成されます。


<?xml version="1.0"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:version>2</w:version>
<w:capabilities>
<w:capability name="BLIP_SUBMITTED"/>
<w:capability name="WAVELET_PARTICIPANTS_CHANGED"/>
<w:capability name="WAVELET_SELF_ADDED"/>

</w:capabilities>
<w:profile name="appName" imageurl="http://appName.appspot.com/icon.png" profileurl="http://appName.appspot.com/"/>
</w:robot>

Robotのバージョン番号はこの設定ファイルに埋め込まれますが、この値に変更がない場合、設定がキャッシュされてしまいます。

Blipを生成

 先ほどイベントハンドラに登録した関数を見ていきます。Waveの投稿内容や参加者情報にアクセスし、発言を加えたりしています。

 まずは、自分自身が参加した直後の処理。main関数内のmyRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)の部分で登録したものです。

def OnRobotAdded(properties, context):
  root_wavelet = context.GetRootWavelet()
  root_wavelet.CreateBlip().GetDocument().SetText('Hi, everybody!')

 Blipを生成し、その内容をセットしています。これで、Robotは自分自身が参加したときに「Hi, everybody!」というあいさつをするようになります。Blipは、Waveにおける会話の単位です。画面内では枠に囲まれた外観をしていて、Blipの中には、さらにBlipを子要素として付加していって木構造を作ることができます。

枠に囲まれた部分がBlip

Blipの追加

 次は、参加者に変更があったときの処理です。main関数内の、「myRobot.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged)」の部分で登録したものです。

def OnParticipantsChanged(properties, context):
  added = properties['participantsAdded']
  for participant in added:
    Greet(context, participant)

 properties['participantsAdded']で、新たに追加したユーザーのIDのリストを取得し、ループで回してあいさつをします。

def Greet(context, participant):
  root_wavelet = context.GetRootWavelet()
  root_wavelet.CreateBlip().GetDocument().SetText('Welcome, ' + participant)

 Blipを生成し、「Welcome, <ユーザーID>」という文字列をセットしていきます。新規Blipが生成されたときの処理です。main関数内の、「myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipCreated)」の部分で登録したものです。

def OnBlipCreated(properties, context):
  blip = context.GetBlipById(properties['blipId'])
  blip.GetDocument().AppendText(':-)')

 そのイベントで新規追加されたBlipのIDがproperties['blipId']で取得できます。このIDを使用して、新しく加わったBlipを取得します。その中身にアクセスし、末尾に「:-)」という文字列を付加しています。

 events.BLIP_SUBMITTEDのイベントは、Robot自身がBlipを追加したときには発生しません。これはRobot APIの仕様です。

【Python編】クラウドにデプロイ

 App Engineランチャーを使って、App Engineのクラウドにデプロイします。メニューから、[File]→[Add Existing Application]を選ぶと、既存アプリケーションの追加ダイアログが開きます。作成したRobotアプリケーションのディレクトリを選択します。

デプロイするためのダイアログ

 アプリケーション一覧に、Robotアプリケーションが加わります。アプリケーションIDなどは、app.yamlから自動で読み込まれますので、あらためて入力する必要はありません。

ランチャーに追加されたアプリケーション

 選択して、Deployアイコンを押します。App Engineへのログインを促すダイアログが出るので、メールアドレスとパスワードを入れて「ログイン」をクリックします。[内部]のチェックボックスは外しておきます。

App Engineへのログイン

 デプロイの過程がコンソールに表示されます。「appcfg.py has finished with exit code 0」と表示されればデプロイ完了です(exit code の値が0以上の場合は失敗です)。

デプロイ成功!

 これで、Robotが利用可能になりました!

1-2-3-4

 INDEX
Google Wave API開発ガイド(後編)
JavaとPythonでGoogle WaveのRobotを作るには
  Page1
Google WaveのRobotをGoogle App Engineに作る
Google App Engineの基本的な使い方
  Page2
【Java編】App Engineでの開発準備
【Java編】Robot開発の準備
【Java編】コード部分の実装
【Java編】設定ファイルを書く
【Java編】クラウドにデプロイ
Page3
【Python編】App Engineの利用準備
【Python編】設定ファイルを書く
【Python編】コード部分の実装
注意 「使用していなかったイベントに対するハンドラを登録したくなった場合」
【Python編】クラウドにデプロイ
  Page4
作成したRobotをWaveに参加させるには
App Engineでのデバッグ
終わりに


リッチクライアント&帳票 全記事一覧へ



HTML5 + UX フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日 月間