Gaelykでemail Twitter連携アプリ作ってみた(解説編)
ざっくり解説。プロジェクトレイアウトはGaelyk本家にあるTemplate projectを拝借。IntelliJであっさりマウントできたので,あとは全部IntelliJ上で完結。GAEへのデプロイも楽ちん。
twitter連携にはもちろんTwitter4Jを利用させていただきました。なお,twitterとの連携にはOAuth認証を利用(プロジェクトレイアウトでモザイクかかってるファイルがそれ)。やり方わかんなくてOAuth認証でちょっとハマったけど,アクセストークン取れたらあとはすんなり。
GAE/Gaelykによくわかってなかったので,ちょとハマり「Javaにしとけばよかったかな?」思ったけど,慣れちゃうとホント簡単。むしろJavaでなんて組んでられっかって気分。
マジメなアプリ作ろう思ったらEC2のほうが自由が利いていいけど,この手のトイプログラムだとGAE/Gaelykのほうが簡単でいいね。:-)
メール連携について
本家のチュートリアルだとこの辺参照。
* Email support - Incoming email messages
もともとGAEがサポートしているメール受信をGaelykがさらに簡易化してくれている。事前準備として,appengine-web.xml
のinbound-services
にmail
を追加。でもって,web.xml
のsecurity-constraint
もチュートリアル通りに設定。
メール受信用のサーブレット(Gaelykの場合,Groovlet)は,routes.groovy
にこんな感じでしているだけ。
email to: "/receiveEmail.groovy"
このGroovlet名がそのままメールアドレスになる。例えば上記の例の場合だと,
receiveEmail@アプリケーション名.appspotmail.com
となる。receiveEmail.groovy
の内容はこんなの。メールの解析はテキトー(添付ファイルとか気にしてない。
import twitter4j.* import twitter4j.conf.ConfigurationBuilder log.info "start!!!" // メール受信 def msg = mail.parseMessage(request) def postMessage = "@masanobuimai ${msg.content} / ${msg.from[0].address.split(/@/)[0]}" log.info "postMessage:${postMessage}" def cb = new ConfigurationBuilder() cb.with { debugEnabled = true OAuthConsumerKey = "xxxxxxxxxxxxxxxxxxxxxx" OAuthConsumerSecret = "xxxxxxxxxxxxxxxxxxxxxx" OAuthAccessToken = "xxxxxxxxxxxxxxxxxxxxxx" OAuthAccessTokenSecret = "xxxxxxxxxxxxxxxxxxxxxx" } // twitterにポスト // -> メール受信処理がコケるとメールが滞留するみたいなんで,コカさないようにする。 try { new TwitterFactory(cb.build()).instance.updateStatus(postMessage).with { status -> log.info "Successfully updated the status to [${status.text}]." } } catch (e) { log.info "twitterにポスト失敗: ${e}" } // ついでにgmailにもポストしとく。 mail.send from: "receiveEmail@xxxx.appspotmail.com", to: "example@gmail.com", subject: "つまからの伝言", textBody: "${msg.content}" log.info "end!!!"
ホント,簡単。:-)
Twitter連携について
定期的にmentionsの新着をチェックするんでGAEのcron使って監視させといた。新着チェック済みのmentionsは読み飛ばす必要があるんで,最後のチェックしたmentionsのIDを永続化しとかないといけない。あとメールの送信も。
本家のチュートリアルだとこの辺参照。
* Improvements to the low-level datastore API
* Email support - New send() method for the mail service
cronの設定はcron.xml
にこんな感じに記述するだけ。最小単位が1分だけど,まあいいか。
<cronentries> <cron> <url>/checkMentions.groovy</url> <description>checkMentions the run every 1 minutes</description> <schedule>every 1 minutes</schedule> <timezone>Asia/Tokyo</timezone> </cron> </cronentries>
mentionsのチェックするcheckMentions.groovy
の中身はこんなの。
import twitter4j.conf.ConfigurationBuilder import twitter4j.TwitterFactory import com.google.appengine.api.datastore.Entity import com.google.appengine.api.datastore.Query import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit log.info "start!!!" // 最後に取得したmentionsのIDを永続化しとかないと...。 def query = new Query("Settings") query.addFilter("name", Query.FilterOperator.EQUAL, "one") def result = datastore.prepare(query).asList(withLimit(10)) // SettingsっていうEntityがあればそれを使う,無ければ新しいEntityを作る。 def entity = !result.isEmpty() ? result[0] : new Entity("Settings") // name="one"に強い意味は無いス。単にユニークにしたいだけ。 entity.name = "one" def lastMentionId = entity.lastMentionId ?: 0 log.info "entity: ${entity}" def cb = new ConfigurationBuilder() cb.with { debugEnabled = true OAuthConsumerKey = "xxxxxxxxxxxxxxxxxxxxxx" OAuthConsumerSecret = "xxxxxxxxxxxxxxxxxxxxxx" OAuthAccessToken = "xxxxxxxxxxxxxxxxxxxxxx" OAuthAccessTokenSecret = "xxxxxxxxxxxxxxxxxxxxxx" } // mentionsのチェック。getMentions() を mentions と書けないもどかしさよ...。 new TwitterFactory(cb.build()).instance.getMentions().reverseEach { status -> if (status.id <= lastMentionId) { log.info "読み込み済みなので無視:id=${status.id}" } else { // 新着のmentionsをメールする mail.send from: "receiveEmail@xxxxx.appspotmail.com", to: "<ヨメのメールアドレス>", subject: "お父ちゃんからの連絡", textBody: status.text.substring(14) entity.lastMentionId = status.id log.info "mention: ${status.text}" } } // -> こっちのエラー処理はいいや。 // 最後に取得したmentionsのIDを永続化しとく。 entity.save() log.info "end!!!"
コテコテのSIer勤めだけど、こんくらいのアプリをペロっと作れる程度の能力が残っていてよかった。あとは、こんなもん使うような事態にならなければもっと良い。:-)