You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
5.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
SDK连接管理器 - 保持SDK登录状态避免重复登录
"""
import threading
import time
from typing import Optional, Dict, Any
from app.services.amazing_data_adapter import AmazingDataAdapter
from app.models.config import SDKConfig
from app.db.session import SessionLocal
import logging
logger = logging.getLogger(__name__)
class SDKConnectionManager:
"""
SDK连接管理器
- 保持SDK登录状态避免重复登录
- 登录成功后,在释放前所有请求都不用重复登录
- 支持多配置管理
"""
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._connections: Dict[int, AmazingDataAdapter] = {}
cls._instance._connection_locks: Dict[int, threading.Lock] = {}
cls._instance._last_activity: Dict[int, float] = {}
return cls._instance
def get_connection(self, config_id: int) -> Optional[AmazingDataAdapter]:
"""
获取SDK连接
Args:
config_id: 配置ID
Returns:
AmazingDataAdapter实例如果连接失败返回None
"""
if config_id not in self._connection_locks:
self._connection_locks[config_id] = threading.Lock()
with self._connection_locks[config_id]:
if config_id in self._connections:
adapter = self._connections[config_id]
if adapter.is_connected():
self._last_activity[config_id] = time.time()
return adapter
else:
del self._connections[config_id]
db = SessionLocal()
try:
config = db.query(SDKConfig).filter(SDKConfig.id == config_id).first()
if not config:
logger.warning(f"SDK配置不存在: {config_id}")
return None
adapter = AmazingDataAdapter({
"username": config.username,
"password": config.password,
"host": config.host,
"port": config.port,
"local_path": config.local_path or "./amazing_data_cache/"
})
if adapter.connect():
self._connections[config_id] = adapter
self._last_activity[config_id] = time.time()
logger.info(f"SDK连接成功: config_id={config_id}")
return adapter
else:
logger.warning(f"SDK连接失败: config_id={config_id}")
return None
finally:
db.close()
def release_connection(self, config_id: int):
"""
释放SDK连接
Args:
config_id: 配置ID
"""
if config_id not in self._connection_locks:
return
with self._connection_locks[config_id]:
if config_id in self._connections:
adapter = self._connections[config_id]
try:
adapter.disconnect()
logger.info(f"SDK连接已释放: config_id={config_id}")
except Exception as e:
logger.warning(f"释放SDK连接时出错: {e}")
del self._connections[config_id]
if config_id in self._last_activity:
del self._last_activity[config_id]
def get_default_connection(self) -> Optional[AmazingDataAdapter]:
"""
获取默认SDK连接
Returns:
AmazingDataAdapter实例
"""
db = SessionLocal()
try:
config = db.query(SDKConfig).filter(SDKConfig.is_default == True).first()
if not config:
config = db.query(SDKConfig).first()
if config:
return self.get_connection(config.id)
return None
finally:
db.close()
def release_all(self):
"""释放所有SDK连接"""
for config_id in list(self._connections.keys()):
self.release_connection(config_id)
def get_status(self, config_id: int) -> Dict[str, Any]:
"""
获取连接状态
Args:
config_id: 配置ID
Returns:
状态信息
"""
if config_id in self._connections:
adapter = self._connections[config_id]
return {
"connected": adapter.is_connected(),
"last_activity": self._last_activity.get(config_id, 0),
"config_id": config_id
}
return {
"connected": False,
"last_activity": 0,
"config_id": config_id
}
sdk_manager = SDKConnectionManager()