ウェブページから JavaScript で MQTT ブローカーに送られてくるデータを取得したかったので、MQTT over WebSocket を試してみました。
RabbitMQ 3.6.6 をいれる
Ubuntu のレポジトリのは 3.5.7 と古いので、Installing on Debian / Ubuntu にしたがって 3.6.6 にします。
既に古いのが入っていても、説明通りに RabbitMQの apt レポジトリを設定して、 apt-get update して install したら自動でアップグレードされます。
プラグインをいれる
rabbitmq_web_mqtt をいれます。これは Community Plugins にありますが、 RabbitMQ のチームが作っているので安心感があります。プラグイン自体が比較的新しくて、RabbitMQ 3.6.1 以降でないと使えません。
$ wget --content-disposition https://bintray.com/rabbitmq/community-plugins/download_file\?file_path\=rabbitmq_web_mqtt-3.6.x-14dae543.ez $ sudo mv rabbitmq_web_mqtt-3.6.x-14dae543.ez /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.6/plugins/ $ sudo rabbitmq-plugins list | grep web_mqtt [ ] rabbitmq_web_mqtt $ sudo rabbitmq-plugins enable rabbitmq_web_mqtt The following plugins have been enabled: cowlib cowboy rabbitmq_web_mqtt Applying plugin configuration to rabbit@stfuawsc... started 3 plugins. $ sudo rabbitmq-plugins list | grep web_mqtt [E*] rabbitmq_web_mqtt
設定する
デフォルトで 15675 が listen されています。このままでいいのですが、念のため設定を書いておくことにしました。
設定例がないのでソースを読むしかないようです。rabbitmq_web_mqtt.schema が設定ファイルのスキーマのようなので、これを参考に以下のようにしました。
{rabbitmq_web_mqtt, [ {tcp_config,[{port, 15675}]} ] }
WebSocket 経路の TLS 化はリバースプロキシ (h2o) で行うので、このサーバ自体には TLS の設定を書いていません。
リバースプロキシ
HTTP フロントエンドの h2o からポート 15675 にリバースプロキシするように設定しました。これで外部から接続可能になります。
なおh2oは定期的にWebSocket接続を切るようになっているので、クライアント側で再接続するコードが必須です。
WebSocket から繋ぐ
認証はどうなるのか? という疑問があるところですが、MQTT レイヤーでのユーザ認証があります。Upgrade 時に Origin による制限などはかけられないようです。
rabbitmq-web-mqtt-examples というレポジトリがあり、これを参考にすれば簡単に接続できます。
ライブラリとして Eclipse Paho の JavaScript 版を使っています。WebSocket のエンドポイントを指定する以外は普通にMQTTするのと変わりません。
var TOPIC = "/foo/bar/baz";
var USER = "foo";
var PASS = "bar";
function mqttConnect() {
var client = new Paho.MQTT.Client(
location.hostname,
location.port || 80,
"/mqtt", "myclientid_" + Math.random().toString(32)
);
client.onConnectionLost = function (responseObject) {
console.log(responseObject);
// reconnect
setTimeout(mqttConnect, 1000);
};
client.onMessageArrived = function (message) {
var data = Number(message.payloadString);
console.log(data);
};
client.connect({
userName: USER,
password: PASS,
timeout: 3,
onSuccess: function () {
console.log('onSuccess');
client.subscribe(TOPIC, {qos: 1});
},
onFailure: function (message) {
console.log('onFailure', message.errorMessage, message);
}
});
}
ブラウザ上の WebSocket の場合、TLS はブラウザ側でやってくれるので、普通の MQTT with TLS の接続で考えることよりも少なくて楽です。