- Client uses a Websocket to connect to 'websocket service'
- Client can register with a login and password using identity service
- Any service can get user id by using identity service
# Download this project
git clone https://github.com/MaximRobota/websocket-chat
Before running services, you should set the database config with yours or set the your database config with my values on .env
MYSQL_HOST=db
MYSQL_USER=user
MYSQL_PASSWORD=devpass
MYSQL_PORT=3398
MYSQL_DB=mysql_database
cd websocket-chat
docker-compose build
docker-compose up
API Endpoints : http://127.0.0.1:5051 (:5052, adminer :8080)
├── identity-service // Our API core handlers
├── message-persistence-service // Check and save events
├── websocket-service // Two-way interactive communication session between the user's browser and a server
├── tests
├── docker-compose.yml
/auth/register (name, pass) -> token
/auth/login (name, pass) -> token
/auth/getIdByToken -> int (id)
- Uses kafka to post messages that need saving (queue “message_save”)
- Listens to kafka (queue “message_events”)
- Checks that a user is a valid user (id service) and only then posts the message to “message_save”
- Sends updates about messages to correct users
- If a user with an invalid token sends a message ignore it and log a warning to stdout
- Listens on “message_save” queue
- Saves messages to database and rollback if an error occurs:
- In case of an error log error to stdout
- Send a message error to “message_events”
- In case of message is saved send message id and other data to “message_events”
- Redis can be used as a key-value storage by websocket service:
- Save user id and message UUID (provided by the client)
- Is required to keep track on which messages are sent by which users
- Connect to a websocket
- Sends message text, user_to_id and a random UUID (generated by client)
- The message UUID is used to identify the message until the message is actually allotted a database id (until it is saved)
- Client sends:
{
uuid: “a62f2bf7-cfe7-48d6x-ad53-956e41b0769b”,
Message: “hi”,
user_to : 2
}
With jwt_token in headers (at connection time)
- Websocket service:
-
Marks the message UUID as the one sent by a user with some id (1? - get the id by token).
-
When a message is saved Websocket service gets a message on “message_events” queue :
{ uuid: “a62f2bf7-cfe7-48d6x-ad53-956e41b0769b”, state: “Saved” }
-
- Websocket service looks up the corresponding websocket handle to send the event (saved)to the correct user and sends
{ uuid: “a62f2bf7-cfe7-48d6x-ad53-956e41b0769b”, state: “Saved” }
- Client gets the message and can identify the correct message to mark it as “successfully sent”.
General:
- Every service is a docker container.
- Every service is written in python 3 (3.7 +)
- Use docker-compose to run the whole stack
- Expect every service to run on the same host (localhost)
- Every service runs on some port
- This port is defined as an environment variable (ENV_VAR)
- Docker-compose.yaml should define the ports for each service (do not hardcode the port values, use environment variables only)
Example:
import os
os.environ[“KAFKA_PORT”] / os.environ[“ID_SERVICE_PORT”]/ ...
web_socket_service:
Image:
Build: ..
Environment:
KAFKA_PORT: 9092
persistence_service:
Image:
Build: ..
Environment:
KAFKA_PORT: 9092
- Docker-compose -f docker_compose.yaml up
- Python3 client_test.py
- Registers 2 users,
- User 1 sends a message to user 2
- assert ( wait for 20 secs) that the message is saved
- Message uuid matches the one we created
- Message state is “saved”
- Use docker-compose up to start for all services
- JWT Authentication
- Flask app for identity service
- Create schema for database MySql
- Implement Kafka Producer / Consumer
- 2 processes
- sends a message
- prints the received message
-
Implement Redis (did not find application in the project) - Implement Kubernetes (basic test without using CP3-WS)