2008年10月31日金曜日

SDKの管理コンソールを本番サーバでも使う

Google App EngineのSDKについて
のエントリで書いたけど、今までもSDK(ローカルの試験環境)では、memcacheを参照する仕組みがあったのだ。だけど本番サーバ上にはなくて、どうしたもんだろと思ってたのですが、

アプリの構成 - Google App Engine - Google Code
にずばりと書いてあるじゃないですか!
つまりこれはSDKの管理コンソールと同じものをSDKでも使えるようにするにはこうするんですよ~、というものなのだ。

で、早速やってみたさ。
すると、Pythonのエラースタックのようなものが。。。いや、幻じゃない、ほんとにエラーだ。
なんだよ!

管理コンソールのデフォルトページがDatastore関連のページなんだけど、ここで、DatastoreAPIにアクセスしようとして失敗しているようだ。
なんで?なんででもないか。SDK環境と本番環境じゃあDatastoreへのアクセス方法が違うんだろうし。 Datastoreは本番サーバ本来の管理コンソールからアクセスできるし、それが表示できなくても困る事はない。
でもそれがデフォルトページだとちょっと困るなあ。

ま、でも、
<管理コンソールのURL>/memcache
とするとmemcache用のページがちゃんと表示されたから良しとするか。

勘弁してください、のその後

勘弁してください、ほんと・・・
で書いた、memcache排他の件だが、とりあえず以下のように回避しました。

1.memcacheをgetする。
2.memcacheに「使用中です」と書いてあったら、memcacheをgetしつつループで使用中でなくなるのを待つ。
3.memcacheに「使用中です」という値を追加して、setする。
4.やりたい処理をする。
5.「使用中です」を取り去って更新したmemcacheを書き込む。

set直後にgetしても値は更新されたものが取れるので、別プロセスが「使用中なのに使用中でなく見える」ということはなさそう。

ただこれも厳密には、1~3の間に、別プロセスの処理で1がきちゃったらアウト。でもそこまでは考えないようにしよう。

2008年10月30日木曜日

appcfg.py プロキシ

どうもこのブログ、
「appcfg.py プロキシ」
とかで検索で引っ掛けてくる人が多いようなのは気づいていたんですが、今日ふと思い立って自分でも検索してみたんですよ。

そしたらまあ2ページ目くらいに出てくるんですけどね、クリックするとこのブログの一番最初のエントリが表示されたりするんですよ!
こらBlogger!もしくはGoogleインデックス!

おかげで、訪れた人が「それってどこやねん」て探し回ってくれるので、訪問あたりのページビューは上がるんですがね。。。でも不憫です。

このキーワードで引っ掛けた人。お探しのページは
http://pushit-dev.blogspot.com/2008/09/appcfgpy.html
になっておりますよ。

てかな~、どうなんだこれは。インデックスが更新されてないだけかなぁ?

ああ、そういえば

思うところあって、Google App EngineでのHTTPSの使い方を調べようと思って検索してみたら、つい最近、
https サポート - Google-App-Engine-Japan | Google グループ
というエントリができておりましたとさ。
最近なのか。確かに前に単にURLをhttpsに変えてやってみた時はダメで、急ぎでもなかったから深く調べることもなくそのまま放置してたのだが、やっぱり前はダメだったのね。

そういえば、GAEを使ってる人は知ってると思うけど、GAEの管理コンソールからDashboardを開くと、「Application Quotas」の欄に、
・Data Sent(HTTPS)
・Data Received(HTTPS)
という2つの項目が増えてた。

HTTPよりはHTTPSの方が多少なりとも負荷はかかるはずだが、Quota値はHTTPと同じ。太っ腹。
(でも自分の場合はCPUの方が先に引っかかりそうだが。。。)

Quotaが同じなんだったら、ユーザの入力したデータを扱うようなページは基本的にHTTPSにしちゃおうかな~、とか思ったりしてます。レスポンスが(ほとんど変わらないと思うけど)多少は落ちるのかな?

2008年10月29日水曜日

AIRのCookieの扱い

常識なのかも知れないが、知ってる人は知っている、知らない人は知らないと思うので(当たり前だ)、備忘録程度に書いておこう。

AIRは(いやFlash/Flexもだが)HTTPを簡単に扱うことができる。

で、Flash/Flexの場合はWebブラウザの中で動くので、キャッシュやCookieはそのブラウザに保存されるだろうと誰もが思う。その通り。

しかしAIRアプリはブラウザの中で動いているわけじゃないので、キャッシュはまあAIRアプリから使うことはないだろうからいいとして、Cookieはどうしてるのだろうか。自前で保管する仕組みを持ってるのだろうか。などと思ったりする。

だが、いきなり結論。AIRアプリは自前でCookieを持たない。じゃあ、誰が持っててくれるのか。
WindowsならIE、MacならSafari、が持つことになってるらしい。
ま、確かにその2つなら必ず入ってるはずだからね。
(Linux版AIRはどうするのだろう・・・)

これはWindowsでいう「通常使うブラウザ(だったっけ?)」に何を指定しても同じこと。
で、それが悲しい事態を招くのだ。

  1. IEとAIRアプリで同一のサイトに対して別々のアカウントが使えない。

    知っての通りCookieはログインの結果を保存しておいて同一サイト内で、認証済みかどうかを確認するために使われたりすることが多いと思うのですが、AIRとIEでCookieを共有しているせいで、どっちかでログアウトすると両方とも未認証の状態にされてしまうのだ。

    普通に使ってる分には特に問題ないのだが、Googleアカウントのように広範なサービスで同一Cookieを利用されてる場合はやっかいなのだ。ましてやGAEの認証機構(Googleアカウントを使わずに自前でやれなくもないんだが面倒)もGAEの管理者コンソールもどっちもGoogleアカウントなんだ。つまり、AIRアプリの試験をしていてログアウトしたら開発コンソールも未認証の状態にされてしまうってこと。(でもこの辺はちゃんと試したわけじゃないので、鵜呑みにしないように。時間があったら追試しますが)

  2. AIRアプリでログインした状態で、AIRからブラウザを開くと未認証だったりする。

    AIRにしろFlexにしろ、navigateToURLという関数を使うと、(擬似ではなく本物の)ブラウザが開きます。指定したURLの内容を表示して。
    Flexから作ったFlashの場合だと、Flashはブラウザの中で動いてますから、当然同じ種類のブラウザが開きます。IEならIE、FireFoxならFireFox。当然Cookieは共有されてますよね。

    でも、AIRの場合はブラウザの中で動いてません。じゃあ開かれるブラウザは何かっていうと、「通常使うブラウザ」に指定されているブラウザ。IEが嫌でFireFoxにしてるとかいう人も結構いるはずです。

    で、何度も言うけど、AIRはIEとはCookieを共有してるけど、FireFoxとは共有してない。つまりAIRアプリがサイトから認証を受けた状態になってその証拠のCookieを持っていても、そこから開いたFireFoxが認証されているとは限らない、ということなのだ。
    つまり「AIRアプリが接続できるようにしてある認証が必要なサイト」で、そのAIRアプリからブラウザを開くと、ユーザーは2回、認証情報を入力しないといけないってわけ。
1は我慢するとか、CookieはAIRアプリ自身で扱うとか(かなりきついけど・・・)すればなんとかなるので良いですが、2は痛いですねえ。。。これと言って回避策が見つからない。

困った。

Adobeに泣きついてなんとかなる話でもない。メジャーどころならともかく、Adobeのあずかり知らぬブラウザも含めて、AIRからブラウザを起動する時に、AIRの知ってるCookieを起動するブラウザに引き渡せ、ってことだから。

Cookieじゃなくて、アカウント情報(ユーザ名とかパスワード)をAIRアプリで覚えておいて、GETやPOSTのパラメータとして引き渡すことならできるんじゃないか?という意見もあろうかと思う。イグザクトリィ!その通り。
わかっちゃいるのだ。

が、如何せん相手がGoogleアカウントであって、自前の認証機構ではないのだよ。もちろんGoogleアカウントの認証プロキシを作りたいわけもない。さて・・・困ったな。


(2009.11追記)
その後の顛末は『「AIRのCookieの扱い」のその後』に、
補足が『AIRでCookieで』にあります。

2008年10月28日火曜日

CSSのシブい技

参照先のタイトルがそのものずばりを表しているのですが、
[CSS]高さの異なるカラムを揃えるスタイルシート
シ、シブい・・・。

要するにどの列も収まるくらいのピクセルサイズをpadding-bottomに、そのマイナス値をmargin-bottomに指定し、はみ出た部分はhiddenで隠してしまえぃ!ということのようだ。

いやいや、これ気づいた人エラいよ。
検索してみたら一発でしたが、それまではページのレンダリング終わった段階でJavaScriptで調整すんのかな~とかそんなことを考えたのですがCSSで済むなら何より。

どのくらい標準準拠なんだとか、どのくらい恒久性があるんだとか気にならないではないが、少なくともIE6/FF3/GCでは問題なく表示できたので良しとしよう。

しかし、この32768pxて値はどうなんでしょう。
2の15乗てことはわかるけど、16bit符号付整数だとMAXは
32767なので収まらない(負のほうは収まる)し、32bitだと小さすぎるし。
CSS標準か何かで定められた最大値、なんすかね?それとも経験則のカタマリ?

2008年10月27日月曜日

勘弁してください、ほんと・・・

何度もお話しているように、Google App Engineにはmemcacheという仕組みがあって、簡易な(そして不揮発でない)データベースのように使えるので、うまく使えばデータベースアクセスを減らすことができ(GAEではDatastoreアクセス回数にもQuotaがかかっているのだ→詳しくは:Understanding Application Quotas with Google App Engineの辺を見ると良い)、かつレスポンスも多少なりとも早くなるのでGoodなのだ。

だがしかし、memcacheの痛いところはロックができないことで、2つのプロセス(GAEに限定すれば2つのHTTPリクエストの処理が、と言い換えてもいい)が同時に同じエントリを更新しようとすると、どっちが採用されるかわからない。これはレスポンスのために割り切ってることなのでしょうがない。memcacheのせいではない。

んで、アプリ側でそれを回避するように作りたいので、以下のようにしてみた。
1.更新するmemcacheデータを読み出す
2.更新するmemcacheデータをキャッシュから消す
3.何やら処理をする
4.memcacheをaddで更新する
addはエントリがあると失敗するので、同時に同じ処理が走れば、後続のプロセスはaddが失敗するはずなのだ。失敗したとわかれば、その後の処理のしようもあるってもんだ。再度1からやるとかね。
(一方のプロセスが1~2の間にいるときに、もう一方が1~4まで終わらせちゃうとデータの矛盾がおきるかも知れないがそこまで考えるのはやめておこう)

で、SDK環境ではうまく動きました。サーバにアップデートしました。

結果。複数プロセスを同時に走らせなくてもaddが失敗するでないの。。。また本物環境とSDK環境の差ですか。。。勘弁してください、ほんとに。。。

多分、類推なのだが、deleteのあと、しばらく置かないとエントリはまだあるとみなされてaddが失敗するのではなかろうか。
代わりにエントリがあろうがなかろうが値をmemcacheに書き込むsetを使ってみると、何事もなく成功する。・・・成功するが目的は達成できんのだよそれじゃあ!

むぅ。。。なんとかならんのかね。。。

2008年10月21日火曜日

日本語化Eclipse

くどいようですが、Flex Builderが使えなくなってしまいました。
これまで、Google App EngineにアップするPythonスクリプト、HTMLコード、JavaScriptなどもFlex BuilderにAptanaとかPyDevとか入れて使ってたんですが(ベースがEclipseなんでね)、Flex Builderの起動すらできなくなってしまったので、これらの環境も一から作り直してたわけです。

で、最初にAptana StudioっていうWeb(特にAJAX)開発の超強力な(と言われている)環境を入れてみたんですが、まあ、普通に使えるんですが、メニューとかが日本語じゃないわけですよ。

ついでにベースのEclipseのバージョンも3.2で古かったりするので、気に食わねぇ、ってんで、Eclipse3.4(Ganymedeってーの?)にAptanaのEclipseプラグインと日本語化プラグインをぶち込んで、、、てなことをやろうと、ダウンロード&展開&インストールなんぞしつつ、その待ち時間に良く良く検索してみると、だ。
http://mergedoc.sourceforge.jp/index.html#/pleiades.html
あるじゃないいいものが!
しかも欲しいもの(Eclipse3.4+日本語化+Aptana+PyDev)が全部入りのパッケージがあるでないの!

ああ、こんなステキなプロジェクトがあったのね。。。最近All-In-One-Eclipseってリリースされてないなあと思ったら、こういう形で存在してたか~!ステキだ!ステキすぎる!

またプロキシ?

前のエントリで、Google App Engineのサーバへのファイルアップロードのコマンド(appcfg.py)がプロキシ環境だとうまく動かなくて、環境変数を設定するに至った話を書いたけど、また引っかかりました。プロキシ。

今度はAIR SDKです。

AIRの配布用ファイル(拡張子air)を作るために、今まではFlex Builderを使ってたんだけど、前に書いた通り試用期限切れで使えなくなっちゃったので、AIRのSDKに付属してるコマンドを使って自力で作るようにしたんです。で、家ではうまくいったんです。

しかし会社でやると(あ、もちろん休憩時間にやってんですけどね)、
Could not generate timestamp: timestamp.geotrust.com
こんなん出て怒られる。

なんのことやら全然想像がつかないので、ググって見る。と、あるもんだね、
http://www.fxug.net/modules/xhnewbb/viewtopic.php?topic_id=1681
この辺に書いてある通り、、、ていうか何を話してるのかついていけてないんだけど、要するにプロキシの設定をしてないとだめだそう。

・・・またプロキシですか・・・もういいです・・・。

と言いたいのだが、しぶしぶJavaのプロパティファイルにプロキシ設定を書いたところ、無事通るようになりました。万歳。

2008年10月19日日曜日

楽しかった日々の終焉

落ち込んでます。

前回ちょろっと書きましたが、Flex Builder3の60日試用版の試用期限が過ぎてしまったのです。
これがなくてもAIRの開発はできます。

Flex SDKとAIR SDKを入れればね。全部コマンドラインで。とほほ。

Flex Builder3はいわゆる統合開発環境ってやつで、
・構文解析、カラー化、アウトライン表示。
・インテリジェントな文字の補完。
・デバッガのブレークポイントが設定できるエディタ。
・インタラクティブなGUI設計。
など、Visual StudioとかEclipseとかNetBeansとかを使ってる人には当たり前な機能なんだけど、それがFlex/AIRの開発に使えるか、コマンドラインでがんばるかは本当に効率が雲泥の差なのだ。とほほ。

60日以内になんとか形に・・・はまあなったけど、広範なテストをしてない(周囲にすらアナウンスしていない)ので、まだまだいじる可能性が大きいだけに痛いすねぇ。

ま、ちゃんと買うべきなんですがね、本来。もしもAdSenseで儲かるようなことがあったらちゃんと買います。ごめんなさい。>Adobe様

ちなみにオープンソースのOpenLaszloって知ってますか。これもAIRとかのアプリが作れるらしく、かつ無料の統合環境もあったはずだけど、Flex(MXML+ActionScript)とはソースコードレベルで互換性がない(コンパイルしたものはAIRランタイム上で動くんだから当然互換性がある)。似てるんだけどね、ソースコード。
今更乗り換えられないっす。。。最初からOpenLaszloでやるべきだったか。でも情報少ないだろうしなあ。。。

2008年10月11日土曜日

Adobe AIRのTextArea

Push It!はサーバにGAE、クライアントにAdobe AIRを使用するので(つか現時点では公開してないけど)、Adobe AIRも触ってます。Flex Builder3の試用版使って(もうじき期限が切れてしまう・・・)。

そのAdobe AIR、内部にWebKitを持っているので、簡単なブラウザなんざ余裕で作れるのです。
で、画面表示用部品としてTextAreaという部品があって、そこのプロパティにhtmlTextというものがあるので、これはてっきりWebKitでHTMLをレンダリングしてくれるのかと思いきや、ものすごく制限されたHTMLしか扱えないのね。。。しょんぼり。

フォントの強調とかアンダーラインとかくらい。htmlTextという割にしょぼいぞ!せいぜい修飾されたテキストじゃねーか。こんにゃろ。

尚、フルHTMLをレンダリングするためにはHTMLというコンポーネントを使う(多分)が、これはAIR専用。できればFlash(ブラウザ内で動作)版とAIR版とを両方用意したくて、手をかけないようになるべくソースを共通化させようとするとこれは使えない。残念。

2008年10月7日火曜日

SDK1.1.5リリース

Google App EngineのSDK1.1.5がリリースされました。
こちらへどうぞ。
(日本語のページのは1.1.0のままで古いから使わないほうが良いよ。←ていうかこれも何とかして欲しい)

リリースノートの超適当な訳はこちら。
  • Additional fixes for file paths on Windows and OSX.
 WindowsとOSXで、ファイルパスの追加の修正。
  • Sped up the datastore stub.
 擬似Datastoreがスピードアップ?
  • Allow different types in list properties in datastore.Entity and Expando.
 datastoreのEntityとExpandoでリストプロパティで異なる型が許可された(意味不明)
  • Add add_multi and replace_multi to memcache API.
 memcache APIのadd_multiとreplace_multiが追加(今まで使えなかったの?)
  • Ignore errors from the API proxy when calling memcache read methods.
 memcache読込メソッドを呼んだ時のAPIプロキシのエラーを無視(意味不明)
  • Set the webapp Request charset property more accurately from CONTENT_TYPE.
 webapp Request charsetプロパティをCONTENT_TYPEからより正確に設定するようにした。
 →うおーこれこれ!これだよ前回のブログエントリで書いたのはさ!
  • Fixed an issue in the development console with schema caching.
 開発コンソールでのスキーマキャッシュの問題を修正(意味不明)
  • Fixed an issue with StringListProperty not returning a class
 StringListPropertyがクラスを返さなかった問題を修正
  • Fixed an issue in the development console where quotes couldn't be used within fields.
 開発コンソールでの、フィールド中にクォートが使えなかった問題の修正
  • Fixed an issue with TimeProperty("0:0") (midnight).
 TimeProperty("0:0")とした時の問題の修正

ということで、だ。
例のContent-Typeの件、試してみましたよ。
結果OK!!!でした。ぐっじょぶ!SDKチーム!
これで、SDKと本番用でコードを分けずに済むよ。

2008年10月2日木曜日

SDKのバグ?

Google App Engineネタです。

ブラウザから日本語を含む文字列をPOSTするとき、基本的にはGAEは文字コードをUTF-8として扱ってくれるようです。OK。

でも、POSTをXMLHttpRequest、いわゆるAJAX的な方法でSDKのサーバに投げると、そのデータをDatastoreに格納するところで怒られます。

File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore_types.py", line 1092, in PackString
pbvalue.set_stringvalue(unicode(value).encode('utf-8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinalnot in range(128)

こんな風に。
でもそもそもが、ブラウザからはUTF-8で送信されているはずで、エンコードの必要などないはずなのに。それに普通にフォームからPOSTした時は怒られないよ?

てーことで色々調べてみたら、フォームからの場合とAJAXからの場合とでHTTP Requestのヘッダがどのように違うかというと、

フォームの場合
'Content-Type': 'application/x-www-form-urlencoded'

AJAXの場合
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'

ふむ。。。Content-Typeにcharsetが指定されてるかそうでないかね。なるほど。
ではこれをフォームに合わせて消してやれば同じ動きをするはず。

・・・で、うまくいかず。
自分が使ってるAJAX系ライブラリのmootoolsというやつで、このライブラリで、charsetだけを消す方法が見つけられず断念(数時間悩みましたけど)。

でもね、ちょっと待ってよ。そもそもcharsetでUTF-8って言ってるんだから、やっぱり変換の必要ないのは同じじゃね?と思う。
思ったところでSDKは聞いてくれないので、試しに「これはUTF-8の文字列ですよ~」と指定してUnicodeに変換する。

↓こんな感じ。
mydb.nihongo = unicode(self.request.get('nihongo'), 'UTF-8')
mydb.put()

OK。通りました。代わりにフォームから通らなくなりました・・・がっくし。
ブチギレ3秒前です。

もう、これって、SDKのバグじゃねーの?ってことで本番サーバに元のままでアップロードする。
・・・通った!!もちろんフォームからでもAJAXからでも。
ブチギレ0.1秒前、ギリギリでセーフです。

ですが、このままだとSDK環境でAJAXの試験ができないことには変わりないんで、困りましたねえ。
DeadlineExceededErrorの件で使ったみたいに、localhostで、かつ、charsetがありなら、って分岐を入れるのか?バカバカしい。ブチギレ。
自分の入れてるPythonとの相性でも悪いのかなあ???