緊急地震速報 by Extension
を作って

Mitsuaki Ishimoto
Aug 21, 2011

自己紹介(1)

@mitsuaki_i

Chrome緊急地震速報を出す拡張機能を作りました。

自己紹介(2)

@mitsuaki_i

他はChrome Extensionandroidでかおもじ辞典作ってます

では緊張してますが本題!(・ω・´;)

※早口でいきます!

まず拡張機能について

今回の発表テーマはChromeで動作する拡張機能です

どうして作ろうと思ったのか?

3月11日

開発の経緯(1)

津波で建物が流されるのを見て大変な事が起こったんだと思い、 自宅まで歩いて帰るなかで見たことの無いような光景を目の当たりにし地震による影響を実感

これからどうなってしまうんだろうと漠然とした不安がありました

開発の経緯(2)

・・・

いや!!

・・・

開発の経緯(3)

何かできるんじゃないか!?

作った何かで人の役に立てるはず

災害に役に立つようなものだって作れるはず

人間はこれまでだって困難に直面した時に乗り越えてきたじゃないか

開発の経緯(4)

大きな事を考えたらやる気がみなぎってきました!

うぉぉぉぉ!

@心のなか

開発の経緯(5)

そんななかで2つの事に気づきました。

■緊急地震速報をキャッチするためだけのテレビ

いつでも速報に反応できるようにテレビをつけっぱなしにしていましたが明らかにエネルギーの無駄遣いでした。

■速報の警告音に慌てるだけの現実

警告音には恐怖心を煽られる一方で心構えが全くできていませんでした。

Desktop NotificationsとWebSocketを利用して分かりやすくリアルタイムに緊急地震速報を配信できるはず

開発スタート

3〜4時間できたので軽くテストして早速リリース!!

想定外に凄い勢いで利用者の方が増えていきました...

数日後...バグらせてしまいましたm(__)m

...さて、そんなこんなで技術的な話題でも...

Web Notifications / Desktop Notificationsとは(1)

ぴょこっと出るヤツ

Web Notifications / Desktop Notificationsとは(2)

こういう四角い小窓です。

desktop notifications

Web Notifications / Desktop Notifications

notification = webkitNotifications.createNotification(
    "icon.png",//image
    "\u7DCA\u6025\u5730\u9707\u901F\u5831",// タイトル(緊急地震速報)
    text// お知らせする内容
);

// 一定時間で閉じる場合の処理
//if(localStorage["close"] && localStorage["close"] !== '0'){
    notification.ondisplay = function(){
        timeId = setTimeout(
            function(){
                notification.cancel();// お知らせを閉じる
            },
            1000 * localStorage["close"]
        );
    }
//}

notification.show();// 表示する

たったこれだけ!
(パーミッションが必要です)

WebSocketとは

WebSocketとは(1)

詳しく知りたい方!

html5

こちらの本を読みましょう!

WebSocketとは(2)

もしくは...

小松さんのトラックに参加した人に聞いてください!

WebSocketとは(3)

簡単に言うと今までのリアルタイムと新しいリアルタイムといった感じでしょうか。

ポーリング

リクエストを投げまくる荒技

ロングポーリング

レスポンスを我慢する裏技

WebSocket

WebSocketとは(4)

あとはコードを見ましょう

WebSocket

var connect = function(){
    var conn = new WebSocket('ws://' + host);
    conn.onopen = function(){// 接続時にクライアントのverをサーバに送信
        conn.send('{"version" : "0.5.8"}');
    }
    conn.onmessage = function(e){// データ受信時の処理
        console.log("d:" + e.data);
    }
    conn.onclose = function(){
        host = hosts[Math.floor(Math.random() * hosts.length) % hosts.length];
        setTimeout(function(){connect();}, 5000);// 再接続処理
    }
    return conn;
}
connect();

たったこれだけ!

スリープ(1)

接続できましたが問題がでました...

PCをスリープすると接続が切れているけど、readyStateは変わらない...

スリープ(2)

なんとかスリープしたかどうかを確認できないか...

//現在時刻と前回の時刻を1分毎に比較して、15秒以上秒以上差があったら再接続する。
var reload = 60000;
var before = new Date();
setInterval(function(){
    var current = new Date();
    if((current - before) > (reload + 15000)){
        connect();// 再接続
    }
    before = current;
},reload);

これで判定できました。

しかしスッキリしないのでhtml5-developers-jpに質問を投げてみました。

スリープ(3)

@komasshu

ブラウザとサーバとの間にNATやFireWallがある場合、通信が一定期間無い場合、リソース節約のためにそのセッションテーブルを切ってしまうため、通信ができなくなってしまいます。

この時、ブラウザやサーバに「切ったよ」と伝えることは普通しないので、readyStateを変えることもできず。。

なので、一定間隔でデータを送信(ping)し、サーバから返信(pong)を確認するキープアライブ処理が必要となります。

小松さんありがとうございました!

スリープ(4)

すっきり(*´∀`*)!!

サーバ側:WebSocketサーバ(http://goo.gl/R3ZX7

var WebSocketServer = require('websocket').server;
var server = require('http').createServer(
    function(request, response) {
        response.writeHead(404);
        response.end();
    }
);
server.listen(
    eew.env['port'],
    function() {
        console.log((new Date()) + " Server is listening on port 80");
    }
);
wsServer = new WebSocketServer({
    "httpServer"            : server,
    "autoAcceptConnections" : true
});
wsServer.on(
    'connect',
    function(connection){
        console.log((new Date()) + " Connection accepted.");
        connection.sendUTF('{"status" : "accepted"}');
    }
);

全容はgistに載せました!

サーバ側:twitter(データ受信時の処理)

JSONの文字列を受信しますが途中で切れている場合もあるため、切れていた場合は結合してparseしてます。

response.on(
    'data',
    function(data){
        try{
            var json = JSON.parse(data);
            wsServer.broadcastUTF(data);
            chunk = '';
        }
        catch(e){
            chunk += data;
            try{
                var json = JSON.parse(chunk);
                wsServer.broadcastUTF(chunk);
                chunk = '';
            }
            catch(e2){
                wsServer.broadcastUTF(" ");
            }
        }
    }
);

ふむふむ

サーバ側:twitter(切断時の処理)

UserStreams APIとの接続がたまに切れます

response.on(
    'end',
    function(){
        throw new Error('response::twitter - response - end');
    }
);

スクリプト内で再接続したら?

プロセスを終了させるようにした理由

ポート

困ったことに自宅だと使えるのに会社だと使えないとご連絡をいただきました

プロキシの影響で3分の1の方は
WebSocketで443にしか接続できませんでした

困っていたこと(1)

Chrome13 => 14

draft 76 => draft-ietf-hybi-thewebsocketprotocol-10

WebSocket-Node

draft-10対応。開発者さんが直接教えてくれました!ありがとうBrian!!

Support draft-10 (chrome 14-dev+)

どうやら外に出してモジュール化することで対応する意向らしいです。

Socket IOhybi10 incompatibility

軽く読んだ限りでは最新の仕様では不具合が発生するよう。ロングポールなど代替手段が揃っているので有用な選択肢ではありますが、今回はクライアント側のコードを変更したくないので選択肢から外しました。

追記:8/30動作するようになった模様。

困っていたこと(2)

node.js以外のモジュールは?

pywebsocket

pywebsocketではdraft-ietf-hybi-thewebsocketprotocol-07まで対応しています。

Jetty

Jetty has supported the various WebSocket drafts in the 7.x and 8.x releases.

どうやら最新の実装には対応していない!?ようですね。

他に良い実装があったら是非とも教えて下さい!

困っていること

主に3つくらい...

サーバーは4台、個人運営

=>サーバ...欲しいな...!開発したい人いないかな?
Geolocationの使用でルータがアドホックモードで動作
=>ご存知のかた教えて下さい!
twitter経由でなく直接取得したい
=>気象庁の方!ぜひオープン化を!

反省点

とにかくスピード重視でした
=>テスト環境なども考えることなくリリースしました
=>間違って開発用のをアップロードしてしましました
=>混乱を起こしてしまいましたm(__)m

@agektmrさんを始め
非常に多くの方から励ましをいただきました!

今だから言えること

Twitterにアクセスしまくる暗黒のバージョンがありました
=>リリースしなくて良かったーε-(´∀`*)ホッ

まとめ

自分だけではどうにもならない事も多々ありました。

テストにご協力いただいた方もいます。
様々なフィードバックもいただいてます。
ありがとうございました!!!

おわり

ご清聴ありがとうございました!

※カットしたスライドはコメントアウトしてます