Getting Started
In my previous post i explained what drove me into an implementation of a small OTP app to subscribe json messages in a Redis channel and foward that json to one or several clients.
I’ll walktrough some of the code that you can find here.
The elixir app is under in this folder.
I will assume you already know how to get the app dependencies and how to compile them to get a working elixir app.
The webpage folder has a webpage with bullet.js to give you a jumpstart.
To start the webpage, if you have python installed, you can run python -m SimpleHTTPServer
inside the webpage folder and you will get it at http://localhost:8000
.
Bootstraping
As usual in a mix
project you will have a mix.exs
file and the application modules implemented under the lib
dir.
mix.exs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Lines 4 to 19: Applications defined here are started with the ws_pub_sub app.
Originally i was starting these apps in the start/2 function in lib/ws_pub_sub.ex
but this way feels more natural.
ws_pub_sub.ex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
In line 6 we initialize cowboy registering a websocket handler
module WsHandler
with bullet_handler behaviour.
In line 8 we create an ETS table to hold the data (PID + Session Key)
of all authenticated clients.
The ConnectionTable.ex
module has a few functions defined to make the
use of ets tables more elixir like and abstract the call of erlang
functions.
It allows us to call ConnectionTable.insert(key, value)
instead of :ets.insert(@table_id, {key, value})
Websockets
The websocket handler is implemented in lib/ws_pub_sub/ws_handler.ex
Authorizing via mongo could definetly be extracted to its own module but
i opted to keep the mongo lookup here to allow easier browsing.
ws_handler.ex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Line 3:
We get the querystring from cowboy_req
.
Line 7: We pass the querystring to mongo to chek if the given key exists.
In lib/ws_pub_sub/ws_handler.ex
you will find the mongo connection and query code under
mongo_auth(key)
.
I think it’s easy to follow so i’ll skip it … if you have any doubt open an
issue on the github repo.
If the key is found we add the user key an pid to the connection table
and in line 19 we publish a message in a given redis channel to notify
that a new user is added to the connected users.
That takes us into the RedisPubSub
module.
This module is implemented with gen_server behaviour and it is added to the app supervisor. This way we can recover from any unexpected failure, and keep on listening to messages !
redis_pub_sub.ex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
In this particular file i would like to point out lines 12 and 13.
We subscribe a redis channel and the function we pass as the one to be
executed everytime a message arrives fn(msg) -> MsgPusher.send(msg) end
simply invokes the send/1 function defined under MsgPusher
module.
If you want to see some JSON getting into your browser open a redis console (redis-cli
).
Inside redis-cli enter:
1
|
|
As the included example webpage indicates the websocket connection will only be established(authorized) if you have an entry in MongoDB with _id:
00721b2a-046c-4ecc-a5df-5f808cc6c58f
The default database is myDB
and the collection myCollection
.