2025-08-21 14:05:27 +08:00
|
|
|
import grpc
|
|
|
|
|
from typing import Dict
|
|
|
|
|
|
|
|
|
|
from .enums import CMVRErrorCode
|
|
|
|
|
from .biohead_client import BioHeadClient
|
2025-08-25 10:34:44 +08:00
|
|
|
from .camera_client import CameraClient
|
|
|
|
|
from .dexhand_client import DexHandClient
|
2025-08-21 14:05:27 +08:00
|
|
|
|
|
|
|
|
class CMVRGrpcClient:
|
|
|
|
|
"""CMVR gRPC 主客户端"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, server_address: str):
|
|
|
|
|
self.server_address = server_address
|
|
|
|
|
self.connected = False
|
|
|
|
|
|
|
|
|
|
# 创建 gRPC 通道
|
|
|
|
|
self.channel = grpc.insecure_channel(server_address)
|
|
|
|
|
|
|
|
|
|
# 初始化各服务的存根
|
|
|
|
|
self.generated = None # 推迟导入
|
|
|
|
|
self.biohead_stub = None
|
|
|
|
|
self.biohead_map: Dict[str, BioHeadClient] = {}
|
|
|
|
|
|
2025-08-25 10:34:44 +08:00
|
|
|
self.camera_stub = None
|
|
|
|
|
self.camera_map: Dict[str, CameraClient] = {}
|
|
|
|
|
|
|
|
|
|
self.dexhand_stub = None
|
|
|
|
|
self.dexhand_map: Dict[str, DexHandClient] = {}
|
|
|
|
|
|
2025-08-21 14:05:27 +08:00
|
|
|
# 检查连接状态
|
|
|
|
|
try:
|
|
|
|
|
grpc.channel_ready_future(self.channel).result(timeout=5)
|
|
|
|
|
self.connected = True
|
|
|
|
|
self._import_generated() # 在连接成功后才导入 generated
|
|
|
|
|
self.biohead_stub = self.generated.biohead_service_pb2_grpc.BioHeadServiceStub(self.channel)
|
2025-08-25 10:34:44 +08:00
|
|
|
|
|
|
|
|
self.camera_stub = self.generated.camera_service_pb2_grpc.CameraServiceStub(self.channel)
|
|
|
|
|
|
|
|
|
|
self.dexhand_stub = self.generated.dexhand_service_pb2_grpc.DexHandServiceStub(self.channel)
|
|
|
|
|
|
2025-08-21 14:05:27 +08:00
|
|
|
except grpc.FutureTimeoutError:
|
|
|
|
|
print(f"连接服务器超时: {server_address}")
|
|
|
|
|
self.connected = False
|
|
|
|
|
|
|
|
|
|
def _import_generated(self):
|
|
|
|
|
"""推迟导入 generated"""
|
|
|
|
|
if self.generated is None:
|
|
|
|
|
try:
|
|
|
|
|
# 从正确的路径导入生成的模块
|
|
|
|
|
from generated.cmvr.api import biohead_service_pb2_grpc
|
2025-08-25 10:34:44 +08:00
|
|
|
from generated.cmvr.api import camera_service_pb2_grpc
|
2025-08-21 14:05:27 +08:00
|
|
|
from generated.cmvr.api import common_pb2, biohead_command_pb2
|
2025-08-25 10:34:44 +08:00
|
|
|
from generated.cmvr.api import camera_command_pb2
|
|
|
|
|
from generated.cmvr.api import dexhand_command_pb2
|
|
|
|
|
from generated.cmvr.api import dexhand_service_pb2_grpc
|
2025-08-21 14:05:27 +08:00
|
|
|
self.generated = type('GeneratedModules', (), {
|
|
|
|
|
'biohead_service_pb2_grpc': biohead_service_pb2_grpc,
|
|
|
|
|
'common_pb2': common_pb2,
|
2025-08-25 10:34:44 +08:00
|
|
|
'biohead_command_pb2': biohead_command_pb2,
|
|
|
|
|
'camera_service_pb2_grpc': camera_service_pb2_grpc,
|
|
|
|
|
'camera_command_pb2': camera_command_pb2,
|
|
|
|
|
'dexhand_service_pb2_grpc': dexhand_service_pb2_grpc,
|
|
|
|
|
'dexhand_command_pb2': dexhand_command_pb2
|
2025-08-21 14:05:27 +08:00
|
|
|
})
|
2025-08-25 10:34:44 +08:00
|
|
|
|
2025-08-21 14:05:27 +08:00
|
|
|
except ImportError as e:
|
|
|
|
|
print(f"导入生成的模块失败: {e}")
|
|
|
|
|
print("请确保已生成 protobuf 代码")
|
|
|
|
|
raise
|
|
|
|
|
return self.generated
|
|
|
|
|
|
|
|
|
|
def is_connected(self) -> bool:
|
|
|
|
|
"""检查连接状态"""
|
|
|
|
|
return self.connected
|
|
|
|
|
|
|
|
|
|
def get_biohead(self, device_id: str) -> BioHeadClient:
|
|
|
|
|
"""获取仿生头客户端"""
|
|
|
|
|
if device_id not in self.biohead_map:
|
|
|
|
|
self.biohead_map[device_id] = BioHeadClient(device_id, self.biohead_stub)
|
|
|
|
|
return self.biohead_map[device_id]
|
2025-08-25 10:34:44 +08:00
|
|
|
def get_camera(self, device_id: str) -> CameraClient:
|
|
|
|
|
"""获取摄像头客户端"""
|
|
|
|
|
if device_id not in self.camera_map:
|
|
|
|
|
self.camera_map[device_id] = CameraClient(device_id, self.camera_stub)
|
|
|
|
|
return self.camera_map[device_id]
|
|
|
|
|
|
|
|
|
|
def get_dexhand(self, device_id: str) -> DexHandClient:
|
|
|
|
|
if device_id not in self.dexhand_map:
|
|
|
|
|
self.dexhand_map[device_id] = DexHandClient(device_id, self.dexhand_stub)
|
|
|
|
|
return self.dexhand_map[device_id]
|
2025-08-21 14:05:27 +08:00
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
|
"""关闭所有连接"""
|
|
|
|
|
# 关闭所有流式连接
|
|
|
|
|
for biohead in self.biohead_map.values():
|
|
|
|
|
biohead.close()
|
|
|
|
|
|
|
|
|
|
# 关闭 gRPC 通道
|
|
|
|
|
self.channel.close()
|
|
|
|
|
|
|
|
|
|
# 清空所有映射
|
|
|
|
|
self.biohead_map.clear()
|
|
|
|
|
|
|
|
|
|
self.connected = False
|