Spaces:
Paused
Paused
| import os | |
| import subprocess | |
| import threading | |
| import requests | |
| from fastapi import FastAPI | |
| from fastapi.responses import HTMLResponse | |
| import uvicorn | |
| app = FastAPI() | |
| MC_PATH = "/data/minecraft" | |
| PORT = 7860 | |
| MAX_RAM = "2G" | |
| MIN_RAM = "1G" | |
| SERVER_VERSION = "1.20.1" | |
| logs = [] | |
| mc_process = None | |
| def log(msg): | |
| print(msg) | |
| logs.append(msg) | |
| if len(logs) > 100: | |
| logs.pop(0) | |
| def setup(): | |
| os.makedirs(MC_PATH, exist_ok=True) | |
| with open(f"{MC_PATH}/eula.txt", "w") as f: | |
| f.write("eula=true\n") | |
| props = f"{MC_PATH}/server.properties" | |
| if not os.path.exists(props): | |
| with open(props, "w") as f: | |
| f.write( | |
| "online-mode=false\n" | |
| "server-port=25565\n" | |
| "motd=HF Fabric Server\n" | |
| ) | |
| def download_fabric(): | |
| jar = f"{MC_PATH}/fabric-server-launch.jar" | |
| if os.path.exists(jar): | |
| log("Fabric already exists") | |
| return | |
| log("Downloading Fabric...") | |
| loader = requests.get( | |
| "https://meta.fabricmc.net/v2/versions/loader" | |
| ).json()[0] | |
| loader_version = loader["loader"]["version"] | |
| installer_version = loader["installer"]["version"] | |
| installer_url = ( | |
| f"https://meta.fabricmc.net/v2/versions/installer/" | |
| f"{installer_version}" | |
| ) | |
| r = requests.get(installer_url) | |
| with open("/tmp/fabric-installer.jar", "wb") as f: | |
| f.write(r.content) | |
| cmd = [ | |
| "java", | |
| "-jar", | |
| "/tmp/fabric-installer.jar", | |
| "server", | |
| "-mcversion", | |
| SERVER_VERSION, | |
| "-loader", | |
| loader_version, | |
| "-downloadMinecraft" | |
| ] | |
| subprocess.run(cmd, cwd=MC_PATH) | |
| log("Fabric installed!") | |
| def start_mc(): | |
| global mc_process | |
| setup() | |
| download_fabric() | |
| jar = f"{MC_PATH}/fabric-server-launch.jar" | |
| cmd = [ | |
| "java", | |
| f"-Xms{MIN_RAM}", | |
| f"-Xmx{MAX_RAM}", | |
| "-jar", | |
| jar, | |
| "nogui" | |
| ] | |
| log("Starting Minecraft...") | |
| mc_process = subprocess.Popen( | |
| cmd, | |
| cwd=MC_PATH, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True | |
| ) | |
| def read_logs(): | |
| for line in mc_process.stdout: | |
| log(line.strip()) | |
| threading.Thread(target=read_logs, daemon=True).start() | |
| def start_playit(): | |
| log("Downloading Playit...") | |
| r = requests.get( | |
| "https://github.com/playit-cloud/playit-agent/releases/latest/download/playit-linux-amd64" | |
| ) | |
| with open("/tmp/playit", "wb") as f: | |
| f.write(r.content) | |
| os.chmod("/tmp/playit", 0o755) | |
| log("Starting Playit...") | |
| p = subprocess.Popen( | |
| ["/tmp/playit"], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True | |
| ) | |
| def read_playit(): | |
| for line in p.stdout: | |
| log("[PLAYIT] " + line.strip()) | |
| threading.Thread(target=read_playit, daemon=True).start() | |
| async def startup(): | |
| threading.Thread(target=start_mc, daemon=True).start() | |
| async def home(): | |
| text = "\n".join(logs[-50:]) | |
| return f""" | |
| <html> | |
| <body style="background:black;color:lime;font-family:monospace"> | |
| <h1>Minecraft Server</h1> | |
| <a href="/start-playit"> | |
| <button style="font-size:20px"> | |
| Start Playit | |
| </button> | |
| </a> | |
| <pre>{text}</pre> | |
| </body> | |
| </html> | |
| """ | |
| async def playit_route(): | |
| threading.Thread( | |
| target=start_playit, | |
| daemon=True | |
| ).start() | |
| return {"ok": True} | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=PORT) |