fxosコードリーディングミートアップ#16 contacts api読んでみた

28
Contacts API読んでみた 株式会社グローバルサイバーグループ マネージャ 藪下 正美

Upload: masami-yabushita

Post on 20-Jul-2015

322 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

Contacts API読んでみた

株式会社グローバルサイバーグループ

マネージャ

藪下正美

Page 2: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

はじめに

Page 3: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

自己紹介

• 藪下正美

• 株式会社グローバルサイバーグループというところから来ました

• Firefox OSコミュニティから来ました

• Codezineに記事乗りました!

– http://codezine.jp/article/detail/8540

Page 4: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

今日のおはなし

• Contacts APIとは

• 手始めにfindメソッドを追ってみる

• getAllメソッドを見てみる

• まとめ

Page 5: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

Contacts APIとは

• 使い方のおはなしは#11でやったのでslideshareとか参照

– http://www.slideshare.net/aoitan/meetup11-contacts-api

Page 6: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

手始めにFINDメソッドを追ってみる

Page 7: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

まずざっとまとめ

• パーミッションチェック

• チェックがallowならsendAsyncMessageで 'Contacts:Find' メッセージを投げる

• Parentプロセスで動いているContactsServiceが 'Contacts:Find' メッセージを受信すると

• ContactDBを検索

• ContactDBの処理が終わったらChildプロセスに 'Contacts:Find:Return:OK' か'Contacts:Find:Return:KO' メッセージを送信

• ContactsManagerがメッセージを受信してDOMRequestのsuccessイベントかerrorイベントを発火

• 間にIPCとか挟まってるけど闇が深いので省略!

• 間にIndexedDBHelperとか挟まってるけどただのプロミスラッパーなので省略!

Page 8: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(1)

• パーミッションチェック

• チェックがallowならsendAsyncMessageで 'Contacts:Find' メッセージを投げる

find: function(aOptions) {if (DEBUG) debug("find! " + JSON.stringify(aOptions));let request = this.createRequest();let options = { findOptions: aOptions };let allowCallback = function() {

cpmm.sendAsyncMessage("Contacts:Find", {requestID: this.getRequestId({

request: request,reason: "find"

}), options: options });}.bind(this)this.askPermission("find", request, allowCallback);return request;

},

Page 9: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(2)

• Chromeプロセスで動いているContactsServiceが 'Contacts:Find' メッセージを受信すると

receiveMessage: function(aMessage) {if (DEBUG) debug("receiveMessage " + aMessage.name);let mm = aMessage.target;let msg = aMessage.data;let cursorList;

switch (aMessage.name) {case "Contacts:Find":

Page 10: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(3)

• ContactDBを検索

• ContactDBの処理が終わったらChildプロセスに 'Contacts:Find:Return:OK' か'Contacts:Find:Return:KO' メッセージを送信

this._db.find(function(contacts) {

for (let i in contacts) {result.push(contacts[i]);

}if (DEBUG) debug("result:" + JSON.stringify(result));mm.sendAsyncMessage("Contacts:Find:Return:OK",

{requestID: msg.requestID, contacts: result});}.bind(this),function(aErrorMsg) {

mm.sendAsyncMessage("Contacts:Find:Return:KO", {requestID: msg.requestID,errorMsg: aErrorMsg });

}.bind(this), msg.options.findOptions);

Page 11: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(4)

• ContactsManagerがメッセージを受信してDOMRequestのsuccessイベントかerrorイベントを発火

receiveMessage: function(aMessage) {if (DEBUG) debug("receiveMessage: " + aMessage.name);let msg = aMessage.json;let contacts = msg.contacts;

let req;switch (aMessage.name) {

case "Contacts:Find:Return:OK":req = this.getRequest(msg.requestID);if (req) {

let result = this._convertContacts(contacts);Services.DOMRequest.fireSuccess(req.request, result);

} else {if (DEBUG) debug("no request stored!" + msg.requestID);

}break;

Page 12: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

GETALLメソッドを見てみる

Page 13: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

まずざっとまとめ

• パーミッションチェック

• チェックがallowならsendAsyncMessageで 'Contacts:GetAll' メッセージを投げる

• Parentプロセスで動いているContactsServiceが 'Contacts:GetAll' メッセージを受信すると

• ContactDBを検索

• ContactDBのカーソルが回るたびにChildプロセスに 'Contacts:GetALl:Next' メッセージを送信する

• 処理失敗が起きたら 'Contacts:GetAll:Return:KO' メッセージを送信

• ContactsManagerがメッセージを受信してDOMCursorのsuccessイベントかerrorイベントを発火

Page 14: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(1)

• パーミッションチェック

• チェックがallowならsendAsyncMessageで 'Contacts:GetAll' メッセージを投げる

getAll: function CM_getAll(aOptions) {if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));let [cursorId, cursor] = this.createCursor();let allowCallback = function() {

cpmm.sendAsyncMessage("Contacts:GetAll", {cursorId: cursorId, findOptions: aOptions});

}.bind(this);this.askPermission("find", cursor, allowCallback);return cursor;

},

Page 15: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(2)

• Parentプロセスで動いているContactsServiceが 'Contacts:GetAll' メッセージを受信すると

receiveMessage: function(aMessage) {if (DEBUG) debug("receiveMessage " + aMessage.name);let mm = aMessage.target;let msg = aMessage.data;let cursorList;

switch (aMessage.name) {(snip)

case "Contacts:GetAll":

Page 16: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(3)

• ContactDBを検索

• ContactDBのカーソルが回るたびにChildプロセスに 'Contacts:GetALl:Next' メッセージを送信する

this._db.getAll(function(aContacts) {

try {mm.sendAsyncMessage("Contacts:GetAll:Next",

{cursorId: msg.cursorId, contacts: aContacts});if (aContacts === null) {

let cursorList = this._cursors.get(mm);let index = cursorList.indexOf(msg.cursorId);cursorList.splice(index, 1);

}} catch (e) {

if (DEBUG) debug("Child is dead, DB should stop sending contacts");throw e;

}}.bind(this),

Page 17: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(4)

• 処理失敗が起きたら 'Contacts:GetAll:Return:KO' メッセージを送信

function(aErrorMsg) {mm.sendAsyncMessage("Contacts:GetAll:Return:KO",

{ requestID: msg.cursorId, errorMsg: aErrorMsg });},msg.findOptions, msg.cursorId);

break;

Page 18: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(5)

• ContactsManagerがメッセージを受信してDOMCursorのsuccessイベントかerrorイベントを発火

case "Contacts:GetAll:Next":(snip)

this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));(snip)

break;

(snip)

_fireSuccessOrDone: function(aCursor, aResult) {if (aResult == null) {

Services.DOMRequest.fireDone(aCursor);} else {

Services.DOMRequest.fireSuccess(aCursor, aResult);}

},

Page 19: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

具体的なコードを見てみる(6)

• ContactsManagerがメッセージを受信してDOMCursorのsuccessイベントかerrorイベントを発火

case "Contacts:GetAll:Return:KO":req = this.getRequest(msg.requestID);if (req) {

Services.DOMRequest.fireError(req.cursor, msg.errorMsg);}break;

Page 20: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

他のメソッド

• どうやら基本は同じ

• 多少プロパティを詰め直したりとかしてるAPIはあるけどやることはfindと同じ

• getAllだけはDOMCursorを扱う都合で多少違った

Page 21: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

まとめ

Page 22: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

ちょっと寄り道

Page 23: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

なぜsendAsyncMessageが挟まっているのか(1)

• 簡単なプロセスの図

Chrome Content

Systemアプリ Contactsアプリ

ContacsServiceContactDB

ContactsManager

Page 24: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

なぜsendAsyncMessageが挟まっているのか(2)

• こんな感じでFxOSのアプリはアプリのプロセスとシステムのプロセスがわかれている

• なので基本的に子プロセスは権限の必要な作業は親プロセスに依頼しないといけない

–非同期に動くメソッドは大体プロセス境界をまたいでいる

• そこでpostなんとかMessageやsendなんとかMessageの出番

• Gaiaで閉じているものだとiframe間の通信なのでpostMessageが使われる

• Gecko側に実体のあるものだとsendAsyncMessage

• 基本的に同じ使い勝手のもので文字列とかJSONオブジェクトしか投げられないのでコマンド文字列とかこねこねしていることが多い

Page 25: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

全体像

• 全体図

Chrome Content

ContactsService ContactsManager

ContactDB

IndexedDB

sendAsyncMessage

Page 26: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

ContentsManager

• メソッドの呼び出しを受けたらパーミッションチェックして親プロセスへのメッセージ送信

• 戻りメッセージを待ち受けてDOMRequestやDOMCursorのイベントを発火

Page 27: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

ContactsService

• 子プロセスからのメッセージを待ち受けてDB処理

– find/save/remove/clearは成功時と失敗時のコールバックを与えてDBのメソッドを呼ぶ

• コールバックの中身は子プロセスに対するsendAsyncMessage

• 成功時は元のメッセージに 'Return:OK' を付けて投げる

• 失敗時は元のメッセージに 'Return:KO' を付けて投げる

– getAllはカーソルが返るのでカーソル一つ回すごとに 'Contacts:GetAll:Next' メッセージをsendAsyncMessageで飛ばす

• sim入れ替えの監視

Page 28: FxOSコードリーディングミートアップ#16 Contacts API読んでみた

ContactDB

• 連絡帳用のDB処理をまとめている

• 単にIndexedDBラッパー