feat: add proxy source crud and wire into app
This commit is contained in:
parent
d249020773
commit
ca58dd94db
@ -4,10 +4,12 @@ from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
from redis.asyncio import from_url as redis_from_url
|
||||
|
||||
from proxy_pool.common.router import router as health_router
|
||||
from proxy_pool.config import get_settings
|
||||
from proxy_pool.db.session import create_session_factory
|
||||
from proxy_pool.plugins.discovery import discover_plugins
|
||||
from proxy_pool.plugins.registry import PluginRegistry
|
||||
from proxy_pool.proxy.router import router as proxy_router
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -57,7 +59,7 @@ def create_app() -> FastAPI:
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
# Register routers here as we build them
|
||||
# app.include_router(...)
|
||||
app.include_router(health_router)
|
||||
app.include_router(proxy_router)
|
||||
|
||||
return app
|
||||
|
||||
126
src/proxy_pool/proxy/router.py
Normal file
126
src/proxy_pool/proxy/router.py
Normal file
@ -0,0 +1,126 @@
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from proxy_pool.common.dependencies import get_db, get_registry
|
||||
from proxy_pool.plugins.registry import PluginRegistry
|
||||
from proxy_pool.proxy.models import ProxySource
|
||||
from proxy_pool.proxy.schemas import (
|
||||
ProxySourceCreate,
|
||||
ProxySourceResponse,
|
||||
ProxySourceUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/sources", tags=["sources"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[ProxySourceResponse])
|
||||
async def list_sources(
|
||||
is_active: bool | None = None,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> list[ProxySourceResponse]:
|
||||
query = select(ProxySource)
|
||||
if is_active is not None:
|
||||
query = query.where(ProxySource.is_active == is_active)
|
||||
query = query.order_by(ProxySource.created_at.desc())
|
||||
|
||||
result = await db.execute(query)
|
||||
sources = result.scalars().all()
|
||||
return [ProxySourceResponse.model_validate(s) for s in sources]
|
||||
|
||||
|
||||
@router.post(
|
||||
"",
|
||||
response_model=ProxySourceResponse,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
async def create_source(
|
||||
body: ProxySourceCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
registry: PluginRegistry = Depends(get_registry),
|
||||
) -> ProxySourceResponse:
|
||||
# Validate parser exists
|
||||
try:
|
||||
registry.get_parser(body.parser_name)
|
||||
except Exception:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"No parser registered with name '{body.parser_name}'",
|
||||
) from None
|
||||
|
||||
source = ProxySource(
|
||||
url=body.url,
|
||||
parser_name=body.parser_name,
|
||||
cron_schedule=body.cron_schedule,
|
||||
default_protocol=body.default_protocol,
|
||||
)
|
||||
db.add(source)
|
||||
await db.commit()
|
||||
await db.refresh(source)
|
||||
|
||||
return ProxySourceResponse.model_validate(source)
|
||||
|
||||
|
||||
@router.get("/{source_id}", response_model=ProxySourceResponse)
|
||||
async def get_source(
|
||||
source_id: UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> ProxySourceResponse:
|
||||
source = await db.get(ProxySource, source_id)
|
||||
if source is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Source not found",
|
||||
)
|
||||
return ProxySourceResponse.model_validate(source)
|
||||
|
||||
|
||||
@router.patch("/{source_id}", response_model=ProxySourceResponse)
|
||||
async def update_source(
|
||||
source_id: UUID,
|
||||
body: ProxySourceUpdate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
registry: PluginRegistry = Depends(get_registry),
|
||||
) -> ProxySourceResponse:
|
||||
source = await db.get(ProxySource, source_id)
|
||||
if source is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Source not found",
|
||||
)
|
||||
|
||||
update_data = body.model_dump(exclude_unset=True)
|
||||
|
||||
if "parser_name" in update_data:
|
||||
try:
|
||||
registry.get_parser(update_data["parser_name"])
|
||||
except Exception:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"No parser registered with name '{update_data['parser_name']}'",
|
||||
) from None
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(source, field, value)
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(source)
|
||||
|
||||
return ProxySourceResponse.model_validate(source)
|
||||
|
||||
|
||||
@router.delete("/{source_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_source(
|
||||
source_id: UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> None:
|
||||
source = await db.get(ProxySource, source_id)
|
||||
if source is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Source not found",
|
||||
)
|
||||
await db.delete(source)
|
||||
await db.commit()
|
||||
Loading…
x
Reference in New Issue
Block a user