A practical concurrency project that simulates a real-time chat system using goroutines and channels.
This project includes:
- A terminal simulation with fake users sending messages concurrently
- A Go HTTP/WebSocket backend
- A browser chat UI connected to WebSockets
- Support for multiple rooms and private messages
This codebase is designed to make Go concurrency concepts concrete:
- Goroutines for independent user/session workloads
- Channels for safe communication between goroutines
- Fan-in/fan-out message flow through a central room loop
select-driven event loops for joins, leaves, and messages- Non-blocking broadcasts to prevent slow consumers from stalling the room
- Concurrent terminal chat simulation (Alice, Bob, Charlie, Eve)
- Random per-user delays to mimic typing/sending behavior
- Public broadcast messages
- Private messages (targeted user)
- Multiple rooms:
generalgamingprogramming
- Browser chat client over WebSockets
- User listing command (
/users) - Graceful shutdown on
Ctrl+C
High-level flow:
Browser/User
-> WebSocket (/ws)
-> Chat Room event loop
-> Broadcast/private routing
-> User inbox channels
-> WebSocket writer / terminal listener
Core event loop pattern:
for {
select {
case user := <-room.Join:
// add user
case user := <-room.Leave:
// remove user
case msg := <-room.Messages:
// route and broadcast
}
}chat-simulator/
├── cmd/
│ └── main.go
├── internals/
│ ├── chat/
│ │ ├── message.go
│ │ ├── room.go
│ │ └── user.go
│ └── server/
│ └── websockets.go
├── web/
│ ├── index.html
│ ├── js/
│ │ ├── api.js
│ │ └── main.js
│ └── styles/
│ └── styles.css
├── go.mod
└── go.sum
- Go
1.25+
From chat-simulator/:
go mod tidy
go run ./cmdServer starts at:
http://localhost:8080
- Open
http://localhost:8080. - Enter a name.
- Select a room.
- Click Connect.
- Send messages with the composer.
Private message options:
- Fill the "Private target" field and send.
- Or use slash format:
/private Alice Hey there
Useful command:
/usersshows connected users in the current room.
When the app starts, simulated users join general and send random messages concurrently.
This is useful to observe:
- Interleaving outputs
- Room fan-out behavior
- Private vs. broadcast routing
GET /api/rooms- Returns available room names.
GET /ws?name=<user>&room=<room>- Upgrades to WebSocket chat session.
- Each room runs as a dedicated goroutine with a channel-based event loop.
- Each connected user has an inbox channel.
- Broadcast writes are non-blocking to avoid head-of-line blocking from slow clients.
go test ./...
gofmt -w cmd/main.go internals/chat/*.go internals/server/*.go- Typing indicators
- Message persistence
- Rate limiting
- Authentication for named users
- Room history replay on join