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.
343 lines
12 KiB
343 lines
12 KiB
"""
|
|
设备管理API
|
|
提供统一的设备管理接口,包括设备操作控制、ADB管理等功能
|
|
注意:设备注册、更新、注销等操作是自动化的,不对外提供API
|
|
"""
|
|
from fastapi import APIRouter, HTTPException, status
|
|
from typing import List, Optional, Dict, Any
|
|
from app.services.device_service import device_service
|
|
from app.schemas.adb import (
|
|
ClickRequest, InputRequest, ScreenshotResponse,
|
|
InstallRequest, InstallResponse, LogcatRequest, LogcatResponse
|
|
)
|
|
from app.utils.structured_log import get_structured_logger, LogLevel
|
|
|
|
logger = get_structured_logger(__name__, LogLevel.INFO)
|
|
|
|
router = APIRouter()
|
|
|
|
@router.get("/devices", summary="获取所有设备")
|
|
async def get_all_devices():
|
|
"""获取所有设备(包括注册和自动发现的)"""
|
|
try:
|
|
devices = await device_service.get_all_devices()
|
|
return {
|
|
"success": True,
|
|
"message": f"获取到 {len(devices)} 个设备",
|
|
"data": {
|
|
"devices": devices,
|
|
"total": len(devices)
|
|
}
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取所有设备失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取设备列表失败: {str(e)}"
|
|
)
|
|
|
|
@router.get("/devices/{device_id}", summary="获取设备信息")
|
|
async def get_device_info(device_id: str):
|
|
"""获取指定设备的详细信息"""
|
|
try:
|
|
device_info = await device_service.get_device_info(device_id)
|
|
if not device_info:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"设备 {device_id} 不存在"
|
|
)
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "获取设备信息成功",
|
|
"data": device_info
|
|
}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"获取设备信息失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取设备信息失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/devices/{device_id}/click", summary="执行点击操作")
|
|
async def click_device(device_id: str, click_request: ClickRequest):
|
|
"""在指定设备上执行点击操作"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="click",
|
|
x=click_request.x,
|
|
y=click_request.y,
|
|
duration=click_request.duration
|
|
)
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "点击操作执行成功",
|
|
"data": result
|
|
}
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"点击操作参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"点击操作失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"点击操作失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/devices/{device_id}/input", summary="输入文本")
|
|
async def input_text(device_id: str, input_request: InputRequest):
|
|
"""在指定设备上输入文本"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="input_text",
|
|
text=input_request.text,
|
|
clear_first=input_request.clear_first
|
|
)
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "文本输入成功",
|
|
"data": result
|
|
}
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"文本输入参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"文本输入失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"文本输入失败: {str(e)}"
|
|
)
|
|
|
|
@router.get("/devices/{device_id}/screenshot", response_model=ScreenshotResponse, summary="获取屏幕截图")
|
|
async def get_screenshot(device_id: str):
|
|
"""获取指定设备的屏幕截图"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="screenshot"
|
|
)
|
|
|
|
return result
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"截图操作参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"截图操作失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"截图操作失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/devices/{device_id}/install", response_model=InstallResponse, summary="安装APK")
|
|
async def install_apk(device_id: str, install_request: InstallRequest):
|
|
"""在指定设备上安装APK"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="install_apk",
|
|
apk_path=install_request.apk_path,
|
|
package_name=install_request.package_name
|
|
)
|
|
|
|
return result
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"安装APK参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"安装APK失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"安装APK失败: {str(e)}"
|
|
)
|
|
|
|
@router.get("/devices/{device_id}/logcat", response_model=LogcatResponse, summary="获取日志")
|
|
async def get_logcat(
|
|
device_id: str,
|
|
package_name: Optional[str] = None,
|
|
level: str = "V",
|
|
max_lines: int = 100
|
|
):
|
|
"""获取指定设备的日志"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="get_logcat",
|
|
package_name=package_name,
|
|
level=level,
|
|
max_lines=max_lines
|
|
)
|
|
|
|
return result
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"获取日志参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"获取日志失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取日志失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/devices/{device_id}/shell", summary="执行Shell命令")
|
|
async def execute_shell_command(device_id: str, command: str, timeout: int = 30):
|
|
"""在指定设备上执行Shell命令"""
|
|
try:
|
|
result = await device_service.execute_operation(
|
|
device_id=device_id,
|
|
operation="execute_shell_command",
|
|
command=command,
|
|
timeout=timeout
|
|
)
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "Shell命令执行成功",
|
|
"data": result
|
|
}
|
|
|
|
except ValueError as e:
|
|
logger.warning(f"Shell命令参数错误: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Shell命令执行失败: {device_id}, 错误: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Shell命令执行失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/devices/cache/clear", summary="清除设备缓存")
|
|
async def clear_device_cache():
|
|
"""清除设备来源缓存"""
|
|
try:
|
|
device_service.clear_cache()
|
|
return {
|
|
"success": True,
|
|
"message": "设备缓存清除成功"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"清除设备缓存失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"清除设备缓存失败: {str(e)}"
|
|
)
|
|
|
|
# ==================== ADB管理功能 ====================
|
|
|
|
@router.get("/adb/server/info", summary="获取ADB服务器信息")
|
|
async def get_adb_server_info():
|
|
"""获取ADB服务器信息"""
|
|
try:
|
|
result = await device_service.auto_discovery_adb_service.get_server_info()
|
|
return {
|
|
"success": True,
|
|
"message": "获取ADB服务器信息成功",
|
|
"data": result
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取ADB服务器信息失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取ADB服务器信息失败: {str(e)}"
|
|
)
|
|
|
|
@router.get("/adb/devices", summary="获取ADB设备列表")
|
|
async def get_adb_devices(status: Optional[str] = None):
|
|
"""获取ADB设备列表"""
|
|
try:
|
|
status_filter = [status] if status else None
|
|
result = await device_service.auto_discovery_adb_service.list_devices(status_filter)
|
|
return {
|
|
"success": True,
|
|
"message": f"获取到 {len(result)} 个ADB设备",
|
|
"data": result
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取ADB设备列表失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取ADB设备列表失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/adb/monitor/start", summary="启动ADB设备监控")
|
|
async def start_adb_monitoring():
|
|
"""启动ADB设备监控"""
|
|
try:
|
|
await device_service.auto_discovery_adb_service.start_monitoring()
|
|
return {
|
|
"success": True,
|
|
"message": "ADB设备监控启动成功"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"启动ADB设备监控失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"启动ADB设备监控失败: {str(e)}"
|
|
)
|
|
|
|
@router.post("/adb/monitor/stop", summary="停止ADB设备监控")
|
|
async def stop_adb_monitoring():
|
|
"""停止ADB设备监控"""
|
|
try:
|
|
await device_service.auto_discovery_adb_service.stop_monitoring()
|
|
return {
|
|
"success": True,
|
|
"message": "ADB设备监控停止成功"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"停止ADB设备监控失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"停止ADB设备监控失败: {str(e)}"
|
|
)
|
|
|
|
@router.get("/adb/monitor/status", summary="获取ADB监控状态")
|
|
async def get_adb_monitoring_status():
|
|
"""获取ADB监控状态"""
|
|
try:
|
|
monitoring_started = device_service.auto_discovery_adb_service._monitoring_started
|
|
task_done = device_service.auto_discovery_adb_service._device_monitor_task.done() if device_service.auto_discovery_adb_service._device_monitor_task else True
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "获取ADB监控状态成功",
|
|
"data": {
|
|
"monitoring_started": monitoring_started,
|
|
"task_done": task_done,
|
|
"status": "running" if monitoring_started and not task_done else "stopped"
|
|
}
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取ADB监控状态失败: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"获取ADB监控状态失败: {str(e)}"
|
|
)
|