Real-time websockets

Recently I gave OpenAI's system design interview, where I was asked to design an online multiplayer Chess game like chess.com, one that is highly scalable and available. The goal was to create a Publish-Subscribe, event streaming service, Kafka-Zookeeper or a Websocket framework.

Generally we use an API based or HTTP TCP/UDP servics, example library management system project. Here, we make POST and GET api endpoints. With Websockets, we have a continuous connection after handshake, like a tunnel. Once the connection is established, we can start sending and receiving data. There is no polling for information, only sending and receiving, okay, maybe there is some polling involved.

So I took upon myself to create a project and learn about Websockets. With Christoph and ChatGPT’s help, I was able to create this project - tracking multiple cursors in different color on the website.

Website - https://cursor-websocket-001.ue.r.appspot.com
Github - https://github.com/Adhira-Deogade/websockets

Main components
  1. Deployed on Google Cloud. Unlike the coverage image generator, I need a server, not a lambda function.
  2. JavaScript library - socket.io
On-boarding with basics
  1. I started with refreshing my memory on hosting an HTML file - html + body. I go to finder, locate the file and double click on it, the webpage is displayed on my browser. Calling this home.html
  2. Now I needed to learn how to run a javascript server running this html file. I created a file called app.js in the same folder as home.html and created 2 objects - one for reading file from Filesystem, and another of type http for serving this file on a Host and Port. Filesystem object will write the data from home.html to the http server listening on this port.

My goal is to show the cursor of every visitor in unique colors to all the visitors. I first understood how can I get the location value of cursor for 1 visitor. I created a file called click.html which includes the javascript function written inside script tag. What does this function do? What do I want? I want cursor information? Which information? It’s X and Y co-ordinates. I am using the browser API - MouseEvent. This helps me capture cursor's attributes - screenX and screenY and I am display in on console logs.

Now moving on to creating a multi-cursor showing of visitors.

Requirements:
  1. Each user will see their own cursor and other visitor's cursor
  2. Each cursor’s location info is captured in real-time
  3. Location information is broadcasted to other users - excluding myself, since that is redundant
  4. Each cursor is unique in color
  5. Cursor's color gradient needs to be bright and visible
  6. Entire screen is tracked for cursor information
  7. Disconnect when client leaves from the website
Project

For point 6: To achieve entire screen tracking is the easiest part - we declare this in html in the beginning - body -> style -> min-height
For point 2: We create a dictionary, key is client id, and value is cursor's CSS. For point 3: We are using broadcasting function socket.broadcast.emit
For point 4: Use hashing to generate a random color giving us a hash id, hashes are incremental.
For point 5: Use Hue, Saturation and Lightness (HSL) method for CSS styling
For point 7: Remove the client id from the dictionary of cursors.

Now, you might say there are still some mysteries -

Mysteries

what does io.on vs socket.on mean?
io can be found in 2 places - client.html and server.js. In both files io is used in different context. In client.html, io is used as a Websocket provided by socket.io via script tag. This is stored in variable socket. Socket = io().
In server.js, io is used as http server connection. Every time the server is called from a browser, the io server creates a new “socket” which is exclusive with that client.

how is html script and socket server script related?
Socket server script is the host, our main application running on Google Cloud server.
Html script is available to the client when they open the website in the browser. The html script connects to the URL, providing the cursor information in color to the server. Server is common, clients are different.

why do we need 2 scripts?
The server script remains constant and it’s only purpose is to broadcast cursor positions to other clients from current client and remove the cursor when clients disconnect.
The client script is the one sending information about the cursor to the server every time it is connected - it provides cursor color, cursor position and if it is still connected. It also receives information about other clients when the server sends that information.

Deployment to Google Cloud
  1. Download cli and follow the instructions to login and setup an app
  2. Run gcloud app deploy from your current directory
Some learnings
  1. Create .gcloudignore file and add google-cloud-sdk to this file. To refresh terminal run source ~/.zshrc
  2. socket.broadcast.emit vs io.emit. Socket.broadcast.emit is used to send message to all clients except current/source client
  3. io.emit is used to send message to all the clients
  4. There is no need to include the generated URL in your html script since by default the current page URL is used.