feature/crud-mongodb-proxy #3
@@ -1,13 +1,13 @@
|
|||||||
from fastapi import APIRouter, HTTPException, status
|
from fastapi import APIRouter, HTTPException, status
|
||||||
|
|
||||||
from models.proxy import ProxyCreateInput, ProxyUpdateInput
|
from db.proxy import (
|
||||||
from utils.proxy.manager import (
|
|
||||||
create_proxy,
|
create_proxy,
|
||||||
delete_proxy,
|
delete_proxy,
|
||||||
get_proxy_by_port,
|
get_proxy_by_port,
|
||||||
list_proxies as list_proxy_documents,
|
list_proxies as list_proxy_documents,
|
||||||
update_proxy,
|
update_proxy,
|
||||||
)
|
)
|
||||||
|
from models.proxy import ProxyCreateInput, ProxyUpdateInput
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter(
|
||||||
prefix="/proxy",
|
prefix="/proxy",
|
||||||
@@ -15,12 +15,12 @@ router = APIRouter(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("")
|
||||||
async def list_proxies_handler():
|
async def list_proxies_handler():
|
||||||
return await list_proxy_documents()
|
return await list_proxy_documents()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{proxy_port}/")
|
@router.get("/{proxy_port}")
|
||||||
async def get_proxy(proxy_port: int):
|
async def get_proxy(proxy_port: int):
|
||||||
proxy = await get_proxy_by_port(proxy_port)
|
proxy = await get_proxy_by_port(proxy_port)
|
||||||
if proxy is None:
|
if proxy is None:
|
||||||
@@ -28,7 +28,7 @@ async def get_proxy(proxy_port: int):
|
|||||||
return proxy
|
return proxy
|
||||||
|
|
||||||
|
|
||||||
@router.post("/", status_code=status.HTTP_201_CREATED)
|
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||||
async def create_proxy_handler(payload: ProxyCreateInput):
|
async def create_proxy_handler(payload: ProxyCreateInput):
|
||||||
existing_proxy = await get_proxy_by_port(payload.proxy_port)
|
existing_proxy = await get_proxy_by_port(payload.proxy_port)
|
||||||
if existing_proxy is not None:
|
if existing_proxy is not None:
|
||||||
@@ -45,7 +45,7 @@ async def create_proxy_handler(payload: ProxyCreateInput):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{proxy_port}/")
|
@router.put("/{proxy_port}")
|
||||||
async def edit_proxy(proxy_port: int, payload: ProxyUpdateInput):
|
async def edit_proxy(proxy_port: int, payload: ProxyUpdateInput):
|
||||||
updated_proxy = await update_proxy(proxy_port, payload)
|
updated_proxy = await update_proxy(proxy_port, payload)
|
||||||
if updated_proxy is None:
|
if updated_proxy is None:
|
||||||
@@ -53,7 +53,7 @@ async def edit_proxy(proxy_port: int, payload: ProxyUpdateInput):
|
|||||||
return updated_proxy
|
return updated_proxy
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{proxy_port}/", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{proxy_port}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def remove_proxy(proxy_port: int):
|
async def remove_proxy(proxy_port: int):
|
||||||
deleted = await delete_proxy(proxy_port)
|
deleted = await delete_proxy(proxy_port)
|
||||||
if not deleted:
|
if not deleted:
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Any, Mapping
|
||||||
|
|
||||||
|
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||||
|
from pymongo import ReturnDocument
|
||||||
|
|
||||||
|
from core.mongodb import get_database
|
||||||
|
from models.proxy import ProxyDocument, ProxyUpdateInput
|
||||||
|
from models.service import ServiceEndpointDocument
|
||||||
|
from utils.proxy.types import ServiceConfig
|
||||||
|
|
||||||
|
COLLECTION_NAME = "proxies"
|
||||||
|
|
||||||
|
|
||||||
|
def _utcnow() -> datetime:
|
||||||
|
return datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
|
async def _collection() -> AsyncIOMotorCollection[dict[str, Any]]:
|
||||||
|
database = await get_database()
|
||||||
|
return database[COLLECTION_NAME]
|
||||||
|
|
||||||
|
|
||||||
|
def _deserialize_proxy(raw: Mapping[str, Any] | None) -> ProxyDocument | None:
|
||||||
|
if raw is None:
|
||||||
|
return None
|
||||||
|
document = dict(raw)
|
||||||
|
document.pop("_id", None)
|
||||||
|
return ProxyDocument.model_validate(document)
|
||||||
|
|
||||||
|
|
||||||
|
async def ensure_proxy_indexes() -> None:
|
||||||
|
collection = await _collection()
|
||||||
|
await collection.create_index("proxy_port", unique=True, name="uq_proxy_port")
|
||||||
|
|
||||||
|
|
||||||
|
async def create_proxy(
|
||||||
|
proxy_port: int,
|
||||||
|
name: str,
|
||||||
|
service: ServiceConfig,
|
||||||
|
code: str,
|
||||||
|
) -> ProxyDocument:
|
||||||
|
now = _utcnow()
|
||||||
|
proxy = ProxyDocument(
|
||||||
|
proxy_port=proxy_port,
|
||||||
|
name=name,
|
||||||
|
code=code,
|
||||||
|
service=ServiceEndpointDocument(address=service["address"], port=service["port"]),
|
||||||
|
created_at=now,
|
||||||
|
updated_at=now,
|
||||||
|
)
|
||||||
|
|
||||||
|
collection = await _collection()
|
||||||
|
await collection.insert_one(proxy.model_dump(exclude_none=True))
|
||||||
|
return proxy
|
||||||
|
|
||||||
|
|
||||||
|
async def get_proxy_by_port(proxy_port: int) -> ProxyDocument | None:
|
||||||
|
collection = await _collection()
|
||||||
|
raw = await collection.find_one({"proxy_port": proxy_port})
|
||||||
|
return _deserialize_proxy(raw)
|
||||||
|
|
||||||
|
|
||||||
|
async def list_proxies() -> list[ProxyDocument]:
|
||||||
|
collection = await _collection()
|
||||||
|
cursor = collection.find({}).sort("proxy_port", 1)
|
||||||
|
|
||||||
|
proxies: list[ProxyDocument] = []
|
||||||
|
async for raw in cursor:
|
||||||
|
proxy = _deserialize_proxy(raw)
|
||||||
|
if proxy is not None:
|
||||||
|
proxies.append(proxy)
|
||||||
|
return proxies
|
||||||
|
|
||||||
|
|
||||||
|
async def update_proxy(proxy_port: int, updates: ProxyUpdateInput) -> ProxyDocument | None:
|
||||||
|
payload = updates.model_dump(exclude_none=True)
|
||||||
|
if not payload:
|
||||||
|
return await get_proxy_by_port(proxy_port)
|
||||||
|
|
||||||
|
payload["updated_at"] = _utcnow()
|
||||||
|
|
||||||
|
collection = await _collection()
|
||||||
|
raw = await collection.find_one_and_update(
|
||||||
|
{"proxy_port": proxy_port},
|
||||||
|
{"$set": payload},
|
||||||
|
return_document=ReturnDocument.AFTER,
|
||||||
|
)
|
||||||
|
return _deserialize_proxy(raw)
|
||||||
|
|
||||||
|
|
||||||
|
async def delete_proxy(proxy_port: int) -> bool:
|
||||||
|
collection = await _collection()
|
||||||
|
result = await collection.delete_one({"proxy_port": proxy_port})
|
||||||
|
return result.deleted_count > 0
|
||||||
+1
-1
@@ -3,9 +3,9 @@ from contextlib import asynccontextmanager
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from api.proxy.router import router as proxy_router
|
from api.proxy.router import router as proxy_router
|
||||||
|
from db.proxy import ensure_proxy_indexes
|
||||||
from core.mongodb import close_mongodb, init_mongodb
|
from core.mongodb import close_mongodb, init_mongodb
|
||||||
from core.redis import close_redis, init_redis
|
from core.redis import close_redis, init_redis
|
||||||
from utils.proxy.manager import ensure_proxy_indexes
|
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
|
|||||||
@@ -1,95 +1,10 @@
|
|||||||
from datetime import datetime, timezone
|
|
||||||
from typing import Any, Mapping
|
|
||||||
|
|
||||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
|
||||||
from pymongo import ReturnDocument
|
|
||||||
|
|
||||||
from core.mongodb import get_database
|
|
||||||
from models.proxy import ProxyDocument, ProxyUpdateInput
|
|
||||||
from models.service import ServiceEndpointDocument
|
|
||||||
from utils.proxy.types import ServiceConfig
|
from utils.proxy.types import ServiceConfig
|
||||||
|
|
||||||
COLLECTION_NAME = "proxies"
|
|
||||||
|
|
||||||
|
|
||||||
def _utcnow() -> datetime:
|
|
||||||
return datetime.now(timezone.utc)
|
|
||||||
|
|
||||||
|
|
||||||
async def _collection() -> AsyncIOMotorCollection[dict[str, Any]]:
|
|
||||||
database = await get_database()
|
|
||||||
return database[COLLECTION_NAME]
|
|
||||||
|
|
||||||
|
|
||||||
def _deserialize_proxy(raw: Mapping[str, Any] | None) -> ProxyDocument | None:
|
|
||||||
if raw is None:
|
|
||||||
return None
|
|
||||||
document = dict(raw)
|
|
||||||
document.pop("_id", None)
|
|
||||||
return ProxyDocument.model_validate(document)
|
|
||||||
|
|
||||||
|
|
||||||
async def ensure_proxy_indexes() -> None:
|
|
||||||
collection = await _collection()
|
|
||||||
await collection.create_index("proxy_port", unique=True, name="uq_proxy_port")
|
|
||||||
|
|
||||||
|
|
||||||
async def create_proxy(
|
async def create_proxy(
|
||||||
proxy_port: int,
|
port: int,
|
||||||
name: str,
|
name: str,
|
||||||
service: ServiceConfig,
|
service: ServiceConfig,
|
||||||
code: str,
|
code: str
|
||||||
) -> ProxyDocument:
|
):
|
||||||
now = _utcnow()
|
return
|
||||||
proxy = ProxyDocument(
|
|
||||||
proxy_port=proxy_port,
|
|
||||||
name=name,
|
|
||||||
code=code,
|
|
||||||
service=ServiceEndpointDocument(address=service["address"], port=service["port"]),
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now,
|
|
||||||
)
|
|
||||||
|
|
||||||
collection = await _collection()
|
|
||||||
await collection.insert_one(proxy.model_dump(exclude_none=True))
|
|
||||||
return proxy
|
|
||||||
|
|
||||||
|
|
||||||
async def get_proxy_by_port(proxy_port: int) -> ProxyDocument | None:
|
|
||||||
collection = await _collection()
|
|
||||||
raw = await collection.find_one({"proxy_port": proxy_port})
|
|
||||||
return _deserialize_proxy(raw)
|
|
||||||
|
|
||||||
|
|
||||||
async def list_proxies() -> list[ProxyDocument]:
|
|
||||||
collection = await _collection()
|
|
||||||
cursor = collection.find({}).sort("proxy_port", 1)
|
|
||||||
|
|
||||||
proxies: list[ProxyDocument] = []
|
|
||||||
async for raw in cursor:
|
|
||||||
proxy = _deserialize_proxy(raw)
|
|
||||||
if proxy is not None:
|
|
||||||
proxies.append(proxy)
|
|
||||||
return proxies
|
|
||||||
|
|
||||||
|
|
||||||
async def update_proxy(proxy_port: int, updates: ProxyUpdateInput) -> ProxyDocument | None:
|
|
||||||
payload = updates.model_dump(exclude_none=True)
|
|
||||||
if not payload:
|
|
||||||
return await get_proxy_by_port(proxy_port)
|
|
||||||
|
|
||||||
payload["updated_at"] = _utcnow()
|
|
||||||
|
|
||||||
collection = await _collection()
|
|
||||||
raw = await collection.find_one_and_update(
|
|
||||||
{"proxy_port": proxy_port},
|
|
||||||
{"$set": payload},
|
|
||||||
return_document=ReturnDocument.AFTER,
|
|
||||||
)
|
|
||||||
return _deserialize_proxy(raw)
|
|
||||||
|
|
||||||
|
|
||||||
async def delete_proxy(proxy_port: int) -> bool:
|
|
||||||
collection = await _collection()
|
|
||||||
result = await collection.delete_one({"proxy_port": proxy_port})
|
|
||||||
return result.deleted_count > 0
|
|
||||||
Reference in New Issue
Block a user