diff --git a/.gitignore b/.gitignore index 5d381cc..d417191 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +server/content +server/token.txt +updater/mods + # ---> Python # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/LICENSE b/LICENSE index a96e7b4..b11411c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 depish +Copyright (c) 2025 Leonov Artur Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/server/config.json b/server/config.json new file mode 100644 index 0000000..06ba52c --- /dev/null +++ b/server/config.json @@ -0,0 +1,3 @@ +{ + "content": "./content" +} \ No newline at end of file diff --git a/server/requirments.txt b/server/requirments.txt new file mode 100644 index 0000000..97dc7cd --- /dev/null +++ b/server/requirments.txt @@ -0,0 +1,2 @@ +fastapi +uvicorn diff --git a/server/server.py b/server/server.py new file mode 100644 index 0000000..27a8c80 --- /dev/null +++ b/server/server.py @@ -0,0 +1,54 @@ +from fastapi import FastAPI, Request, Header, Depends, Response, HTTPException +from fastapi.responses import FileResponse +import os +import json +from pathlib import Path + +config_path: Path = Path("./config.json") +config: dict = {} +with open(config_path, "r") as f: + config = json.load(f) + +CONTENT_PATH: Path = Path(config["content"]).resolve() +MODS_PATH: Path = CONTENT_PATH / "mods" +RESOURCEPACKS_PATH: Path = CONTENT_PATH / "resourcepacks" + +if not CONTENT_PATH.exists(): + CONTENT_PATH.mkdir(parents=True) + MODS_PATH.mkdir() + RESOURCEPACKS_PATH.mkdir() + +# Токен для доступа к сервису +TOKEN: str = None +TOKENFILE = Path(__file__).parent / "token.txt" +if not TOKENFILE.exists(): + TOKEN = os.urandom(48).hex() + + with open(TOKENFILE, "w") as f: + f.write(TOKEN) +else: + with open(TOKENFILE, "r") as f: + TOKEN = f.read() + +# Функция для проверки токена +def check_token(authorization: str = Header(...)): + if authorization != TOKEN: + raise HTTPException(status_code=401, detail="Неверный токен") + +app = FastAPI() + +@app.get("/mods/files") +async def get_files(): + # Получаем список всех файлов в указанной директории + files = os.listdir(str(MODS_PATH)) + return {"files": files} + + +@app.get("/mods/download/{filename}") +async def download_file(filename: str): + file_path: Path = MODS_PATH / filename + + if not file_path.exists(): + return {"error": f"Файл {filename} не найден"} + + return FileResponse(path=file_path, filename=str(filename), media_type="application/octet-stream") \ No newline at end of file diff --git a/server/start-server.sh b/server/start-server.sh new file mode 100755 index 0000000..c97db38 --- /dev/null +++ b/server/start-server.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +source .venv/bin/activate +uvicorn main:app --host 0.0.0.0 --port 7779 diff --git a/updater/config.json b/updater/config.json new file mode 100644 index 0000000..34eafb0 --- /dev/null +++ b/updater/config.json @@ -0,0 +1,5 @@ +{ + "minecraft": "./", + "server.url": "http://localhost:7779", + "token": "" +} \ No newline at end of file diff --git a/updater/requirments.txt b/updater/requirments.txt new file mode 100644 index 0000000..663bd1f --- /dev/null +++ b/updater/requirments.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/updater/update.bat b/updater/update.bat new file mode 100644 index 0000000..ea7cb5c --- /dev/null +++ b/updater/update.bat @@ -0,0 +1,21 @@ +@echo off + +:: Если это git репозиторий то автоматически обновляемся +IF EXIST .git ( + git pull +) + +:: Проверяем существование виртуального окружения +IF EXIST .\venv ( + :: Активируем виртуальное окружение + call .venv\Scripts\activate.bat +) ELSE ( + :: Создаем новое виртуальное окружение + python -m venv .venv + call .venv\Scripts\activate.bat + pip3 install -r requirements.txt +) + + +:: Запускаем скрипт updater.py +python .\updater.py diff --git a/updater/update.sh b/updater/update.sh new file mode 100755 index 0000000..8d96552 --- /dev/null +++ b/updater/update.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -d ".git" ]; then + git pull +fi + +if [ ! -d ".venv" ]; then + python3 -m venv .venv + source .venv/bin/activate + pip3 install -r ./requirments.txt +else + source .venv/bin/activate +fi + +python3 ./updater.py diff --git a/updater/updater.py b/updater/updater.py new file mode 100644 index 0000000..0382245 --- /dev/null +++ b/updater/updater.py @@ -0,0 +1,68 @@ +from pathlib import Path +import json +import os +import requests + +CONFIG_FILE: Path = Path(__file__).parent / "config.json" +CONFIG: dict = {} +with CONFIG_FILE.open() as f: + CONFIG = json.load(f) + +TOKEN: str = CONFIG["token"] + +MINECRAFT_FOLDER: Path = Path(CONFIG["minecraft"]).resolve() +MODS_FOLDER: Path = MINECRAFT_FOLDER / "mods" + +# Создаем папку модов если ее нет +if not MODS_FOLDER.exists(): + MODS_FOLDER.mkdir(parents=True) + +CURRENT_MODS: list["Path"] = [Path(p).name for p in os.listdir(MODS_FOLDER)] + +def get_mod_list(): + headers = {'Authorization': TOKEN} + response = requests.get(f'{CONFIG["server.url"]}/mods/files', headers=headers) + if response.status_code == 200: + return response.json().get('files', []) + else: + print(f'Ошибка при получении списка файлов: {response.text}') + return [] + + +def download_file(filename: str, dest: Path): + headers = {'Authorization': TOKEN} + url = f'{CONFIG["server.url"]}/mods/download/{filename}' + response = requests.get(url, headers=headers) + if response.status_code == 200: + with open(dest, 'wb') as f: + f.write(response.content) + print(f'Файл {filename} успешно загружен.') + else: + print(f'Не удалось загрузить файл {filename}: {response.text}') + + +ACTUAL_MODS: list["str"] = get_mod_list() + +TO_DELETE: list["Path"] = [] +TO_DOWNLOAD: list["str"] = [] + +# Проверяем лишние или старые моды +for cur_mod in CURRENT_MODS: + # Проверяем лишние или старые моды + if cur_mod not in ACTUAL_MODS: + TO_DELETE.append(MODS_FOLDER / cur_mod) + +for amod in ACTUAL_MODS: + if amod not in CURRENT_MODS: + TO_DOWNLOAD.append(amod) + +# Применение действий + +# Удаление лишнего +for file in TO_DELETE: + print(f"Удаление {amod}") + os.remove(str(file)) + +# Скачивание нужного +for filename in TO_DOWNLOAD: + download_file(filename, MODS_FOLDER / filename)