redis & listening works!!

This commit is contained in:
2024-05-10 15:11:25 +03:00
parent 2a696f96c1
commit 0ebfd11851
10 changed files with 105 additions and 14 deletions

10
backend/app/db/redis.py Normal file
View File

@ -0,0 +1,10 @@
import redis
import os
REDIS_HOST = os.environ.get("REDIS_HOST", "redis")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
async def create_redis() -> redis.Redis:
redis_connection = await redis.asyncio.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0)
return redis_connection

View File

@ -1,4 +1,9 @@
from typing import Annotated
from fastapi import Depends
import redis
from .db.database import SessionLocal from .db.database import SessionLocal
from .db.redis import create_redis
def get_db(): def get_db():
@ -7,3 +12,19 @@ def get_db():
yield db yield db
finally: finally:
db.close() db.close()
async def get_redis():
r = await create_redis()
try:
yield r
finally:
r.close()
async def get_pubsub(r: Annotated[redis.Redis, Depends(get_redis)]):
ps = r.pubsub()
try:
yield ps
finally:
ps.close()

View File

@ -1,8 +1,10 @@
from typing import Union from typing import Union, Annotated
from fastapi import FastAPI, Depends from fastapi import FastAPI, Depends
import redis
from .db import models from .db import models
from .db.database import SessionLocal, engine from .db.database import SessionLocal, engine
from .db.redis import create_redis
from .dependencies import get_db from .dependencies import get_db
from .views.auth.api import router as auth_router from .views.auth.api import router as auth_router
@ -17,6 +19,12 @@ app.include_router(auth_router)
app.include_router(news_router) app.include_router(news_router)
@app.on_event("startup")
async def startup_event():
r = await create_redis()
await r.flushall()
@app.get("/") @app.get("/")
async def read_root(): async def read_root():
return {"message": "OK"} return {"message": "OK"}

View File

@ -53,3 +53,10 @@ async def join_queue(
queue_user: Annotated[schemas.QueueUser, Depends(services.join_queue)] queue_user: Annotated[schemas.QueueUser, Depends(services.join_queue)]
) -> schemas.QueueUser: ) -> schemas.QueueUser:
return queue_user return queue_user
@router.post("/{queue_id}/listen")
async def listen_queue(
updated_queue: Annotated[schemas.QueueDetail, Depends(services.set_queue_listener)]
) -> schemas.QueueDetail:
return updated_queue

View File

@ -1,11 +1,23 @@
from typing import Union from typing import Union, List
from pydantic import BaseModel from pydantic import BaseModel
from uuid import UUID from uuid import UUID
from ..auth import schemas as auth_schemas
class QueueUser(BaseModel):
id: UUID
position: int
passed: bool
user: auth_schemas.AnonUser
class Config:
from_attributes = True
class ParticipantInfo(BaseModel): class ParticipantInfo(BaseModel):
total: int total: int
remaining: int remaining: int
users_list: List[QueueUser]
class Queue(BaseModel): class Queue(BaseModel):
@ -30,12 +42,3 @@ class QueueInDb(Queue):
class QueueDetail(Queue): class QueueDetail(Queue):
id: UUID id: UUID
participants: ParticipantInfo participants: ParticipantInfo
class QueueUser(BaseModel):
id: UUID
position: int
passed: bool
class Config:
from_attributes = True

View File

@ -2,8 +2,10 @@ from fastapi import Depends, HTTPException, status
from typing import Annotated from typing import Annotated
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from uuid import UUID from uuid import UUID
import redis
import asyncio
from ...dependencies import get_db from ...dependencies import get_db, get_pubsub
from ...db import models from ...db import models
from ..auth import services as auth_services from ..auth import services as auth_services
@ -50,6 +52,9 @@ def get_detailed_queue(
participants=schemas.ParticipantInfo( participants=schemas.ParticipantInfo(
total=q.users.count(), total=q.users.count(),
remaining=q.users.filter(models.QueueUser.passed == False).count(), remaining=q.users.filter(models.QueueUser.passed == False).count(),
users_list=q.users.filter(models.QueueUser.passed == False).order_by(
models.QueueUser.position.asc()
),
), ),
) )
raise HTTPException( raise HTTPException(
@ -82,3 +87,18 @@ def join_queue(
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,
detail="Not Found", detail="Not Found",
) )
async def set_queue_listener(
queue_id: UUID,
db: Annotated[Session, Depends(get_db)],
ps: Annotated[redis.client.PubSub, Depends(get_pubsub)],
) -> schemas.QueueDetail:
await ps.subscribe(str(queue_id))
async for m in ps.listen():
print(m, flush=True)
if m.get("data", None) == b"updated":
print("UPDATED", flush=True)
break
new_queue = get_detailed_queue(queue_id=queue_id, db=db)
return new_queue

View File

@ -5,4 +5,5 @@ sqlalchemy
psycopg2-binary psycopg2-binary
python-jose[cryptography] python-jose[cryptography]
passlib[all] passlib[all]
captcha captcha
redis[hiredis]

12
dev.yml
View File

@ -13,6 +13,8 @@ services:
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
redis:
condition: service_healthy
frontend: frontend:
build: build:
context: frontend context: frontend
@ -51,3 +53,13 @@ services:
interval: 2s interval: 2s
timeout: 2s timeout: 2s
retries: 5 retries: 5
redis:
image: redis:7.2.4-alpine
restart: unless-stopped
ports:
- 6379
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 2s
timeout: 2s
retries: 5

4
env/backend/dev.env vendored
View File

@ -1,4 +1,6 @@
POSTGRES_USER=user POSTGRES_USER=user
POSTGRES_PASSWORD=password POSTGRES_PASSWORD=password
POSTGRES_DB=db POSTGRES_DB=db
DEBUG=1 DEBUG=1
REDIS_HOST=redis
REDIS_PORT=6379

View File

@ -0,0 +1,7 @@
import React from "react";
const UUIDToColor = (uuid: string): string => {};
const AnonUserCard = (): JSX.Element => {
return;
};