This is very simple chess website built using React, Go, and MongoDB. Players will be matched with another player when one is available. They will then be able to play chess in realtime. The frontend is built with React and Redux. It uses the chess.js and chessboardjsx libraries which are used by the likes of chess.com and lichess.org. The underlying databases is MongoDB, using the new MongoDB Driver for Go. Clients communicate with the server through websockets. When a player makes a move, the game is updated in the database. A change stream takes any changes to games and sends them to clients via websockets.
-
Running the React application:
cd frontend npm i npm run dev
This runs webpack dev server. If you build the frontend and serve it with the go app, the chess board will flicker when moving pieces. I haven't figured out the cause of this yet, so best results are when using
npm run dev
to run the react app separatey from the go app. -
Running the Go backend:
cd .. go run .
- Open
localhost:8080
in two browser windows side by side. - Enter a name in one window and click "Start Game".
- Enter another name in the other window and click "Start Game".
- Each window will now have a chess board open. White moves first.
- Each move made will be broadcast to the other player. A list of moves in the game is shown on the side.
- Quick gaem to show off (Scholar's Mate):
1. e4 e5 2. Bc4 Nc6 3. Qh5 Nf6?? 4. Qxf7#
There are 4 files:
-
main.go
:main()
does three things:- calls a function to connect to MongoDB,
- calls a function to start a change stream to watch the
chess.games
collection, - Defines two routes and starts an http server.
The server handles two routes:
/ws
: The websocket which the frontend connects to. The frontend will send moves made to this websocket./start
: Clients will POST here to start a game.
-
mongo.go
:connectMongo()
: Connects to MongoDB usingmongo.Connect()
.watchForChanges()
: Will watch a MongoDB collection and will send the change events to a channel.
-
websockets.go
-
makeHandleWebsockets()
: Returns the handler function for the/ws
endpoint. It creates a websocket using thegorilla
websocket library. A couple of things happen here:- The client registers with the websocket.
- Then in the
readMessages
goroutine, we wait for any messages from the client. The client sends moves. These are added to the game document in the database. - At the same time, we wait for any change events sent through a channel. When we receive these change events, we broadcast that to the players so the state of their game is updated.
-
-
find_game.go
makeHandleStart()
: Returns the handler function for the/start
endpoint. This does the matchmaking. The matchmaking is very simple. If there's a document in the games collection whereblack
is an empty string, that means there's no black player, and the player is added to that game as black. If there isn't a document whereblack
is an empty string, a new game is made where the player is set to be white. They will then have to wait for another player to come along and join their game as black.
It's worth just showing off a couple of things:
-
Show the functionality of the chess app, by playing a few moves.
-
Show
mongo.go
. This shows how to connect to the database inconnectMongo()
and how it watches for changes inwatchForChanges()
-
You can then show how in
websockets.go
, and changes to a game is sent to the players via websockets. The key code block is:for event := range eventChan { fmt.Println("Event received: ", event) for _, client := range clients[event.FullDocument.ID.Hex()] { err := client.WriteJSON(event.FullDocument) if err != nil { log.Printf("error: %v", err) client.Close() } } }