When it’s ready.

出来るまで出来ない

GoogleAppEngine ハッカソンNo.2に参加してきました。

12/13 渋谷でGAEのハッカソンがあったので参加してきました。
チュートリアル、マッシュアップ、データストア、フレームワークのチームに分かれて、作業を行い。最後にチーム毎に発表を行うという流れで行われました。前回同様、ゴージャスなお弁当をご馳走になったり、大変快適でした。tmatsuoさん、Googlerのみなさまありがとうございます。

私は、マッシュアップチームR(@akisutesama takao.funami id:a2c)でGDataをGAEで使えるようにするチームに所属しました。とりあえづ出来たものが、以下のURLで、動作確認出来ます。トークンを奪うような事をしていないので適当に認証してみてください。ソースも公開しています。
http://1.latest.inote.appspot.com/
上記ページ言って認証ってのを押すと


認証画面に飛ばされますので


画面下部の、認証のボタンを押せば、Google(自分の)のBloggerとCalendarとDocsのタイトルをそれぞれ、持ってきて表示する事が出来るようになっています。

コードは、codereposに置かせて貰っています。
svn co http://svn.coderepos.org/share/lang/python/gae_gdata/

個人的に、マッシュアップとは別課題でgoogle app engine oilを使ってみるというのがあったので、このアプリはgaeoでスケルトン作成しています。gaeは、djangoだろという意見もありますが、djangoをもっとシンプルにした感じです。また、コントローラーとかを作成してくれるコマンドがあったり、urlの指定が/:controller/:id であったりと、毎回やる事が最低限に押さえられていて、サックサク進める感じがしますです。

んで、gaeoでgdataを使うには、3つのライブラリが必要になります。

  1. gaeo
  2. atom
  3. gdata

gaeoは、easy_installで入ります。今回使用したPCは、pythonのいろんなバージョンが入っていたので、そのままだと使えない方に入ってしまう/usr/bin/easy_installを使って入れます(osx10.5.6の場合)

atomとgdataは、http://code.google.com/p/gdata-python-client/ からDLして、setup.py installで入りますがこの際も/usr/bin/python のやつを使っとくと全然関係ないかも知れないが良いかと思う。

なんで関係ないかというと、アプリのルートフォルダにライブラリをコピーしなくてはならないから、OSに入ってるsite-packegeは使われない。っていうか、結局appspot.comに上げてしまうので、プロジェクトフォルダの中に入っている必要があります。

今回は、このライブラリのフォルダを圧縮して、zipで利用しました。site-packege内のatomとgdataとgaeoのフォルダを適当な場所にコピーした後、finder上で右クリック>圧縮します。そして、zipファイルをプロジェクトフォルダに移動して、main.pyにzipファイルをロードする部分を書き足します。

/main.py

import os
import sys

try:
    lib_list = ['atom.zip', 'gdata.zip', "gaeo.zip"]
    for aLib in lib_list:
      if os.path.exists(aLib):
        sys.path.insert(0, aLib)
except:
    print "zip lib load fail"

import gaeo
from gaeo.dispatch import router

これで、zipファイルからのロードが出来るようになりました。lib_list育ててもらえば、zip化したライブラリがどんどん使えるようになるとおもいます。ちなみに、オリジナルだと300項目以上のファイルが3ファイルになるのでアップロードの時間が大幅に短くなってハッピーです。

ハッカソンでは、順調にいったところが全然なくて、躓きまくりでした。
躓きポイントの乗り越えた方法をいくつか上げます。

ソケット通信出来ない。

標準のgdataは、gaeでは使得ない方法でatom取りに行くので、そこを修正する必要があります。コントローラ内で

gdata.service.http_request_handler = gdata.urlfetch

と、やってあげるだけですが、これが見つかるまで大変でした。

どのGdataにアクセスしたのかスコープを定義する

GData経由で、様々なデータを取ってくる事が出来るのですが、全てのサービスを取ってくる為には、どのサービスか指定して、トークンを取得してあげる必要があります。

# 権限を与えたいホストを指定する
HOST_URI = 'http://localhost:8085'
# 権限が欲しいサービスを指定する
gdataScope = 'http://www.blogger.com/feeds/ \
http://www.google.com/calendar/feeds \
http://docs.google.com/feeds/'

# トークンを返すパスを作成
authsub_url = (HOST_URI + '/welcome')
# 認証を行うURLを生成する
self.msg = client.GenerateAuthSubURL(authsub_url,
            gdataScope,
            secure=False, session=True)

認証を行うURLを作成出来たら、そのページにアクセスし認証する事で、権限を与える用に設定したページにトークン付きで帰ってくる事が出来ます。

トークンを取得し、利用可能な形にアップグレードする

この辺が、結構山場で、googlerの鵜邙さんとかに質問したりしながらゴシゴシと進んでいきました。
前ステップで取得したトークン(文字列)と、gdataスコープをSetAuthSubTokenに食わせる事で登録が出来て、クライアントインスタンスをアップグレードする事が出来ます。

client.SetAuthSubToken(token, gdataScope)
client.UpgradeToSessionToken()

このアップグレードの作業は、1トークン1回しか出来ないようです。継続的にサービスにアクセスしたい(リロードとか)場合には、memchacheやdatastoreを利用して保存しておく必要があります。もう一班のマッシュアップチームがそれが出来るようになっていたので、ソースを見たいと思っております。

Getメソッドでデータを取りまくる

あとは、各サービスで用意されているfeedのurlに対して、Getをかけていき帰ってきたGDataFeedオブジェクトを適当にばらせば情報にリーチすることが出来ます。

docsQ = 'http://docs.google.com/feeds/documents/private/full'
blogQ = 'http://www.blogger.com/feeds/default/blogs'
calQ = 'http://www.google.com/calendar/feeds/default/allcalendars/full'

self.docs_feed = client.Get(queryMaker(docsQ).ToUri())
self.blog_feed = client.Get(queryMaker(blogQ).ToUri())
self.cal_feed = client.Get(queryMaker(calQ).ToUri())

gaeoのテンプレートで展開する

gaeoは、特にレンダーhogeとかしなくても、コントローラーフォルダのメソッド名なhtmlをテンプレートファイルとして使ってくれるのでその中に表示部分を記述すればよい。また、renderがないが、self.hogeの変数がそのままテンプレート内で使える事が出来るので、色々パッキングしたりせずに非常に楽にvc間の受け渡しが出来る。

{% extends "../base.html" %}
{% block title %}GAEO GData MushUp{% endblock %}
{% block content %}
        {% for i in blog_feed.entry %}
          {{ i.title }} <br>
        {% endfor %}<p>

        {% for i in cal_feed.entry %}
          {{ i.title }} <br>
        {% endfor %}<p>

        {% for i in docs_feed.entry %}
          {{ i.title }} <br>
        {% endfor %}<p>
{% endblock %}

今回は、標準的なクラスでデータを取得したのでgdatafeedクラスが全部同じだったけど、それぞれのサービスに適したクラスを使うともっと便利な取り方があるらしい。

課題

  • 書き込みまだやってない。
  • memcache使ってトークン使い回す

非常に充実したハッカソンとなりました。一人でやってたら挫折したであろうタイミングでも一緒に何人かとやっていると一緒に乗り越えられるし、問題点を説明しよう、としている段階で自分で解決策を気づいたりする事が出来たりと、楽し充実でした。