Modern real-time chat platform in scalable architecture, written in go.
Kafka is used for message Pub/Sub. Checkout this branch for the Redis Pub/Sub version.
![image](https://private-user-images.githubusercontent.com/50090692/283671652-81733303-b022-4069-91c0-1d0360bede7f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM0MjM1NTUsIm5iZiI6MTcyMzQyMzI1NSwicGF0aCI6Ii81MDA5MDY5Mi8yODM2NzE2NTItODE3MzMzMDMtYjAyMi00MDY5LTkxYzAtMWQwMzYwYmVkZTdmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MTIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODEyVDAwNDA1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWUwNzQ1MTYyZDRkMWVmNWQxNzcxYjgwNDFjM2FlYTQ1NDczMmVhN2UxZDFlNzU4YmViZjUzZTZiZWNmOTAwNDUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.QjRbUmnLMLr0G6V4pTp2T_rMaUBTdfXJV47ikkITvyA)
- Real-time communication and efficient websocket handling using Melody.
- Microservices architecture. All services are stateless and can be horizontally scaled on demand.
web
: frontend serveruser
: user account servermatch
: user matching serverchat
: messaging serverforwarder
: message forwarding server that maps message receivers to specificchat
serversuploader
: file uploader
- Use gRPC for inter-service communication
- with retry, timeout, and circuit breaker
- Use cobra and viper for CLI and configuration management respectively.
- Dependency injection using wire.
- Graceful shutdown.
- Observability using Golang Prometheus client for monitoring and opentelemetry-go for tracing.
- At-least-once delivery for message Pub/Sub using Kafka.
- Persist messages and chat channel metadata in Cassandra, an open source NoSQL distributed database for scalability and high availability.
- Automatically generate RESTful API documentation with Swagger 2.0.
- User login session management using http-only cookie.
- Support Google OAuth2 login.
- User matching with idempotency.
- Chat channel authentication using JWT.
- S3-compatible object storage for uploaded files.
- Channel-level file access control using S3 presigned URLs.
- Support uploading images from clipboard.
- Use Traefik FowardAuth for file upload authentication.
- Protect file upload api with distributed rate limiting (token bucket algorithm).
- Message seen feature.
- Auto-scroll to the first unseen message.
- Persist chat history on browser close or page refresh.
- Automatic websocket reconnection.
- Responsive web design.
Prerequisite:
- Docker-Compose v2
- Root permission
First, create OAuth client ID credentials and replace USER_OAUTH_GOOGLE_CLIENTID
and USER_OAUTH_GOOGLE_CLIENTSECRET
with your credentials in run.sh
.
Example setting:
To run locally, execute the following command:
cd deployments
sudo ./run.sh add-host
./run.sh start
run.sh add-host
needs root permission to alias minio
to localhost
in /etc/hosts
.
Check cassandra connection:
docker exec deployments-cassandra-1 bash -c "cat /opt/bitnami/cassandra/logs/cassandra.log"
docker exec deployments-cassandra-1 bash -c "cqlsh -u ming -p cassandrapass"
This will spin up all services declared in docker-compose.yaml
. Visit http://localhost
and you will see the application home page.
Bucket myfilebucket
will be created automatically on minio
by createbucket
. However, if minio
is still initializing after 5 retries of createbucket
, the bucket creation will fail. If this happens, please run the following command once minio
is up and running:
docker restart deployments-createbucket-1
- Visit
http://localhost
for the application home page. - Visit
http://localhost:8080
for Traefik dashboard. - VIsit
http://localhost:9001
for Minio dashboard. - Visit
http://localhost:9090
for Prometheus dashboard. - Visit
http://localhost:16686
for Jaeger dashboard. - Visit
http://localhost/api/<svc>/swagger/index.html
for API documentation, where<svc>
could beuser
,match
,chat
, oruploader
.
Example configuration: config.example.yaml.
A common scenario is that one deploys the application behind a reverse proxy with SSL termination. If that is your case, remember to correctly configure your proxy for websocket. For example, in Google Cloud Platform, for websocket traffic sent through a Google Cloud external HTTP(S) load balancer, the backend service timeout is interpreted as the maximum amount of time that a WebSocket connection can remain open, whether idle or not. Therefore, you may want to use a timeoutSec
value larger than the default 30 seconds in your BackendConfig
.
Event | Ref | Docker Tags |
---|---|---|
pull_request |
refs/pull/2/merge |
pr-2 |
push |
refs/heads/master |
master |
push |
refs/heads/releases/v1 |
releases-v1 |
push tag |
refs/tags/v1.2.3 |
v1.2.3 , latest |
push tag |
refs/tags/v2.0.8-beta.67 |
v2.0.8-beta.67 , latest |