redis & listening works!!
This commit is contained in:
10
backend/app/db/redis.py
Normal file
10
backend/app/db/redis.py
Normal 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
|
||||||
@ -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()
|
||||||
|
|||||||
@ -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"}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
12
dev.yml
@ -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
4
env/backend/dev.env
vendored
@ -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
|
||||||
7
frontend/app/src/components/user/AnonUserCard.tsx
Normal file
7
frontend/app/src/components/user/AnonUserCard.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const UUIDToColor = (uuid: string): string => {};
|
||||||
|
|
||||||
|
const AnonUserCard = (): JSX.Element => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user