One visualization I’ve always wanted is some elegant way to be notified whenever someone visited a website of mine. This past week, I was able to make that wish a reality by building software to make the lights on my laptop keyboard blink whenever someone makes an HTTP request to my server. Here’s what it looks like.

Note that I have two keyboards connected to my laptop to make the blinking more apparent in video form. Additionally, you can see the lights blink several times in the video without me making a request; those additional blinks are from requests made by other people.

tl;dr: I wrote a program that runs on my server to track HTTP requests, that program communicates over the internet to another program running on my laptop, and the program running on my laptop blinks the lights on my laptop keyboard when my server says “I got an HTTP request”. Read on for more details and source code.

Background

I seem to remember seeing projects in the past where people made lights blink when their site got a visitor, but right now I can’t seem to find any of those old projects. The only one I could find is this example by Dimitrios Vlastaras using an Arduino, and that required the computer running his HTTP server to be physically connected via USB to an Arduino which blinks its LED. That wouldn’t fly for me, since I use a rented server in a datacenter to serve my web pages, so I can’t physically access the server (so no plugging things into the server).

What I wanted

What I wanted was some way to get a notification (hopefully as simple as a blinking light) no matter where I am, and I want the notification to happen automatically. So I don’t want to have to actively “tune in” to get notifications; I want something that’s smart enough so that it’ll notify me automatically without much intervention. Additionally, I want these notifications to be “gentle”, gentler than an annoying beep or a vibration. Let’s write these requirements out a bit more formally:

  1. Notifications on HTTP requests can happen remotely; I shouldn’t need to be nearby my web server or physically connected to it at all.
  2. The mechanism for notifications should be resilient and passive. I shouldn’t have to “turn on” a notification system, it should always be happening.
  3. The presentation of notifications should be tasteful and not overly jarring. No beeping sounds, no popup windows, no vibrating device.

These requirements are relatively vague and open ended, and that’s intentional. I could have implemented this notification system in any number of ways, and I’d thought of plenty. For example, a small patch of my desktop menu-bar could have changed colors when my server received an HTTP request. Certain requirements also exclude certain approaches; for example, I don’t want to make my phone buzz every time an HTTP request is received, as that would probably get annoying really fast.

Ultimately though, I opted for a program that makes the lights on my keyboard blink on and off when my web server receives an HTTP request. These indicator lights are already built to fit in the visibility niche I described above, where they don’t draw too much attention to themselves, but are still meant to provide information to the user.

However, I still had to figure out all the mechanisms for making the keyboard lights on my laptop blink when my server received an HTTP request.

The very terse answer to that is: I make the lights blink by making the correct ioctl syscall to the Linux kernel which my laptop is running, and the Linux kernel knows how to turn those lights on and off, and does it for me.

Thankfully, you can ignore diving too far into that because I’ve created a Go package which provides a nice interface for making the keyboard lights of your computer blink. To make the keyboard lights blink, I import that package and call the Do method with a duration of my choosing, causing the lights on my keyboard to blink for that amount of time. Here’s an example Go program using my package that will make the keyboard lights blink on for one second:

package main import ( "time" "github.com/lelandbatey/blink" ) func main() { blink.Do(1 * time.Second) }

Note that the above program will probably need to be run as root, since only root can make the necessary syscalls.

How does my laptop know when my server receives a request?

My laptop is able to know when my server receives a request because I’ve written software for the server to tell my laptop when it receives a request. Actually there’s two parts to this software, a server which runs on my server, and a client which runs on my laptop. How they work together:

My software on my server spawns a TCP server and watches the /var/log/apache2/ directory on my server for changes to files. Any changes to files within that directory will be changes to log files, the vast majority of which are changes to the access.log file which has a new line appended to the end of it whenever apache2 serves an HTTP request (since all HTTP traffic on my server is routed through apache2, every HTTP request to my server results in a modification to the access logs). Upon seeing a change to a file, my software will write a single special byte to all the clients who are connected to it via TCP.

The client software on my laptop connects to my server via TCP socket and waits for that special byte (I chose the null byte in this case) to be sent by the server. When the client on my laptop recieves the null byte, it blinks my keyboard lights.

Additionally, since my laptop is constantly being moved around, losing and regaining network conectivity, being opened and closed, I wanted my client to detect when it’s connection has failed so it may try to reconnect. To do this, I changed the server software so that it sends “heartbeat” bytes once every ten seconds, with the client expecting a least one byte (heartbeat or not) every ten seconds. If the client doesn’t recieve any data from the server for 10 seconds, then the client assumes that something’s gone wrong, closes the connection, and tries to reconnect.

The source of the client and server for making this work may be found here: https://github.com/lelandbatey/watchserver

Summary

I wrote some software to run on my server which monitors for new HTTP requests, that software then tells software on my laptop that a new request was served, so the software on my laptop blinks the lights.

Writing this software has been fun, and I want to give big props to the Go language for making it easy to build and reason about concurrent software, it made building this little project fun and easy!