import os import sys import subprocess import time import signal import atexit import threading import logging import uvicorn from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(name)s: %(message)s') log = logging.getLogger(__name__) # Try to import markdown, but provide a fallback if it's not available try: import markdown import markdown.extensions.fenced_code import markdown.extensions.tables MARKDOWN_AVAILABLE = True except ImportError: MARKDOWN_AVAILABLE = False log.warning("markdown package not available. Will serve raw markdown files.") # Create the FastAPI app app = FastAPI(title="Markdown Server", docs_url=None, redoc_url=None) # Define the HTML template for rendering markdown HTML_TEMPLATE = """ {title} {content} """ # Function to read and convert markdown to HTML def render_markdown(file_path, title): try: with open(file_path, 'r', encoding='utf-8') as f: md_content = f.read() if MARKDOWN_AVAILABLE: # Convert markdown to HTML with extensions html_content = markdown.markdown( md_content, extensions=[ 'markdown.extensions.fenced_code', 'markdown.extensions.tables', 'markdown.extensions.toc' ] ) else: # Simple fallback if markdown package is not available # Just wrap the content in
 tags to preserve formatting
            html_content = f"
{md_content}
" # Insert the HTML content into the template return HTML_TEMPLATE.format(title=title, content=html_content) except Exception as e: return HTML_TEMPLATE.format( title="Error", content=f"

Error

Failed to render markdown: {str(e)}

" ) # Routes for TOS and Privacy Policy @app.get("/tos", response_class=HTMLResponse) async def get_tos(request: Request): return render_markdown("TOS.md", "Terms of Service") @app.get("/privacy", response_class=HTMLResponse) async def get_privacy(request: Request): return render_markdown("PRIVACY_POLICY.md", "Privacy Policy") # Root route that redirects to TOS @app.get("/", response_class=HTMLResponse) async def root(request: Request): return """ Bot Legal Documents

Discord Bot Legal Documents

Please review our Terms of Service and Privacy Policy.

""" # Function to start the server in a thread def start_markdown_server_in_thread(host="0.0.0.0", port=5006): """Start the markdown server in a separate thread.""" log.info(f"Starting markdown server on {host}:{port}...") def run_server(): try: uvicorn.run(app, host=host, port=port) except Exception as e: log.exception(f"Error running markdown server: {e}") # Start the server in a daemon thread server_thread = threading.Thread(target=run_server, daemon=True) server_thread.start() log.info(f"Markdown server thread started. TOS available at: http://{host}:{port}/tos") return server_thread def start_server(): """Start the markdown server as a background process (legacy method).""" print("Starting markdown server on port 5006...") # Get the directory of this script script_dir = os.path.dirname(os.path.abspath(__file__)) # Start the server as a subprocess server_process = subprocess.Popen( [sys.executable, os.path.join(script_dir, "markdown_server.py")], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True ) # Register a function to terminate the server when this script exits def cleanup(): if server_process.poll() is None: # If process is still running print("Stopping markdown server...") server_process.terminate() try: server_process.wait(timeout=5) except subprocess.TimeoutExpired: print("Server didn't terminate gracefully, forcing...") server_process.kill() atexit.register(cleanup) # Handle signals for sig in (signal.SIGINT, signal.SIGTERM): signal.signal(sig, lambda signum, frame: sys.exit(0)) # Wait a moment for the server to start time.sleep(2) # Check if the server started successfully if server_process.poll() is not None: print("Failed to start server. Exit code:", server_process.returncode) output, _ = server_process.communicate() print("Server output:", output) return False print(f"Markdown server running on http://localhost:5006") print("TOS available at: http://localhost:5006/tos") print("Privacy Policy available at: http://localhost:5006/privacy") return True def run_as_daemon(): """Run the server as a daemon process.""" if start_server(): # Keep the script running to maintain the server try: while True: time.sleep(60) # Sleep to reduce CPU usage except KeyboardInterrupt: print("Received keyboard interrupt. Shutting down...") sys.exit(0) if __name__ == "__main__": # If run directly, start the server in the main thread log.info("Starting markdown server on port 5006...") uvicorn.run(app, host="0.0.0.0", port=5006)