cmvr-es-cli/cmvr/client.py

156 lines
6.6 KiB
Python
Raw Normal View History

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-26 17:19:45 +08:00
from .micphone_client import MicphoneClient
from .speaker_client import SpeakerClient
2025-10-21 09:33:47 +08:00
from .humanoid_robot import HumanoidRobotClient
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 通道
2025-10-21 09:33:47 +08:00
# 设置通道选项,增加最大接收和发送消息大小
max_message_size: int = 20 * 1024 * 1024
options = [
('grpc.max_send_message_length', max_message_size),
('grpc.max_receive_message_length', max_message_size),
]
self.channel = grpc.insecure_channel(server_address,options=options)
2025-08-21 14:05:27 +08:00
# 初始化各服务的存根
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-26 17:19:45 +08:00
self.micphone_stub = None
self.micphone_map: Dict[str, MicphoneClient] = {}
self.speaker_stub = None
self.speaker_map: Dict[str, SpeakerClient] = {}
2025-10-21 09:33:47 +08:00
self.humanoid_robot_stub = None
self.humanoid_robot_map: Dict[str, HumanoidRobotClient] = {}
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-26 17:19:45 +08:00
self.speaker_stub = self.generated.speaker_service_pb2_grpc.SpeakerServiceStub(self.channel)
self.micphone_stub = self.generated.microphone_service_pb2_grpc.MicPhoneServiceStub(self.channel)
2025-10-21 09:33:47 +08:00
self.humanoid_robot_stub = self.generated.humanoid_robot_sevice_pb2_grpc.HumanoidRobotServiceStub(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-26 17:19:45 +08:00
from generated.cmvr.api import speaker_command_pb2
from generated.cmvr.api import speaker_service_pb2_grpc
from generated.cmvr.api import microphone_command_pb2
from generated.cmvr.api import microphone_service_pb2_grpc
2025-10-21 09:33:47 +08:00
from generated.cmvr.api import humanoid_robot_command_pb2
from generated.cmvr.api import humanoid_robot_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,
2025-08-26 17:19:45 +08:00
'dexhand_command_pb2': dexhand_command_pb2,
'speaker_service_pb2_grpc': speaker_service_pb2_grpc,
'speaker_command_pb2': speaker_command_pb2,
'microphone_service_pb2_grpc': microphone_service_pb2_grpc,
2025-10-21 09:33:47 +08:00
'microphone_command_pb2': microphone_command_pb2,
'humanoid_robot_sevice_pb2_grpc': humanoid_robot_service_pb2_grpc,
'humanoid_robot_command_pb2': humanoid_robot_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
2025-08-26 17:19:45 +08:00
def get_speaker(self, device_id: str) -> SpeakerClient:
if device_id not in self.speaker_map:
self.speaker_map[device_id] = SpeakerClient(device_id, self.speaker_stub)
return self.speaker_map[device_id]
def get_micphone(self, device_id: str) -> MicphoneClient:
if device_id not in self.micphone_map:
self.micphone_map[device_id] = MicphoneClient(device_id, self.micphone_stub)
return self.micphone_map[device_id]
2025-10-21 09:33:47 +08:00
def get_humanoid_robot(self, device_id: str) -> HumanoidRobotClient:
if device_id not in self.micphone_map:
self.humanoid_robot_map[device_id] = HumanoidRobotClient(device_id, self.humanoid_robot_stub)
return self.humanoid_robot_map[device_id]
2025-08-26 17:19:45 +08:00
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