Code structure
In this guide you will learn how InstaQuiz server works and how you can extend it for your own usage.
How it works
The application uses Express.Js, Postgresql in the server and Socket.IO on both ends for real-time synchronization between users in a game room.
Data handling
Users, questions and game creation are handled by REST API using express routers.
And actions related to real-time running of the game such as sending game info to all users in game, receiving answers and updating leaderboard, starting the game loop and syncing questions for all users are handled by Socket.IO event handlers.
Caching
For lowest latency while the game loop is running game info and game leaderboard are cached with node-cache that is an in memory key-value caching library
Game logic
Game has 3 statuses:
0 = Created
1 = Running
2 = Ended
Each game contains 10 questions that are randomly selected based on the category selected by the user while creating the game.
Anyone with the link to the game can join and if users lose connection or crash can rejoin if the game is still running.
Users can see who is in the game before joining if the game is ended the results will be displayed instead.
Each question has 20 seconds timeout and if the user answers in the first 6 seconds they will receive the complete score that is 10 and after that each if they answered from 7 to 16 seconds their score is lowered by 1 each 2 seconds and from 17 to 20 by each second delayed, the code for this logic is located at ./server/src/events/answer.ts
Code
The main entry for the application is located at ./server/src/app.js and it will be run when the app starts and sets up an Express.Js app, it's middlewares, routes, Socket.io events handler and event emitters.
Setup express
Setup Socket.IO
Socket events
Event structure
Each event is a function that takes a socket param as entry that receives events
and can have 3 different optional functions as parameters for emitting events to users:
updateWaitList
updateGameInfo
updateLeaderboard
functions receive gameId as parameter and have an optional parameter for getting data from cache.
A socket event handler can have below structure:
handleGetWaitList
Listens to getWaitList
event from socket.
Input parameters
gameId
If game was ended it returns the leaderboard if not returns the list of users present in game.
Path: ./server/src/events/waitlist.ts
handleJoinGame
Listens to joinGame
event from socket.
Input parameters
userId
gameId
If game was ended return error and if it was not the creator of the game add user to game_users table cache leaderboard, return gameInfo and leaderboard.
Path: ./server/src/events/join.ts
handleAnswer
Listens to gameAnswer
socket event.
Input parameters:
gameId
userId
questionId
answerId
isCorrect
Get user answer, calculate score from game last_question_time
field and save to database.
Path: ./server/src/events/answer.ts
handleStartGame
Listens to startGame
socket event.
Input parameters:
userId
gameId
If the game has not started it will be updated in the database, game info and leaderboard will be retrieved from the database, game loop starts and returns current data to the user who started the game.
Game loop emits questions each 15 seconds using timeout and all data is handled by cache the time of game running to ensure there is no delay.
Last updated