Skip to main content
Glama
rhino_client.py6.88 kB
""" Rhino Client - Client for communicating with Rhino via socket connection. This module implements a client that connects to the Rhino Bridge socket server and provides methods to send commands and receive responses. Version: 1.0 (2025-03-13) """ from typing import Dict, Any, Optional, List, Tuple, Union, TypedDict import socket import json import time import threading from dataclasses import dataclass class Point3d(TypedDict): """Type definition for a 3D point with x, y, z coordinates.""" x: float y: float z: float class RhinoClient: """Client for communicating with Rhino via socket connection. This class provides methods to connect to the Rhino Bridge socket server, send commands, and receive responses. Attributes: host: The hostname or IP address of the Rhino Bridge server port: The port number of the Rhino Bridge server socket: The socket connection to the Rhino Bridge server connected: Whether the client is currently connected to the server """ def __init__(self, host: str = '127.0.0.1', port: int = 8888): """Initialize the Rhino client. Args: host: The hostname or IP address of the Rhino Bridge server port: The port number of the Rhino Bridge server """ self.host = host self.port = port self.socket: Optional[socket.socket] = None self.connected = False def connect(self) -> bool: """Connect to the Rhino Bridge server. Returns: True if connected successfully, False otherwise Raises: ConnectionError: If failed to connect to the server """ try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.connect((self.host, self.port)) self.connected = True print(f"Connected to Rhino Bridge at {self.host}:{self.port}") return True except ConnectionRefusedError: self.connected = False raise ConnectionError( f"Failed to connect to Rhino Bridge at {self.host}:{self.port}. " "Make sure Rhino is running and the Bridge server is started." ) except Exception as e: self.connected = False raise ConnectionError(f"Connection error: {str(e)}") def disconnect(self) -> None: """Disconnect from the Rhino Bridge server. Returns: None """ if self.socket: self.socket.close() self.socket = None self.connected = False print("Disconnected from Rhino Bridge") def send_command(self, cmd_type: str, data: Dict[str, Any] = None) -> Dict[str, Any]: """Send a command to the Rhino Bridge server. Args: cmd_type: The type of command to send data: The data to send with the command Returns: The response from the server as a dictionary Raises: ConnectionError: If not connected to the server RuntimeError: If failed to send command or receive response """ if not self.connected or not self.socket: raise ConnectionError("Not connected to Rhino Bridge") if data is None: data = {} try: # Prepare the command command = { 'type': cmd_type, 'data': data } # Send the command self.socket.sendall(json.dumps(command).encode('utf-8')) # Receive the response response_data = self.socket.recv(4096) if not response_data: raise RuntimeError("No response from server") # Parse the response response = json.loads(response_data.decode('utf-8')) return response except Exception as e: raise RuntimeError(f"Command error: {str(e)}") def ping(self) -> Dict[str, Any]: """Ping the Rhino Bridge server to check connection. Returns: Server information including version and status Raises: ConnectionError: If not connected to the server """ return self.send_command('ping') def create_curve(self, points: List[Point3d]) -> Dict[str, Any]: """Create a NURBS curve in Rhino. Args: points: List of points (each a dict with x, y, z keys) Returns: Response from the server including curve ID if successful Raises: ValueError: If points list is invalid ConnectionError: If not connected to the server """ if not points or len(points) < 2: raise ValueError("At least 2 points are required to create a curve") return self.send_command('create_curve', {'points': points}) def refresh_view(self) -> Dict[str, Any]: """Refresh the Rhino viewport. Returns: Response from the server Raises: ConnectionError: If not connected to the server """ return self.send_command('refresh_view') def run_script(self, script: str) -> Dict[str, Any]: """Run a Python script in Rhino's Python context. Args: script: The Python script to run Returns: Response from the server including script result Raises: ValueError: If script is empty ConnectionError: If not connected to the server """ if not script: raise ValueError("Script cannot be empty") return self.send_command('run_script', {'script': script}) def test_connection(host: str = '127.0.0.1', port: int = 8888) -> bool: """Test the connection to the Rhino Bridge server. Args: host: The hostname or IP address of the Rhino Bridge server port: The port number of the Rhino Bridge server Returns: True if connected successfully, False otherwise """ client = RhinoClient(host, port) try: client.connect() response = client.ping() print(f"Connection successful! Server info:") for key, value in response.get('data', {}).items(): print(f" {key}: {value}") return True except Exception as e: print(f"Connection test failed: {str(e)}") return False finally: client.disconnect() if __name__ == "__main__": # Simple test when run directly test_connection()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/a01110946/RhinoMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server