qwen2api-v2 / backend /core /database.py
fromozu's picture
Add MongoDB-enabled Python files (database.py, config.py, main.py, admin.py)
5718d27 verified
import asyncio
import json
import logging
from pathlib import Path
from typing import Any, Dict, List, Optional
log = logging.getLogger("qwen2api.db")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# JSON ๆ–‡ไปถๅญ˜ๅ‚จ๏ผˆๆœฌๅœฐๅผ€ๅ‘ / Docker ๅทๆจกๅผ๏ผ‰
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
class AsyncJsonDB:
"""ๅธฆๅผ‚ๆญฅ่ฏปๅ†™้”็š„ JSON ๆ–‡ไปถๅญ˜ๅ‚จ๏ผŒ้˜ฒๆญขๅนถๅ‘ๆŸๅใ€‚"""
def __init__(self, path: str | Path, default_data: Any = None):
self.path = Path(path)
self.default_data = default_data if default_data is not None else []
self._lock = asyncio.Lock()
self._data: Any = None
self._init_file()
def _init_file(self):
if not self.path.exists():
self.path.parent.mkdir(parents=True, exist_ok=True)
self.path.write_text(json.dumps(self.default_data, indent=2, ensure_ascii=False), encoding="utf-8")
async def load(self) -> Any:
async with self._lock:
if not self.path.exists():
self._data = self.default_data
return self._data
try:
content = self.path.read_text(encoding="utf-8")
self._data = json.loads(content)
except Exception as e:
log.error(f"Failed to load JSON from {self.path}: {e}")
self._data = self.default_data
return self._data
async def save(self, data: Any):
async with self._lock:
self._data = data
try:
self.path.write_text(json.dumps(self._data, indent=2, ensure_ascii=False), encoding="utf-8")
except Exception as e:
log.error(f"Failed to save JSON to {self.path}: {e}")
async def get(self) -> Any:
if self._data is None:
return await self.load()
return self._data
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# MongoDB Atlas ๆŒไน…ๅŒ–๏ผˆHugging Face ็ญ‰ๆ— ็Šถๆ€็Žฏๅขƒ๏ผ‰
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
class AsyncMongoDB:
"""MongoDB Atlas ๆŒไน…ๅŒ–ๅญ˜ๅ‚จ๏ผŒๆŽฅๅฃไธŽ AsyncJsonDB ๅฎŒๅ…จๅ…ผๅฎนใ€‚
ๆฏไธชๅฎžไพ‹ๅฏนๅบ”ไธ€ไธช MongoDB collection๏ผŒ
ๅฐ†ๆ•ดไธช list ไฝœไธบๅ•ไธชๆ–‡ๆกฃๅญ˜ๅ‚จ๏ผˆ_id="data", value=<list>๏ผ‰๏ผŒ
ไฟ่ฏๆœ€ๅฐๆ”นๅŠจๅณๅฏๆ›ฟๆข AsyncJsonDBใ€‚
"""
def __init__(self, collection_name: str, db, default_data: Any = None):
self._collection = db[collection_name]
self.default_data = default_data if default_data is not None else []
self._lock = asyncio.Lock()
self._data: Any = None
async def load(self) -> Any:
async with self._lock:
try:
doc = await self._collection.find_one({"_id": "data"})
self._data = doc["value"] if doc else self.default_data
except Exception as e:
log.error(f"MongoDB load failed for {self._collection.name}: {e}")
self._data = self.default_data
return self._data
async def save(self, data: Any):
async with self._lock:
self._data = data
try:
await self._collection.replace_one(
{"_id": "data"},
{"_id": "data", "value": data},
upsert=True,
)
except Exception as e:
log.error(f"MongoDB save failed for {self._collection.name}: {e}")
async def get(self) -> Any:
if self._data is None:
return await self.load()
return self._data
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ๅทฅๅŽ‚ๅ‡ฝๆ•ฐ๏ผšๆ นๆฎ้…็ฝฎ่‡ชๅŠจ้€‰ๆ‹ฉๅญ˜ๅ‚จๅŽ็ซฏ
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
_mongo_client = None
_mongo_db = None
async def init_mongo(uri: str, db_name: str, timeout_ms: int = 5000):
"""ๅˆๅง‹ๅŒ–ๅ…จๅฑ€ MongoDB ่ฟžๆŽฅ๏ผŒๅœจ lifespan ๅฏๅŠจๆ—ถ่ฐƒ็”จไธ€ๆฌกใ€‚"""
global _mongo_client, _mongo_db
from motor.motor_asyncio import AsyncIOMotorClient
_mongo_client = AsyncIOMotorClient(
uri,
serverSelectionTimeoutMS=timeout_ms,
connectTimeoutMS=timeout_ms,
)
_mongo_db = _mongo_client[db_name]
# ้ชŒ่ฏ่ฟžๆŽฅ
await _mongo_client.admin.command("ping")
log.info(f"MongoDB Atlas ๅทฒ่ฟžๆŽฅ โ†’ db={db_name}")
async def close_mongo():
"""ๅ…ณ้—ญ MongoDB ่ฟžๆŽฅ๏ผŒๅœจ lifespan ๅ…ณ้—ญๆ—ถ่ฐƒ็”จใ€‚"""
global _mongo_client, _mongo_db
if _mongo_client:
_mongo_client.close()
_mongo_client = None
_mongo_db = None
log.info("MongoDB ่ฟžๆŽฅๅทฒๅ…ณ้—ญ")
def get_mongo_db():
"""่ฟ”ๅ›žๅฝ“ๅ‰ MongoDB database ๅฎžไพ‹๏ผˆๅฏ่ƒฝไธบ None๏ผ‰ใ€‚"""
return _mongo_db
def create_db(collection_name: str, file_path: str, default_data: Any = None):
"""ๅทฅๅŽ‚ๅ‡ฝๆ•ฐ๏ผšๆœ‰ MongoDB ๆ—ถ่ฟ”ๅ›ž AsyncMongoDB๏ผŒๅฆๅˆ™ๅ›ž้€€ๅˆฐ AsyncJsonDBใ€‚"""
if _mongo_db is not None:
return AsyncMongoDB(collection_name, _mongo_db, default_data)
return AsyncJsonDB(file_path, default_data)