I use mosquitto for a lot of projects; it’s a great MQTT broker. However, I’ve also always had to spin my own middleware to meld it into my websocket implementations. This isn’t the worst thing, as the approach allows a custom layer that can do heavy processing before being sent to clients.
The issue being…sometimes I just want the straight stream without the middleware.
To accomplish this, we can build a custom version of the Mosquitto 1.4 branch with libwebsockets that will allow us to configure Mosquitto to output on a websocket.
Fire up the VM on Google Compute Engine
There are two ways to start an instance on Compute Engine; the web panel or the command line. The command line is the easiest in my opinion. This assume you’ve already auth’ed (otherwise you may want to read up on the managing authentication and credentials)
➜ ~ gcloud compute instances create my-instance-name --image centos-7 --zone us-central1-a
Once we’re up and running, we can go ahead an ssh into that instance:
➜ ~ gcloud compute ssh my-instance-name --zone us-central1-a
Grab some dependiences
First things first: grab your development tools:
➜ ~ sudo yum groupinstall "Development Tools"
Now, let’s grab other pieces we’ll need to build libwebsockets and mosquitto:
➜ ~ sudo yum install wget mercurial cmake openssl-devel c-ares-devel libuuid-devel
Fantastic! Now, let’s go get libwebsockets:
➜ ~ wget https://github.com/warmcat/libwebsockets/archive/v1.3-chrome37-firefox30.tar.gz
Building libwebsockets
Presuming everything above went a-okay, we should have all we need to build.
Note: I’ve shorted the zsh command prompts without the path name below; obvisouly we’re changing into a directory and in oh-my-zsh that would put the folder in the path…it just gets a little long on the cut and paste.
➜ ~ tar zxvf v1.3-chrome37-firefox30.tar.gz
➜ ~ cd libwebsockets-1.3-chrome37-firefox30
➜ ~ mkdir build; cd build;
➜ ~ cmake .. -DLIB_SUFFIX=64
➜ ~ sudo make install
The cmake command above is important on CentOS 7; if we don’t give it the lib suffix, the build will fail.
Building Mosquitto 1.4
First, let’s pull the code from the repo using mecurial:
➜ ~ hg clone https://bitbucket.org/oojah/mosquitto
➜ ~ cd mosquitto
➜ ~ hg pull && hg update 1.4
Okay, so you have some code. Now we need to tell Mosquitto to use libwebsockets by editing the config.mk file and enabling WITH_WEBSOCKETS:
WITH_WEBSOCKETS:=yes
After we’ve done that, we can build mosquitto:
➜ ~ make binary
➜ ~ sudo make install
Why “make binary”? Because mosquitto really isn’t very setup to build kindly on CentOS; we would have to change a lot of hardcoded paths to the docbook xsl dependinces. There is a bug marked WONTFIX that explains this (see issue 1269967). Trust me, it’s not worth the time. Just use make binary.
It all went well…or so I thought
So everything builds, you install everything, you go to fire up mosquitto and it fails. Turns out, we need to symlink our libwebsockets lib:
➜ ~ sudo ln -s /usr/local/lib64/libwebsockets.so.4.0.0 /usr/lib/libwebsockets.so.4.0.0
Well, and it would be helpful to have a very basic mosquitto.conf:
autosave_interval 1800
persistence true
persistence_file mosquitto.db
persistence_location /var/mosquitto/
connection_messages true
log_timestamp true
listener 1883
listener 10001 127.0.0.1
protocol websockets
Note the “protocol websockets” line. This is going to enable our implemenation.
Now, we fire mosquitto up:
➜ ~ /usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf -d
Open up some ports
It would help if we told the instance to allow some traffic:
➜ ~ gcloud compute firewall-rules create allow-mqtt --allow tcp:1883
Let us not forget our websocket:
➜ ~ gcloud compute firewall-rules create allow-websocket --allow tcp:10001
Talk with Paho JavaScript
With the server feeling chatty, you can now connect and talk with Eclipse Paho’s JavaScript implementation: Paho JavaScript Client. The wire up is fairly straightforward in the most basic setup:
mqttClient = new Messaging.Client(YOUR_HOST, parseInt(YOUR_PORT), MY_CLIENT_ID);
mqttClient.onConnectionLost = onConnectionLost;
mqttClient.onMessageArrived = onMessageArrived;
mqttClient.connect({onSuccess:onConnect});
function onConnect() {
client.subscribe("#");
}
function onMessageArrived(response) {
var ret_topic = response.destinationName;
var ret_payload = response.payloadString;
// More things!
}