I had a lot of fun with my team at GamerBet. We designed and implemented a real-time betting platform for League of Legends games.
I implemented most of the backend code in Golang. This included a core API written in Golang and 4 microservices. The 4 microservices were as follows. Event manager that managed games in the database by polling a third party API. An Interest manager which parsed game data and determined interest level of games. A web scraper which extracted data from websites for player stats.
We later pivoted to a media company. We turned our existing platform into an automatic replay recording system. We added a Replay recording service to record live games for highlights.
Here's how that worked...
The application polls Riot’s API for new games and inserts them into the database through The Great Gamerbet API. When a new game is added, we run a web scraper for each player to get their latest stats.
The application polls Riot’s API for recently ended games then updates them if they were present in the database. When a game ends we sent a Server Sent Event to every client. Any connected betters get a success or completed modal. Through the web client, users are able to signup for an account and place bets on open games.
Our application components
- Web client written in Angular.js
- API written in Golang
- PostgreSQL database
- Website Scraper for LoLKing.com
- Event Manager
- Socket.io WebSockets
The web client was written by my co founder Phil Swanson. It uses websockets with a socket.io service to live update games and alert users on wins and losses.
The API consists of a set of HTTP handlers grouped into 3 different access levels.
Public contains all the HTTP requests that are necessary to view the site as a visitor and nothing more. Think, get open games, get leaderboard, and all other visual data.
Authenticated routes are all routes specific to user actions. They require the user be logged in.
We use token based authentication. The way token based auth works in our application is standard. A user enters a username and password. If the username and password are correct, we issue them a secret token. We store their public user data as a value in Redis and use their token as the key. We send them their token in the response to their login request. The client saves the token in their local storage and sends it on every subsequent request.
Whenever a request is made, the API takes the token out of the HTTP headers and checks if Redis has a value on that key. If it does, we take the necessary data from redis and associate it with the given request. For example, a user is placing a bet. We take his user id and assign it to the new bet object so we’ll know who placed that bet when it comes time to pay money out.
Secret routes are used only by internal services. Services are given a unique token that only works with those routes. No client issued token will work with these routes and there are no login routes for these routes.
The event manager POSTs new games to the API. We don’t want any maliscious sources to post new games to the API. We generate a single crypto secure token and set it as an ENV variable and use it in the event manager and the API.
We use PostgreSQL as our database. GORM Object Relational Mapper is used for most interaction. We have a few routes using custom joins to optimize their speed.
We use primary keys, unique constraints and all the other goodies. Additionally, one thing I like to do is use the database for all my validation. I use CHECKs to check validate input lengths and characters. It keeps all parts of my application in sync. Error messages are transformed into human readable text and bubbled up all the way to the client.
Riot’s API did not have any valuable player stats. Nor was there any other API that existed for this. We created a scraper for the most popular fan made website. It runs an exact match search on the website and returns the stats if the player is found.
This is the most important peice of the application. My co-founder Phil wrote it in python. I later rewrote it in golang. It polls Riot’s API for new games and for new ended games. It then updates our database.
With some experimentation, business side realized people didn’t care about amateur games. They only wanted to bet on pro players. We added a clause to only add games to our database that contained pro players in the match.