- Improvements to EntitlementsDomain & Services - Prechecks in Document domain - Add audit information to LicenseUsage
153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
import webview
|
|
import threading
|
|
import time
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
import signal
|
|
import requests
|
|
import atexit
|
|
from eveai_client.platform.app import create_app
|
|
|
|
|
|
class EveAIClient:
|
|
"""Main client class that orchestrates all platform components."""
|
|
|
|
def __init__(self):
|
|
"""Initialize the EveAI client."""
|
|
self.port = 7001 # Default port
|
|
self.host = "127.0.0.1" # Only listen on localhost for security
|
|
self.app = create_app()
|
|
self.window = None
|
|
self.server_process = None
|
|
|
|
# Register cleanup at exit to ensure server is terminated
|
|
atexit.register(self.cleanup)
|
|
|
|
def _run_server(self):
|
|
"""Run Gunicorn server in a separate process."""
|
|
# Set environment variables if needed
|
|
env = os.environ.copy()
|
|
|
|
# Construct the command
|
|
cmd = [
|
|
"gunicorn",
|
|
"--workers", "1",
|
|
"--threads", "4",
|
|
"--bind", f"{self.host}:{self.port}",
|
|
"--timeout", "120",
|
|
"wsgi:app"
|
|
]
|
|
|
|
# Start the server as a subprocess
|
|
self.server_process = subprocess.Popen(
|
|
cmd,
|
|
env=env,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
universal_newlines=True
|
|
)
|
|
|
|
# Log server output
|
|
for line in iter(self.server_process.stdout.readline, ""):
|
|
print(f"[Server] {line.strip()}")
|
|
|
|
def _wait_for_server(self, timeout=30):
|
|
"""Wait for server to be ready by polling the endpoint."""
|
|
url = f"http://{self.host}:{self.port}/"
|
|
start_time = time.time()
|
|
|
|
while time.time() - start_time < timeout:
|
|
try:
|
|
response = requests.get(url, timeout=1)
|
|
if response.status_code == 200:
|
|
print(f"Server at {url} is ready!")
|
|
return True
|
|
except requests.RequestException:
|
|
print("Waiting for server to start...")
|
|
time.sleep(1)
|
|
|
|
print(f"Server did not start within {timeout} seconds")
|
|
return False
|
|
|
|
def _on_window_closing(self):
|
|
"""Handle window closing event."""
|
|
print("Window closing, shutting down server...")
|
|
self.cleanup()
|
|
return True # Allow window to close
|
|
|
|
def start(self):
|
|
"""Start the EveAI client application."""
|
|
# Start Gunicorn server in a separate thread
|
|
server_thread = threading.Thread(target=self._run_server)
|
|
server_thread.daemon = True
|
|
server_thread.start()
|
|
|
|
# Wait for the server to be ready to accept connections
|
|
if not self._wait_for_server():
|
|
print("Failed to start server, exiting...")
|
|
self.cleanup()
|
|
return
|
|
|
|
print(f"Starting webview with URL: http://{self.host}:{self.port}")
|
|
|
|
# Create and show the main window
|
|
self.window = webview.create_window(
|
|
self.app.config['WINDOW_TITLE'],
|
|
f'http://{self.host}:{self.port}',
|
|
width=self.app.config['WINDOW_WIDTH'],
|
|
height=self.app.config['WINDOW_HEIGHT'],
|
|
min_size=(self.app.config['WINDOW_MIN_WIDTH'], self.app.config['WINDOW_MIN_HEIGHT']),
|
|
)
|
|
|
|
# Set window close handler
|
|
self.window.events.closing += self._on_window_closing
|
|
|
|
print("Webview window created, starting webview...")
|
|
webview.start(debug=True)
|
|
print("Webview closed.")
|
|
|
|
def cleanup(self):
|
|
"""Clean up resources before shutdown."""
|
|
# Terminate the server process
|
|
if self.server_process:
|
|
print("Shutting down server...")
|
|
try:
|
|
# Only terminate the specific server process, not its parent
|
|
self.server_process.terminate()
|
|
|
|
# Wait for termination with timeout
|
|
try:
|
|
self.server_process.wait(timeout=5)
|
|
print("Server process terminated gracefully.")
|
|
except subprocess.TimeoutExpired:
|
|
print("Server didn't terminate gracefully, forcing kill...")
|
|
self.server_process.kill()
|
|
try:
|
|
self.server_process.wait(timeout=2)
|
|
print("Server process killed.")
|
|
except subprocess.TimeoutExpired:
|
|
print("Failed to kill server process.")
|
|
|
|
except Exception as e:
|
|
print(f"Error during server cleanup: {e}")
|
|
|
|
self.server_process = None
|
|
|
|
# Additional cleanup for any resources, cache, etc.
|
|
print("Cleanup complete.")
|
|
|
|
|
|
def main():
|
|
"""Application entry point."""
|
|
client = EveAIClient()
|
|
try:
|
|
client.start()
|
|
finally:
|
|
# This ensures cleanup runs even if start() raises an exception
|
|
client.cleanup()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|