Dodanie mapy serwera i poprawka pobierania modów

- Dodaje #16 - Mape serwera w panelu (z pluginem squaremap)
- Poprawia pobieranie modów z Modrinth (dobra wersja i typ)
This commit is contained in:
Andus 2025-04-14 00:27:03 +02:00
parent ee189b7e72
commit efa85c5070
3 changed files with 174 additions and 34 deletions

View file

@ -5,7 +5,7 @@ import subprocess
import docker import docker
import requests import requests
from flask import Blueprint, jsonify, request, send_from_directory, abort from flask import Blueprint, jsonify, request, send_from_directory, abort, Response
from .auth import oidc from .auth import oidc
from .docker_utils import start_server, stop_server, restart_server, get_logs, delete_server, save_server_info, \ from .docker_utils import start_server, stop_server, restart_server, get_logs, delete_server, save_server_info, \
@ -296,6 +296,108 @@ def stats():
return jsonify({"error": "Container not found"}), 404 return jsonify({"error": "Container not found"}), 404
# Map
# TODO: OTHER PROXYS ARE JUST A TEMPORARY FIX!!! MAKE SOMETHING PERMANENT INSTEAD
@api.route('/map')
@oidc.require_login
def map_proxy():
username = oidc.user_getfield('preferred_username')
container_name = f"mc-{username}"
container_ip = client.containers.get(container_name).attrs['NetworkSettings']['IPAddress']
url = f"http://{container_ip}:8080"
try:
response = requests.get(url, params=request.args, timeout=5)
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'application/octet-stream')
)
except requests.exceptions.RequestException as e:
print(f"Error proxying map: {e}")
return jsonify({"message": "Mapa nie działa. Czy zainstalowałeś Squaremap?"}), 500
@api.route('/js/<path:filename>', methods=['GET'])
@oidc.require_login
def proxy_js(filename):
username = oidc.user_getfield('preferred_username')
container_name = f"mc-{username}"
container_ip = client.containers.get(container_name).attrs['NetworkSettings']['IPAddress']
url = f"http://{container_ip}:8080/js/{filename}"
try:
response = requests.get(url, timeout=5)
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'application/javascript')
)
except requests.exceptions.RequestException as e:
return jsonify({"message": "Błąd ładowania skryptu: " + str(e)}), 500
@api.route('/css/<path:filename>', methods=['GET'])
@oidc.require_login
def proxy_css(filename):
username = oidc.user_getfield('preferred_username')
container_name = f"mc-{username}"
container_ip = client.containers.get(container_name).attrs['NetworkSettings']['IPAddress']
url = f"http://{container_ip}:8080/css/{filename}"
try:
response = requests.get(url, timeout=5)
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'text/css')
)
except requests.exceptions.RequestException as e:
return jsonify({"message": "Błąd ładowania stylu: " + str(e)}), 500
@api.route('/tiles/<path:filename>', methods=['GET'])
@oidc.require_login
def proxy_tiles_settings(filename):
username = oidc.user_getfield('preferred_username')
container_name = f"mc-{username}"
container_ip = client.containers.get(container_name).attrs['NetworkSettings']['IPAddress']
url = f"http://{container_ip}:8080/tiles/{filename}"
try:
response = requests.get(url, timeout=5)
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'text/json')
)
except requests.exceptions.RequestException as e:
return jsonify({"message": "Błąd ładowania tiles: " + str(e)}), 500
@api.route('/images/<path:filename>', methods=['GET'])
@oidc.require_login
def proxy_images(filename):
username = oidc.user_getfield('preferred_username')
container_name = f"mc-{username}"
container_ip = client.containers.get(container_name).attrs['NetworkSettings']['IPAddress']
url = f"http://{container_ip}:8080/images/{filename}"
try:
response = requests.get(url, timeout=5)
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'image/png')
)
except requests.exceptions.RequestException as e:
return jsonify({"message": "Błąd ładowania tiles: " + str(e)}), 500
# Modrinth # Modrinth
@api.route('/modrinth/search') @api.route('/modrinth/search')
def modrinth_search(): def modrinth_search():
@ -327,19 +429,34 @@ def download_mod():
project_id = data['project_id'] project_id = data['project_id']
username = data['username'] username = data['username']
server_type = data['type'] server_type = data['type']
server_version = data['version']
version_response = requests.get(f"https://api.modrinth.com/v2/project/{project_id}/version") base_path = f"./servers/mc-{username}/{'plugins' if server_type == 'paper' else 'mods'}"
version_data = version_response.json()
file_url = version_data[0]['files'][0]['url'] downloaded = []
file_name = version_data[0]['files'][0]['filename']
folder = 'plugins' if server_type == 'paper' else 'mods' def download_project(pid, version_id=None):
file_path = f"./servers/mc-{username}/{folder}/{file_name}" if version_id:
version_data = requests.get(f"https://api.modrinth.com/v2/version/{version_id}").json()
else:
all_versions = requests.get(f"https://api.modrinth.com/v2/project/{pid}/version").json()
version_data = next((v for v in all_versions if server_version in v['game_versions'] and server_type in v['loaders']), None)
if not version_data:
return
with requests.get(file_url, stream=True) as r: file = version_data['files'][0]
file_path = f"{base_path}/{file['filename']}"
if file['filename'] not in downloaded:
with requests.get(file['url'], stream=True) as r:
with open(file_path, 'wb') as f: with open(file_path, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192): for chunk in r.iter_content(chunk_size=8192):
f.write(chunk) f.write(chunk)
downloaded.append(file['filename'])
return jsonify({"success": True, "file": file_name}) for dep in version_data.get('dependencies', []):
if dep.get('version_id'):
download_project(dep['project_id'], dep['version_id'])
download_project(project_id)
return jsonify({"success": True, "downloaded": downloaded})

View file

@ -33,11 +33,18 @@ function searchMods() {
} }
function installMod(projectId) { function installMod(projectId) {
const serverType = document.getElementById("server-type").value; fetch('/api/config')
.then(response => response.json())
.then(configData => {
console.log(configData);
if (configData.success) {
const serverType = configData.type;
const serverVersion = configData.version;
if (serverType && serverVersion) {
fetch('/api/modrinth/download', { fetch('/api/modrinth/download', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ project_id: projectId, username, type: serverType }) body: JSON.stringify({ project_id: projectId, username, type: serverType, version: serverVersion }),
}) })
.then(r => r.json()) .then(r => r.json())
.then(data => { .then(data => {
@ -48,4 +55,14 @@ function installMod(projectId) {
alert("Nie udało się zainstalować moda."); alert("Nie udało się zainstalować moda.");
} }
}); });
} else {
console.error('Server type or version not available');
}
} else {
console.error('Server config not found');
}
})
.catch(err => {
console.error('Error fetching server config:', err);
});
} }

View file

@ -6,12 +6,13 @@
<button class="tab-button" onclick="showTab('controls')">Sterowanie 🎛️</button> <button class="tab-button" onclick="showTab('controls')">Sterowanie 🎛️</button>
<button class="tab-button" onclick="showTab('console')">Konsola 📟</button> <button class="tab-button" onclick="showTab('console')">Konsola 📟</button>
<button class="tab-button" onclick="showTab('files')">Pliki 📁</button> <button class="tab-button" onclick="showTab('files')">Pliki 📁</button>
<button class="tab-button" onclick="showTab('config')">Konfiguracja 🛠️</button>
</div> </div>
<div class="tabs"> <div class="tabs">
<button class="tab-button" onclick="showTab('config')">Konfiguracja 🛠️</button> <button class="tab-button" onclick="showTab('map')">Mapa 🗺️</button>
<button class="tab-button" onclick="showTab('statistics')">Statystyki 📈</button>
<button class="tab-button" onclick="showTab('mods')">Mody/Pluginy 🧩</button> <button class="tab-button" onclick="showTab('mods')">Mody/Pluginy 🧩</button>
<button class="tab-button" onclick="showTab('statistics')">Statystyki 📈</button>
</div> </div>
<div class="tab-content"> <div class="tab-content">
@ -112,11 +113,9 @@
</form> </form>
</div> </div>
<div class="tab-panel" id="statistics"> <div class="tab-panel" id="map">
<div class="charts-row"> <h2>Mapa Serwera</h2>
<div class="chart-container"><canvas id="cpuChart"></canvas></div> <iframe src="/api/map" width="100%" height="500px"></iframe>
<div class="chart-container"><canvas id="ramChart"></canvas></div>
</div>
</div> </div>
<div class="tab-panel" id="mods"> <div class="tab-panel" id="mods">
@ -124,6 +123,13 @@
<input type="text" id="mod-search" placeholder="Wyszukaj mod/plugin..." oninput="searchMods()"> <input type="text" id="mod-search" placeholder="Wyszukaj mod/plugin..." oninput="searchMods()">
<div id="mod-results"></div> <div id="mod-results"></div>
</div> </div>
<div class="tab-panel" id="statistics">
<div class="charts-row">
<div class="chart-container"><canvas id="cpuChart"></canvas></div>
<div class="chart-container"><canvas id="ramChart"></canvas></div>
</div>
</div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>