Spaces:
Build error
Build error
| #!/usr/bin/env python3 | |
| """ | |
| Coral Server Python Wrapper | |
| Starts and manages the coral-server on port 5555 | |
| """ | |
| import os | |
| import sys | |
| import subprocess | |
| import signal | |
| import time | |
| import logging | |
| from threading import Thread | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | |
| ) | |
| logger = logging.getLogger('coral-wrapper') | |
| class CoralServerWrapper: | |
| def __init__(self, port=5555, jar_path='coral-server.jar'): | |
| self.port = int(os.environ.get('CORAL_PORT', port)) | |
| self.jar_path = jar_path | |
| self.process = None | |
| self.running = False | |
| def check_java_version(self): | |
| """Verify Java version is > 17""" | |
| try: | |
| result = subprocess.run( | |
| ['java', '-version'], | |
| capture_output=True, | |
| text=True | |
| ) | |
| version_info = result.stderr or result.stdout | |
| logger.info(f"Java version: {version_info.split()[2].strip('\"')}") | |
| # Extract major version | |
| version_str = version_info.split()[2].strip('"') | |
| major_version = int(version_str.split('.')[0]) | |
| if major_version < 17: | |
| logger.error(f"Java version {major_version} is < 17. Please upgrade.") | |
| return False | |
| return True | |
| except Exception as e: | |
| logger.error(f"Error checking Java version: {e}") | |
| return False | |
| def start_server(self): | |
| """Start the coral-server""" | |
| if not self.check_java_version(): | |
| sys.exit(1) | |
| try: | |
| # Java command to run coral-server | |
| java_cmd = [ | |
| 'java', | |
| '-Xmx512m', | |
| '-Xms256m', | |
| '-XX:+UseContainerSupport', | |
| '-XX:MaxRAMPercentage=75.0', | |
| '-jar', | |
| self.jar_path, | |
| '--sse-server-ktor', | |
| str(self.port) | |
| ] | |
| logger.info(f"Starting coral-server on port {self.port}...") | |
| logger.info(f"Command: {' '.join(java_cmd)}") | |
| # Start the process | |
| self.process = subprocess.Popen( | |
| java_cmd, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| universal_newlines=True, | |
| bufsize=1 | |
| ) | |
| self.running = True | |
| # Start thread to monitor output | |
| output_thread = Thread(target=self.monitor_output) | |
| output_thread.daemon = True | |
| output_thread.start() | |
| # Wait a moment to ensure server starts | |
| time.sleep(3) | |
| if self.process.poll() is None: | |
| logger.info(f"β Coral-server started successfully on port {self.port}") | |
| logger.info(f" Server URL: http://localhost:{self.port}") | |
| else: | |
| logger.error("Server failed to start") | |
| self.running = False | |
| sys.exit(1) | |
| except FileNotFoundError: | |
| logger.error(f"JAR file not found: {self.jar_path}") | |
| sys.exit(1) | |
| except Exception as e: | |
| logger.error(f"Error starting server: {e}") | |
| sys.exit(1) | |
| def monitor_output(self): | |
| """Monitor and log server output""" | |
| try: | |
| for line in iter(self.process.stdout.readline, ''): | |
| if line: | |
| logger.info(f"[coral-server] {line.strip()}") | |
| if not self.running: | |
| break | |
| except Exception as e: | |
| logger.error(f"Error monitoring output: {e}") | |
| def stop_server(self): | |
| """Stop the coral-server gracefully""" | |
| if self.process and self.running: | |
| logger.info("Stopping coral-server...") | |
| self.running = False | |
| # Send SIGTERM for graceful shutdown | |
| self.process.terminate() | |
| # Wait for process to end (max 10 seconds) | |
| try: | |
| self.process.wait(timeout=10) | |
| logger.info("β Coral-server stopped gracefully") | |
| except subprocess.TimeoutExpired: | |
| logger.warning("Force killing coral-server...") | |
| self.process.kill() | |
| self.process.wait() | |
| logger.info("β Coral-server force stopped") | |
| def restart_server(self): | |
| """Restart the coral-server""" | |
| logger.info("Restarting coral-server...") | |
| self.stop_server() | |
| time.sleep(2) | |
| self.start_server() | |
| def health_check(self): | |
| """Check if server is healthy""" | |
| if self.process and self.process.poll() is None: | |
| return True | |
| return False | |
| def run(self): | |
| """Main run method - starts server and handles signals""" | |
| # Setup signal handlers | |
| signal.signal(signal.SIGTERM, self.signal_handler) | |
| signal.signal(signal.SIGINT, self.signal_handler) | |
| # Start the server | |
| self.start_server() | |
| # Keep running and monitor health | |
| try: | |
| while self.running: | |
| time.sleep(5) | |
| if not self.health_check(): | |
| logger.error("Server health check failed!") | |
| logger.info("Attempting restart...") | |
| self.restart_server() | |
| except KeyboardInterrupt: | |
| logger.info("Received interrupt signal") | |
| finally: | |
| self.stop_server() | |
| def signal_handler(self, signum, frame): | |
| """Handle shutdown signals""" | |
| logger.info(f"Received signal {signum}") | |
| self.running = False | |
| def main(): | |
| """Main entry point""" | |
| logger.info("="*50) | |
| logger.info("Coral Server Python Wrapper") | |
| logger.info("="*50) | |
| # Get configuration from environment | |
| port = os.environ.get('CORAL_PORT', 5555) | |
| jar_path = os.environ.get('CORAL_JAR_PATH', 'coral-server.jar') | |
| # Create and run wrapper | |
| wrapper = CoralServerWrapper(port=port, jar_path=jar_path) | |
| wrapper.run() | |
| if __name__ == "__main__": | |
| main() |