Google App Engine で HTML5 の Application Cache

参考:

マニフェストファイルを用意する

拡張子は .appcache (.manifestから変更された)。以下サンプル。

CACHE MANIFEST
# version 1.0

CACHE:
path/to/the/file.html
/could/be/absolute/path.js

NETWORK:
always/refer/to/serverside/content.html

# external source
http://example.com/

サーバを参照するものがある場合は、必ず NETWORK に指定(CACHEで指定したもの以外はサーバを参照する、という事ではない)。

マニフェストファイルが更新されないとブラウザはキャッシュし続ける。ファイルの構成が変わらなくても更新させたい場合を考えて、コメントでバージョンとか日付とか入れておき、キャッシュを更新させる場合はここを変更する。

HTMLとJavaScript

HTMLタグにmafifest属性を追加。

<html manifest="example.appcache">

JavaScriptでキャッシュ対象のファイルがアップデートされた時に更新する。

applicationCache.addEventListener("updateready", function(){
    applicationCache.swapCache();
}, false);

GAEの設定 (app.yaml)

mime_typeを text/cache-manifestにする。以下、例。

- url: /(.*)\.appcache
  static_files: static/\1.appcache
  upload: static/(.*)\.appcache
  mime_type: text/cache-manifest
Advertisements
Google App Engine で HTML5 の Application Cache

Managing files for GAE with Git and Dropbox

At last, I started to use git to manage files that are hosting on GAE. For backup and remote access, I use Dropbox for the git repository. Here is the memo.

Resources

Steps

1) Download Dropbox and launch it. (Create account if you don’t have the one.)
2) Install Git. If you use Mac, you can install it with MacPorts

$ sudo port install git-core

3) Create a bare repository in Dropbox directory

$ cd ~/Dropbox
$ mkdir repo
$ cd repo
$ mkdir project_name.git
$ cd project_name.git
$ git --bare init

4) Go to the directory that contains source files, and then push the files to the git repository

$ cd ~/project_name
$ git init
$ git add .
$ git commit -m "initial commit"
$ git push ~/Dropbox/repo/project_name.git master
$ git remote add origin ~/Dropbox/repo/project_name.git
Managing files for GAE with Git and Dropbox

Markdown Wiki (3) Memcache

  1. ユーザーサービス
  2. データストア
  3. Memcache

Memcache

今回勉強がてらにやってみたことの最後は Memcache。

デモサイトでは、常に右側のメニューにページ一覧が出ているので、そのリストを取得する時に cache を利用。以下、コードの抜粋。

from django.utils import simplejson
from google.appengine.ext import db
from google.appengine.api import memcache
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class PageList(webapp.RequestHandler):
    def get(self):
        permission = Permission()
        data       = []

        if permission.get():
            pagelist = memcache.get("pagelist")

            if pagelist is not None:
                data = pagelist
            else:
                query = WikiPage.all()
                query.order("title")

                for record in query:
                    data.append({"keyname":record.key().name(), "title": record.title })

                memcache.add("pagelist", data, 3600)

        self.response.headers[''Content-Type''] = ''text/plain''
        self.response.out.write(simplejson.dumps(data))

呼び出す側の JavaScript は、単に GET してるだけ。

var Connect = YAHOO.util.Connect;

var oCallback = {
    success: _create
};
Connect.asyncRequest("GET", "/wiki/list", oCallback);

デモページは Gmail のアカウントがあれば誰でも使えるが、データは 1 日に 1 回リセットされる。

Markdown Wiki (3) Memcache

Markdown Wiki (2) データストア

  1. ユーザーサービス
  2. データストア
  3. Memcache

データストア

Google App Engine の勉強のつづきで、データストアの使い方。GAE のドキュメントは、

などを参照した。

GQL という SQL のようなクエリ言語を使ってデータを扱えるけど、それとは別の Query インターフェースを使った。以下はデモサイトでページを表示、編集する部分のコード。

from django.utils import simplejson
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class Page(webapp.RequestHandler):
def __init__(self):
self.permission = Permission()
self.data = {}

def get(self, keyname):
if self.permission.get():
page = WikiPage.get_by_key_name(keyname)
self.data = {"keyname":keyname, "title": page.title, "content": page.content}

self.response.headers[''Content-Type''] = ''text/plain''
self.response.out.write(simplejson.dumps(self.data))

def post(self, keyname):
if self.permission.get():
page = WikiPage(key_name=keyname)
page.title = self.request.get("title")
page.content = self.request.get("content")
page.put()

self.data = {"keyname":keyname, "title": page.title, "content": page.content}

self.response.headers[''Content-Type''] = ''text/plain''
self.response.out.write(simplejson.dumps(self.data))

以下のような JavaScript から呼び出される (ページ更新時のリクエスト部分のみ。JavaScript ライブラリは YUI)。

var Connect = YAHOO.util.Connect,
Dom = YAHOO.util.Dom;

var _onClickUpdate = function(oEvent){
var sKeyName = Dom.get("keyname").value,
sTitle = Dom.get("title").value,
sPostData = "title=" + encodeURIComponent(sTitle)
+ "&content=" + encodeURIComponent( Dom.get("content").value ),
oCallback = {
success: _renderPage
};
Connect.asyncRequest("POST", _sRequestUrl + sKeyName, oCallback, sPostData);
Dom.get(sKeyName).innerHTML = sTitle;
};

その 3 へつづく。。

デモページは Gmail のアカウントがあれば誰でも使えるが、データは 1 日に 1 回リセットされる。

Markdown Wiki (2) データストア

Markdown Wiki (1) ユーザー認証

Google App Engine の勉強がてら、シンプルな wiki を作ってみた。といっても、主に GAE の

  1. ユーザーサービス
  2. データストア
  3. Memcache

の使い方を知るためのもので、ページのレンダリングは Showdown を使った。サーバ側のスクリプトは Python で、リクエストを受けた結果を JSON で返している。

GAE だけじゃなくて、Python の勉強もかねているので、変なところがあるかもしれない。。

ユーザーサービス

基本的な使い方は、GAE のドキュメント ユーザー サービスの使用にあるように、簡単だった。これだと Gmail のアカウントを持ってる人は誰でもアクセスできる事になるので、メールアドレスのリストを用意して、そこに登録されている人のアクセスを許可するようにした。該当部分を一部抜粋。

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class Permission:
    def __init__(self):
        self.accessible = ["example@gmail.com"]

    def get(self):
        user = users.get_current_user()

        if user:
            if len(self.accessible) < 1:
                return True

            for email in self.accessible:
                if user.email() == email:
                    return True

        return False

class Auth(webapp.RequestHandler):
    def get(self):
        url        = ''/wiki.html''
        permission = Permission()

        if permission.get():
            user = users.get_current_user()
            data = {"nickname": user.nickname(), "logoutUrl": users.create_logout_url(url)}

        else:
            data = {"loginUrl": users.create_login_url(url)}

        self.response.headers[''Content-Type''] = ''text/plain''
        self.response.out.write(simplejson.dumps(data))

JavaScript 側から以下のようにして呼び出している(JavaScript ライブラリは YUI を使用)。

YAHOO.namespace("mdwiki");

YAHOO.mdwiki.Auth = function(){
    var Connect = YAHOO.util.Connect,
        Dom     = YAHOO.util.Dom,
        Event   = YAHOO.util.Event,
        JSON    = YAHOO.lang.JSON;

    var _handleAuth = function(oResponse){
        var oAuthInfo = JSON.parse(oResponse.responseText);

        if (typeof oAuthInfo === "object") {
            var oProfile   = Dom.get("profile");

            if (oAuthInfo.nickname) {
                // the user has been authenticated
                oProfile.innerHTML = "<a href=''" + oAuthInfo.logoutUrl + "''>Logout</a>";
                YAHOO.mdwiki.Page.show();
                YAHOO.mdwiki.PageList.init();
            } else {
                // the user has not been authenticated
                oProfile.innerHTML = "<a href=''" + oAuthInfo.loginUrl + "''>Login</a>";
            }
        }
    };

    Event.onDOMReady(function(){
        var oCallback = {
            success: _handleAuth
        };
        Connect.asyncRequest("GET", "/wiki/auth", oCallback);
    });
}();

長くなりそうなので、その 2 へつづく。。

尚、デモページは Gmail のアカウントがあれば誰でも使えるが、データは 1 日に 1 回リセットされる。

Markdown Wiki (1) ユーザー認証

Google Apps のサブドメインに “www” を使う

Google Page Craetor の終了に伴い、下のページに書いたように静的ファイルのホスティングをGoogle App Engine に移行した。

移行の際、GAE には “www” というサブドメインを割当て、Page Creator の使用を停止した(無効にした)。それで問題なく動いていたのだが、去年の 12 月に Google が Page Creator のコンテンツを Google Sites に移行させてからおかしくなった。

Page Creator で作ったページが Sites に復活し、GAE で使っているサブドメイン “www” を割当てられたので、コンテンツが移行された後、GAE にホスティングしたファイルにアクセスできなくなった。さらに Sites の web address mapping から “www” を削除して、Page Creator から移行されたページを削除しても、 GAE の方には “www” でアクセスできなくなったままだった。

最近になって、下の Help トピックを見つけて解決できたので、メモしておく。

一言で言うと、一度 “www” をスタートページのサブドメインにしてから、別のものにすれば
他のアプリケーション (GAE など) で使えるようになる。

実際にやった手順は以下の通り。

  1. Google Sites の Web Address Mapping から “www” を削除 (Page Creator のコンテンツも削除した)
  2. DNS の設定から、”www” を削除 (これと、4 は必要ないかもしれない)
  3. スタートページのサブドメインに “www” を割り当てる
  4. DNS の設定で “www” の CNAME レコードに “ghs.google.com.” を割り当てる
  5. スタートページのサブドメインを他のものに変更 (“start” など)
  6. GAE の Web Address Setting で “www” を設定 (www.example.com)
Google Apps のサブドメインに “www” を使う

Using “www” for subdomain of Google Apps

Due to temination of Google Page Creator, I moved hosting of static files to Google App Engine as I wrote the following article.

When I moved to App Engine, I set up “www” to the subdomain for GAE. And I disable Page Creator on my Google Apps Account. It has worked as expected… until Google migrate page creator contents to Google Sites last December.

Google revived my Page Creator contens in Google Sites, and assigned “www” as the subdomain of Google Apps, that prevented access to my GAE contents. Moreover, even though I removed “www” from web address mapping of Sites, I couldn’t resolve the problem to access to my GAE contens with subdomain “www’.

Now I could fix the problem lately, according to the following help topic (Japanese) of Google Apps, here is the notes.

In short, to use “www” as submain of Google Apps, assign “www” to Start Page, and then change subdomain of Start Page, asign “www” to another Apps.

Here is the exact steps to assign “www” to GAE in my case.

  1. Remove “www” from Google Sites addresss mapping (removed page creator contents from Sites too)
  2. Remove “www” from my DNS settings (You might not need this step and step 4)
  3. Assign “www” to Start Page of my Google Apps
  4. Set up “www” to CNAME record (points to “ghs.google.com.”)
  5. Change subdomain of Start Page (e.g., “start” or something)
  6. Assign “www” to GAE (web address setting)
Using “www” for subdomain of Google Apps