Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -4,8 +4,12 @@ import os
|
|
4 |
import subprocess
|
5 |
import sys
|
6 |
import shutil
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
-
# Try to import pyngrok, install if not available
|
9 |
try:
|
10 |
from pyngrok import ngrok, conf
|
11 |
PYNGROK_AVAILABLE = True
|
@@ -384,6 +388,148 @@ def start_server():
|
|
384 |
print(f"Failed to start server: {e}")
|
385 |
return False
|
386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 |
def cleanup_ngrok():
|
388 |
"""Clean up ngrok tunnels on exit"""
|
389 |
if PYNGROK_AVAILABLE:
|
@@ -393,7 +539,22 @@ def cleanup_ngrok():
|
|
393 |
except:
|
394 |
pass
|
395 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
397 |
print("=== Minecraft Server Setup ===")
|
398 |
|
399 |
try:
|
@@ -408,17 +569,40 @@ if __name__ == "__main__":
|
|
408 |
else:
|
409 |
print("\n=== Starting ngrok tunnel ===")
|
410 |
tunnel, tunnel_url = start_ngrok_tunnel()
|
411 |
-
if
|
|
|
|
|
|
|
|
|
|
|
412 |
print("Failed to start ngrok tunnel. Server will start but won't be accessible externally.")
|
413 |
|
414 |
print("\n=== Starting Minecraft Server ===")
|
415 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
|
417 |
except KeyboardInterrupt:
|
418 |
print("\n\nShutting down...")
|
419 |
-
|
420 |
sys.exit(0)
|
421 |
except Exception as e:
|
422 |
print(f"Unexpected error: {e}")
|
423 |
-
|
424 |
sys.exit(1)
|
|
|
4 |
import subprocess
|
5 |
import sys
|
6 |
import shutil
|
7 |
+
from mcstatus import JavaServer
|
8 |
+
import gradio as gr
|
9 |
+
import threading
|
10 |
+
import time
|
11 |
+
import signal
|
12 |
|
|
|
13 |
try:
|
14 |
from pyngrok import ngrok, conf
|
15 |
PYNGROK_AVAILABLE = True
|
|
|
388 |
print(f"Failed to start server: {e}")
|
389 |
return False
|
390 |
|
391 |
+
def start_server_background():
|
392 |
+
"""Start the Minecraft server in the background"""
|
393 |
+
global server_process
|
394 |
+
|
395 |
+
if not JAR_PATH.exists():
|
396 |
+
print("Server JAR not found. Run setup first.")
|
397 |
+
return False
|
398 |
+
|
399 |
+
# Get Java path
|
400 |
+
java_path = check_java()
|
401 |
+
if not java_path:
|
402 |
+
print("Java not found. Run setup first.")
|
403 |
+
return False
|
404 |
+
|
405 |
+
# Change to the data directory
|
406 |
+
original_cwd = os.getcwd()
|
407 |
+
os.chdir(DATA_DIR)
|
408 |
+
|
409 |
+
# Start the server
|
410 |
+
cmd = [
|
411 |
+
java_path,
|
412 |
+
"-Xmx2G", # Max heap size
|
413 |
+
"-Xms1G", # Initial heap size
|
414 |
+
"-jar", str(JAR_PATH),
|
415 |
+
"--nogui"
|
416 |
+
]
|
417 |
+
|
418 |
+
print(f"Starting Minecraft server in background with command: {' '.join(cmd)}")
|
419 |
+
print(f"Working directory: {DATA_DIR}")
|
420 |
+
|
421 |
+
try:
|
422 |
+
server_process = subprocess.Popen(
|
423 |
+
cmd,
|
424 |
+
stdout=subprocess.PIPE,
|
425 |
+
stderr=subprocess.STDOUT,
|
426 |
+
universal_newlines=True,
|
427 |
+
bufsize=1,
|
428 |
+
cwd=DATA_DIR
|
429 |
+
)
|
430 |
+
|
431 |
+
# Start a thread to monitor server output
|
432 |
+
def monitor_server():
|
433 |
+
for line in server_process.stdout:
|
434 |
+
print(f"[SERVER] {line.strip()}")
|
435 |
+
|
436 |
+
monitor_thread = threading.Thread(target=monitor_server, daemon=True)
|
437 |
+
monitor_thread.start()
|
438 |
+
|
439 |
+
# Wait a bit for server to start
|
440 |
+
time.sleep(5)
|
441 |
+
|
442 |
+
os.chdir(original_cwd)
|
443 |
+
print("✓ Minecraft server started in background")
|
444 |
+
return True
|
445 |
+
|
446 |
+
except Exception as e:
|
447 |
+
print(f"Failed to start server: {e}")
|
448 |
+
os.chdir(original_cwd)
|
449 |
+
return False
|
450 |
+
|
451 |
+
def get_server_status():
|
452 |
+
"""Get current server status for Gradio interface"""
|
453 |
+
global server_ip
|
454 |
+
|
455 |
+
if not server_ip:
|
456 |
+
return "Server IP not available", "N/A", "N/A", "N/A"
|
457 |
+
|
458 |
+
try:
|
459 |
+
server = JavaServer.lookup(server_ip)
|
460 |
+
status = server.status()
|
461 |
+
latency = server.ping()
|
462 |
+
|
463 |
+
status_text = f"**Server Status:** {status.players.online} player(s) online, latency: {round(status.latency)} ms"
|
464 |
+
version_text = f"**Server Version:** {status.version.name} ({status.version.protocol})"
|
465 |
+
description_text = f"**Server Description:** {status.description}"
|
466 |
+
|
467 |
+
if status.players.sample:
|
468 |
+
players_text = f"**Players:** {', '.join(player.name for player in status.players.sample)}"
|
469 |
+
else:
|
470 |
+
players_text = "**Players:** No players online"
|
471 |
+
|
472 |
+
return status_text, version_text, description_text, players_text
|
473 |
+
|
474 |
+
except Exception as e:
|
475 |
+
error_msg = f"**Error:** Could not connect to server - {str(e)}"
|
476 |
+
return error_msg, "N/A", "N/A", "N/A"
|
477 |
+
|
478 |
+
def create_gradio_interface():
|
479 |
+
"""Create and return the Gradio interface"""
|
480 |
+
global server_ip
|
481 |
+
|
482 |
+
with gr.Blocks(title="Minecraft Server Manager") as demo:
|
483 |
+
gr.Markdown("# Minecraft Server Status Monitor")
|
484 |
+
|
485 |
+
if server_ip:
|
486 |
+
gr.Markdown(f"**Server IP:** {server_ip}")
|
487 |
+
else:
|
488 |
+
gr.Markdown("**Server IP:** Not available yet")
|
489 |
+
|
490 |
+
# Initial status
|
491 |
+
try:
|
492 |
+
if server_ip:
|
493 |
+
initial_status = get_server_status()
|
494 |
+
else:
|
495 |
+
initial_status = ("Server starting...", "N/A", "N/A", "N/A")
|
496 |
+
except:
|
497 |
+
initial_status = ("Server not ready", "N/A", "N/A", "N/A")
|
498 |
+
|
499 |
+
status_markdown = gr.Markdown(initial_status[0])
|
500 |
+
version_markdown = gr.Markdown(initial_status[1])
|
501 |
+
description_markdown = gr.Markdown(initial_status[2])
|
502 |
+
players_markdown = gr.Markdown(initial_status[3])
|
503 |
+
|
504 |
+
btn = gr.Button("Refresh Status")
|
505 |
+
btn.click(
|
506 |
+
get_server_status,
|
507 |
+
outputs=[status_markdown, version_markdown, description_markdown, players_markdown]
|
508 |
+
)
|
509 |
+
|
510 |
+
# Auto-refresh every 30 seconds
|
511 |
+
demo.load(
|
512 |
+
get_server_status,
|
513 |
+
outputs=[status_markdown, version_markdown, description_markdown, players_markdown],
|
514 |
+
every=30
|
515 |
+
)
|
516 |
+
|
517 |
+
return demo
|
518 |
+
|
519 |
+
def stop_server():
|
520 |
+
"""Stop the Minecraft server"""
|
521 |
+
global server_process
|
522 |
+
|
523 |
+
if server_process:
|
524 |
+
print("Stopping Minecraft server...")
|
525 |
+
server_process.terminate()
|
526 |
+
try:
|
527 |
+
server_process.wait(timeout=10)
|
528 |
+
except subprocess.TimeoutExpired:
|
529 |
+
server_process.kill()
|
530 |
+
server_process = None
|
531 |
+
print("✓ Minecraft server stopped")
|
532 |
+
|
533 |
def cleanup_ngrok():
|
534 |
"""Clean up ngrok tunnels on exit"""
|
535 |
if PYNGROK_AVAILABLE:
|
|
|
539 |
except:
|
540 |
pass
|
541 |
|
542 |
+
def cleanup_all():
|
543 |
+
"""Clean up all resources"""
|
544 |
+
stop_server()
|
545 |
+
cleanup_ngrok()
|
546 |
+
|
547 |
+
def signal_handler(signum, frame):
|
548 |
+
"""Handle shutdown signals"""
|
549 |
+
print("\nReceived shutdown signal. Cleaning up...")
|
550 |
+
cleanup_all()
|
551 |
+
sys.exit(0)
|
552 |
+
|
553 |
if __name__ == "__main__":
|
554 |
+
# Register signal handlers
|
555 |
+
signal.signal(signal.SIGINT, signal_handler)
|
556 |
+
signal.signal(signal.SIGTERM, signal_handler)
|
557 |
+
|
558 |
print("=== Minecraft Server Setup ===")
|
559 |
|
560 |
try:
|
|
|
569 |
else:
|
570 |
print("\n=== Starting ngrok tunnel ===")
|
571 |
tunnel, tunnel_url = start_ngrok_tunnel()
|
572 |
+
if tunnel:
|
573 |
+
ngrok_tunnel = tunnel
|
574 |
+
# Extract IP from tunnel URL (format: tcp://x.tcp.ngrok.io:port)
|
575 |
+
server_ip = tunnel_url.replace('tcp://', '')
|
576 |
+
print(f"Server will be accessible at: {server_ip}")
|
577 |
+
else:
|
578 |
print("Failed to start ngrok tunnel. Server will start but won't be accessible externally.")
|
579 |
|
580 |
print("\n=== Starting Minecraft Server ===")
|
581 |
+
if not start_server_background():
|
582 |
+
print("Failed to start server.")
|
583 |
+
cleanup_all()
|
584 |
+
sys.exit(1)
|
585 |
+
|
586 |
+
# Wait a bit for server to fully start
|
587 |
+
print("Waiting for server to start...")
|
588 |
+
time.sleep(10)
|
589 |
+
|
590 |
+
print("\n=== Starting Gradio Interface ===")
|
591 |
+
demo = create_gradio_interface()
|
592 |
+
|
593 |
+
# Launch Gradio interface
|
594 |
+
demo.launch(
|
595 |
+
server_name="0.0.0.0",
|
596 |
+
server_port=7860,
|
597 |
+
share=False,
|
598 |
+
show_error=True
|
599 |
+
)
|
600 |
|
601 |
except KeyboardInterrupt:
|
602 |
print("\n\nShutting down...")
|
603 |
+
cleanup_all()
|
604 |
sys.exit(0)
|
605 |
except Exception as e:
|
606 |
print(f"Unexpected error: {e}")
|
607 |
+
cleanup_all()
|
608 |
sys.exit(1)
|