Salesforce Developer User Group [Tokyo] Meetup #4に参加

Posted by joeartsea on 2013-12-20

こちらの記事は Force.com Advent Calendar 2013 に参加しております。

一昨日、Salesforce Developer User Group [Tokyo] Meetup #4 に参加しましてDreamforce’13 の $1M Hackathon に参加したことについての発表させていただきました。

@stomitaさんよりスピーカーの機会をいただきまして心より感謝致します。また、当日イベントの運営に尽力された皆様、私のつたない発表を観ていただいた皆様、本当にありがとうございました!

以下が発表スライドになります。

** [1 mhackathon](https://www.slideshare.net/joeartsea/1-mhackathon "1 mhackathon") ** from **[joeartsea](http://www.slideshare.net/joeartsea)**

発表ではちょっとネタに走りすぎた部分があり肝心の技術的なところの話があまりできなかったのでブログにて補足させていただきます。

スライドの中でシステム構成図の粒度がちょっと大きすぎてWebサーバ周りとIMAP Proxyが実際どうなってるのか見えにくいと思いますのでそこを中心に。

Webサーバ周り

ここは構成が紆余曲折して複雑になってしまったので結局どうなったのか以下に整理します。

  1. メールからのリクエストを受け取り Chatter へ投稿する処理が必要
  2. Chatter へ投稿するには認可情報をストアする必要がある
  3. Chatter のどのグループに投稿するのかもユーザが設定保存
  4. つまり設定サイトはメンバー管理が必要
  5. さらに IMAP Proxy からメール情報を POST できる API が必要

スライドにある通り IMAP Proxy の実装に思ったより時間がかかったために最終日かなり焦りながら考えた結果、データストア周りや API 周りを簡単に作れる Deployd を使うことにしました。Deployd については @stomita さんのオープンソースMBaaS「deployd」を使ってみる が詳しいです。

実は以前 AngularJS を Deployd の public ディレクトリで動かしてメンバー管理を実装していてソレを流用しました。以下にソレをもっとシンプルにした例を作ってみました。これはこれでクイック構築例として有用だと思います。

で、設定サイトを構築してココに各ユーザがログインして force.com に OAuth する機能を作る際、サーバレスで行けると思い込んでやってたんですが forceTK でも PHP のプロキシが必要?とか、結局よく見れてないんですが時間がないので最も確実なサーバサイドでやることにしたということです。

まあ、後で考えたらメールからのリクエストを Chatter へ投稿するプロキシの役目も果たさないといけないのでカスタムな API は必須で結局サーバサイドは必要だったんですが。

Express+node-salesforce で Chatter feed 投稿に関しては node-salesforce の Readme がわかりやすいです。@stomita さん、重ね重ねありがとうございます!

IMAP Proxy

スライドにもありますがソースは Inspect IMAP Traffic Using a Node.js Proxy というブログから拝借しました。JavascriptにコンパイルしたのはGithubに上げてます

IMAPとかTLSとか門外漢なので今でも何となくしか解ってませんが、このソース落として node server.js ってやるだけでローカルで IMAP Proxy サーバがすんなり起動してコレを介してメール受け取るだけでも感動します。

で、ログを見てれば何となく以下の箇所でメールの中身をごにょごにょするんだなと解るので data の中身をパースして Like! をするリンクの HTML を挿入して再度 buffer でバイナリに戻してクライアントに返せば良いと考えます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
connectionToImapServer.on("data", function(data) {
var minusCompress;
console.log(imapServer + ": ", data.toString());
if (!isConnected) {
return;
}
if (data.toString().match(/CAPABILITY.*COMPRESS=DEFLATE/)) {
minusCompress = data.toString().replace("COMPRESS=DEFLATE ", "");
console.log("Proxy substitution: ", minusCompress);
return connectionToClient.write(minusCompress);
} else {
return connectionToClient.write(data);
}
});

メールの生データをパースするには Mailparser を使いました。以下のようにしてパースします。パースしたら前述したDeployd の API へ POST してデータをストアします。

1
2
3
4
5
6
7
// @data メールデータ
mailparser.write(data);
mailparser.end();
mailparser.on("end", function (mail_object) {
console.log(mail_object);
});

ここで実際のハッカソンの時はパースしたメールを元に戻すのがよくわからなくて Mailparser のソースを見て該当しそうなものがなさそうなので結局なまデータを改行で切り分けて文字列処理をしました。

が、今落ち着いてみますと Mailparser の Readme 冒頭に「コレでパースしたのは Nodemailer でメール送信できるよ」っぽいことが書いてるので、その過程でもしかしたら生データを抜けるかもしれないですね(見てないですけど)

今回はスライドにもある通り、1人で馬鹿正直に3日間でアプリを完成させようとしたピエロですがw ただ、こういう差し迫った状態で生産性を向上させた有用な事例として自分の中でも整理できて大変有意義でした!