dnlgrv

Building Hello Stranger

TL;DR I built hellostranger.xyz, a Phoenix app for chatting anonymously with a random stranger.

So this week I finally got around to building and deploying something in Phoenix. I wanted to build something that utilised Phoenix’s capability to handle real-time messages through WebSockets (Channels), so chat was the immediate go-to.

The guide on the Phoenix website will get you up and running with a chat app in no time. I wanted to go a step further, so I decided to go with one-on-one chat, where you were paired up with a random stranger who was also connected.

The source code for the entire app is available on GitHub.

Channels

Here’s an overview of the channels that currently exist, and their purpose:

  • id The client retrieves their unique ID when they first join, but stays connected for further events (statistics for number of connected clients).
  • lobby These are the clients that are not currently in a chat. The client will join/leave this channel when their chats start/finish.
  • strangers:123 The 123 is the client’s ID (retrieved from the ID channel). This is how I am able to send messages to an individual client. The channel validates that only a client with that ID is allowed to join.
  • room:123 When two strangers are paired together, a room is created and they are told to join. This is the channel that handles the chat between two strangers.

Overall it was a fairly simple project, but there were a couple of issues that I had trouble with.

The strangers channel

When I first started this I didn’t think I’d actually need the client to be in their own channel. I figured there would be a way to send messages to a connected client via their socket ID. The only message I seemed to be able to get through to them was disconnect, which wasn’t too helpful.

I’ve seen in the Phoenix Slack room that there is something currently being written called Phoenix.Presence, which I think is solving this particular problem.

Matching with another stranger

My initial attempts at putting two individuals in a chat together were fruitless. I initially thought that I would have the first person who connected try and find a stranger, then if it failed, continue to try until they eventually found someone. I actually took the opposite approach.

When they first connect, they try to see if anyone is in the lobby (available to chat). If not, they themselves join the lobby and just wait there. Then when the next client connects, they do the same, except this time someone is waiting and they join a chat together. It turned out to be a lot simpler this way.

Worth mentioning

The site is deployed on Digital Ocean using the wonderful Elixir Release Manager. I haven’t written a post on the deploy process yet (it’s still rather manual), but I will soon.

I’ve learned a lot more about processes and GenServer in general since I started building this, so much so that I think the architecture of even this app could be improved already.

I haven’t done any kind of load testing, so I’m interested to see what happens if this gets any kind of traffic. Phoenix Channels can handle a lot of connections, but I’m worried about the GenServers I have in place being a bottleneck.

I would really like to have either some JavaScript tests or integration tests for the project.

Documentation is missing, I’ll get to it!

The next feature I want to add is a typing indicator (Stranger is typing…).

The source code is available on GitHub in the hope that it might help someone with Phoenix. As always I’m accepting Pull Requests if you want to contribute.

Thanks for reading.