NTTドコモ様_dカーシェア
NTTドコモ様_dカーシェア
2015.03.30

MQTTブローカーサービス「sango」を使ってJavaScriptだけでチャットを作ってみた

まろ

こんにちは、まろCです。
幼い頃から本が嫌いで、読み始めると数ページで眠くなってたんですが、最近読めるようになりました。なんと、Kindleで読むと眠くならないのです!
もっと言うと、Kindleで行間を空けて、文字を大きくし、1ページで見える文字数をなるべく少なくしたら睡眠魔術が効かなくなってきたのです。

それはさておき、今回は最近話題のMQTTについて、MQTTブローカーサービス「sango」を使ってチャットツールをつくってみたので、そのことを書きたいと思います。実装はフロントのみ!

MQTTとは

sango

一言で言うならば、「あらゆるモノをつなぐ軽量プロトコルで、パブリッシャー(送信者)とサブスクライパー(購読者)の間に位置するMQTTブローカーサーバーを介して、メッセージをやりとりする」といったところ。

ちなみに、Facebook MessengerもMQTTでメッセージのやりとりを行っています。

必要なもの

  • クライアント(PC、SP、マイコンボードなど)
  • MQTTブローカーサーバー

MQTTブローカーサーバーを構築するには、

を使うようですが、今回は作らずにサービスを使います。

ブローカーサービス

スクリーンショット 2015-03-24 11.59.03

使うのはこちら。サーバーもsangoのようなサービスを使うことで、構築せずに気軽に始められるのがいいですね。

とりあえず登録

スクリーンショット 2015-03-24 12.01.34

GitHubアカウントで一発登録です。素晴らしい。すぐに使うことができるんですよ!

ダッシュボード

スクリーンショット 2015-03-24 12.05.53

ここからステータスを見ることができます。

作ってみる

簡単なチャットアプリを作りたいと思います。
1ページ内にメッセージをpublishする入力フォームと、自分を含めた誰かが送信したメッセージを受け取るsubscribeの機能を作っていきます。

参考:sangoの使い方 – JavaScript WebSocket 編 — Sango ドキュメント

MQTTクライアントライブラリはpahoを使います。

Paho – Open Source messaging for M2M

JavaScriptだけでなく、いろいろな言語に対応しています。

サーバーとの通信

まず、pahoライブラリを使ってMQTTブローカーサーバーに接続するところ、メッセージを配信するところ、メッセージを受信するところを実装します。

var client;
var clientID = 'maroc'; //何でもいいみたい
var topic = '{ユーザー名}/test'; //トピックを任意に作成

function connetct() {
    //sangoで表示されている情報
    var userName = {ユーザー名};
    var password = 'PASSWORD';
    var websocketUrl = 'ws://lite.mqtt.shiguredo.jp:8080/mqtt';

    // Pahoの接続clientをnew
    client = new Paho.MQTT.Client(websocketUrl, clientID);
    // ブローカー(sango)に接続
    client.connect({
         userName: userName,
         password: password,
         onSuccess: onConnect,
         onFailure: failConnect
    });
    client.onConnectionLost = onConnectionLost;
    // メッセージがSubscribe(購読者)に届いたらのイベントを登録
    client.onMessageArrived = onMessageArrived;
}

// sangoと接続できなかったら
function failConnect(e) {
    console.log('failed!');
    console.log(e);
}
     
// sangoと接続できたら
function onConnect() {
    console.log('connecct');
    // 接続した時点で購読をスタートさせる。一回で後は誰かがメッセージを送ったらonMessageArrivedが呼ばれる
    subscribe();
}

// ブローカーにメッセージを送信
function publish(msg){
    message = new Paho.MQTT.Message(msg);
    message.destinationName = topic;
    client.send(message);
}

// 購読をする
function subscribe() {
    console.log('subscribe');
    client.subscribe(topic);
}

// メッセージが到着したら
function onMessageArrived(message) {
    console.log('onMessageArrived:'+ message.payloadString);
    msgView.update(message.payloadString); //vue.jsのメソッド
}

// 接続が切れたら
function onConnectionLost(responseObject) {
    if (responseObject.errorCode !== 0) {
        console.log("onConnectionLost:"+responseObject.errorMessage);
    }
}
connetct();

データバインディングはvue.jsで

vue.js

次に、フォームに名前を入れて、内容を送信するところを実装していきます。
inputのエンターを押した時点で、イベントを発火させ、メッセージをsangoに送信します。
送信すると、sangoは接続している全ての購読者に配信します。もちろん自分自身もonConnectで購読者となっていますので、メッセージを受け取ります。それをmsgViewに反映させます。

HTML

<div id="input" class="input">
    <input v-on="keyup:submit | key 13" v-model="msg.c">
</div>
<div id="name" class="name">
    <input v-model="uName">{{uName}}
</div>
<div id="msgView" class="msg-view">
    <div v-repeat="msg" class="{{classname}}">
        <p class="from"><span>{{from}}</span></p>
        <div class="message"><span class="baloon">{{{c}}}</span><span class="date">{{read}}<br>{{date}}</span></div>
    <div>
</div>
<script src="vue.min.js"></script>

JavaScript

var name = new Vue({
    el: '#name',
    data: {
        uName: 'なまえ'
    }
});

new Vue({
    el: '#input',
    data: {
        msg: {
            c: '',
            from: '',
            date: '',
            read: '',
            classname: ''
        }
    },
    methods: {
        submit: function(e){
            e.stopPropagation();
            // console.log(this.msg);
            if (this.msg.c.length > 0) {
                var now = new Date();
                var hour = now.getHours();
                var min = ("0"+ now.getMinutes()).slice(-2);
                this.msg.from = name.uName;
                this.msg.date = hour+ ':'+ min;
                publish(JSON.stringify(this.msg));
                this.msg = {};
            }
            // subscribe(); //onConnectで一回でいい
         }
    }
});

var msgView = new Vue({
    el: '#msgView',
    data: {
        msg: []
    },
    methods: {
        update: function(msg) {
            var received = JSON.parse(msg);
            var _msg = {};
            _msg.c = received.c;
            _msg.from = received.from;
            _msg.date = received.date;
            _msg.read = '既読';
            var classname = '';
            var regexp = new RegExp('^'+name.uName, 'g');
            console.log(msg.match(regexp));
            if (_msg.from.match(regexp) !== null) {
                //じぶん
                classname = 'right_balloon';
            } else {
                classname = 'left_balloon';
            }
            _msg.classname = classname;
            this.msg.push(_msg);
        }
    }
});

すごく簡単に記述できますね。
データバインディングもvue.jsがサクッとやってくれるので最高です。

動かしてみる

ローカルサーバーは、pythonのSimpleHTTPServerを使います。
Macだと最初から入っているので、ローカルでサーバーに上げたいときはこれ一発でOKです。

python -m SimpleHTTPServer 9000

こんな感じで出来上がり

スクリーンショット 2015-03-24 11.47.37img_1196

PCで2つブラウザを開いて、あらかさんにスマホからメッセージを送ってもらいました。自分とあらかさんのやりとりが、もうひとつのブラウザでもしっかり反映されています。
グループチャットも簡単に実装できました!

まとめ

MQTTの特徴にもあるように、送るだけの軽いキーワードであれば、スマホはもちろんのことウェアラブルデバイスやマイコンボードといった、IoTよりなものに向いていると言えます。

今回は時雨堂さんのブローカーサービスsangoを使い、フロントエンドの実装だけでチャットをつくることができました。プロトコルと言うとちょっと難しい気がしますが、このようなサービスがあることでより理解への距離が縮まり、なにができるんだろうとワクワクします。

いま、そのワクワクから僕の中ですごいアイデアが生まれました!
今日作ったものにスタンプ機能や電話帳からの友だち追加機能、無料電話をつけたりして例えばiPhoneやAndroidでアプリとして展開すれば、何でしょう、、世界展開もできるような気がします!
それでは。

参考

 

【チャットツールを作る方法は他にもあります!】

インタラクティブコンテンツを作ろう!milkcocoaで5分のチャットアプリ制作

ChatWorkがメッセージ取得APIを解禁したのでHubotと連携させてみよう!(業界初かも)

チャットツールをGitとNode.jsとHerokuでDIYする方法〜環境構築編〜

チャットツールをGitとNode.jsとHerokuでDIYする方法〜画面作成編〜

チャットツールをGitとNode.jsとHerokuでDIYする方法〜相手作成編〜