#!/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()