post
parent
6851b39c28
commit
ac5eb45787
12
Dockerfile
12
Dockerfile
|
|
@ -1,9 +1,17 @@
|
||||||
|
# /opt/rustdesk-organizer/Dockerfile
|
||||||
|
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
COPY app.py .
|
COPY app.py .
|
||||||
COPY templates/ ./templates/
|
COPY templates/ ./templates/
|
||||||
EXPOSE 8001
|
|
||||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8001"]
|
# Экспонируем оба порта
|
||||||
|
EXPOSE 8001 8002
|
||||||
|
|
||||||
|
# Запускаем два процесса Uvicorn для разных портов
|
||||||
|
CMD ["sh", "-c", "uvicorn app:app_get --host 0.0.0.0 --port 8001 & uvicorn app:app_post --host 0.0.0.0 --port 8002"]
|
||||||
280
app.py
280
app.py
|
|
@ -1,30 +1,23 @@
|
||||||
from fastapi import FastAPI, HTTPException, File, UploadFile, Query
|
from fastapi import FastAPI, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import datetime
|
import datetime
|
||||||
import csv
|
|
||||||
import markdown
|
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.responses import FileResponse, StreamingResponse
|
from fastapi.responses import FileResponse
|
||||||
import io
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
app = FastAPI()
|
# Создаем два экземпляра FastAPI для разных портов (опционально, для демонстрации)
|
||||||
|
app_get = FastAPI(title="RustDesk Organizer - Web Interface")
|
||||||
|
app_post = FastAPI(title="RustDesk Organizer - API")
|
||||||
|
|
||||||
|
# Монтируем папку templates как статические файлы для GET
|
||||||
|
app_get.mount("/templates", StaticFiles(directory="templates"), name="templates")
|
||||||
|
|
||||||
# Соединение с базой данных
|
# Соединение с базой данных
|
||||||
conn = sqlite3.connect("/db/rustdesk.db", check_same_thread=False)
|
conn = sqlite3.connect("/db/rustdesk.db", check_same_thread=False)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# Проверяем и обновляем структуру таблицы installs
|
# Создаем таблицы (оставляем как есть)
|
||||||
cursor.execute("PRAGMA table_info(installs)")
|
|
||||||
columns = [row[1] for row in cursor.fetchall()]
|
|
||||||
if 'protocol' not in columns:
|
|
||||||
cursor.execute("ALTER TABLE installs ADD COLUMN protocol TEXT DEFAULT 'rustdesk'")
|
|
||||||
conn.commit()
|
|
||||||
if 'note' not in columns:
|
|
||||||
cursor.execute("ALTER TABLE installs ADD COLUMN note TEXT DEFAULT ''")
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
# Создаем таблицы (добавляем поле protocol и note, если таблицы нет)
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS folders (
|
CREATE TABLE IF NOT EXISTS folders (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
|
@ -40,24 +33,12 @@ CREATE TABLE IF NOT EXISTS installs (
|
||||||
computer_name TEXT,
|
computer_name TEXT,
|
||||||
install_time TEXT,
|
install_time TEXT,
|
||||||
folder_id INTEGER,
|
folder_id INTEGER,
|
||||||
protocol TEXT DEFAULT 'rustdesk',
|
|
||||||
note TEXT DEFAULT '',
|
|
||||||
FOREIGN KEY (folder_id) REFERENCES folders(id)
|
FOREIGN KEY (folder_id) REFERENCES folders(id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
# Проверяем/создаем папку "Несортированные" и получаем её ID
|
# Модели данных (оставляем как есть)
|
||||||
cursor.execute("SELECT id FROM folders WHERE name = 'Несортированные'")
|
|
||||||
unsorted_folder = cursor.fetchone()
|
|
||||||
if not unsorted_folder:
|
|
||||||
cursor.execute("INSERT INTO folders (name) VALUES ('Несортированные')")
|
|
||||||
conn.commit()
|
|
||||||
unsorted_folder_id = cursor.lastrowid
|
|
||||||
else:
|
|
||||||
unsorted_folder_id = unsorted_folder[0]
|
|
||||||
|
|
||||||
# Модели данных
|
|
||||||
class Folder(BaseModel):
|
class Folder(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
parent_id: int | None = None
|
parent_id: int | None = None
|
||||||
|
|
@ -66,242 +47,101 @@ class FolderUpdate(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
class InstallData(BaseModel):
|
class InstallData(BaseModel):
|
||||||
rust_id: str | None = None
|
rust_id: str
|
||||||
computer_name: str | None = None
|
computer_name: str
|
||||||
install_time: str | None = None # Принимаем строку в формате YYYY-MM-DD HH:MM:SS
|
install_time: str | None = None
|
||||||
folder_id: int | None = None
|
folder_id: int | None = None
|
||||||
protocol: str | None = 'rustdesk' # По умолчанию RustDesk
|
|
||||||
note: str | None = '' # Новая заметка, по умолчанию пустая
|
|
||||||
|
|
||||||
# Монтируем папки templates и icons как статические файлы
|
# Функция для работы с базой данных
|
||||||
app.mount("/templates", StaticFiles(directory="templates"), name="templates")
|
def get_db():
|
||||||
app.mount("/icons", StaticFiles(directory="templates/icons"), name="icons")
|
return conn, cursor
|
||||||
|
|
||||||
# Главная страница
|
# --- GET API (порт 8001) ---
|
||||||
@app.get("/")
|
@app_get.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
return FileResponse("templates/index.html")
|
return FileResponse("templates/index.html")
|
||||||
|
|
||||||
# --- Folders API ---
|
@app_get.get("/api/folders")
|
||||||
@app.get("/api/folders")
|
|
||||||
def get_folders():
|
def get_folders():
|
||||||
|
conn, cursor = get_db()
|
||||||
cursor.execute("SELECT * FROM folders")
|
cursor.execute("SELECT * FROM folders")
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
return [{"id": row[0], "name": row[1], "parent_id": row[2]} for row in rows]
|
return [{"id": row[0], "name": row[1], "parent_id": row[2]} for row in rows]
|
||||||
|
|
||||||
@app.post("/api/folders")
|
@app_get.get("/api/installs")
|
||||||
|
def get_installs():
|
||||||
|
conn, cursor = get_db()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT i.id, i.rust_id, i.computer_name, i.install_time, i.folder_id, f.name as folder_name
|
||||||
|
FROM installs i
|
||||||
|
LEFT JOIN folders f ON i.folder_id = f.id
|
||||||
|
""")
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
return [{"id": row[0], "rust_id": row[1], "computer_name": row[2],
|
||||||
|
"install_time": row[3], "folder_id": row[4], "folder_name": row[5]}
|
||||||
|
for row in rows]
|
||||||
|
|
||||||
|
# --- POST API (порт 8002) ---
|
||||||
|
@app_post.post("/api/folders")
|
||||||
def add_folder(folder: Folder):
|
def add_folder(folder: Folder):
|
||||||
|
conn, cursor = get_db()
|
||||||
cursor.execute("INSERT INTO folders (name, parent_id) VALUES (?, ?)",
|
cursor.execute("INSERT INTO folders (name, parent_id) VALUES (?, ?)",
|
||||||
(folder.name, folder.parent_id))
|
(folder.name, folder.parent_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return {"status": "success", "id": cursor.lastrowid}
|
return {"status": "success", "id": cursor.lastrowid}
|
||||||
|
|
||||||
@app.put("/api/folders/{folder_id}")
|
@app_post.put("/api/folders/{folder_id}")
|
||||||
def update_folder(folder_id: int, folder: FolderUpdate):
|
def update_folder(folder_id: int, folder: FolderUpdate):
|
||||||
|
conn, cursor = get_db()
|
||||||
cursor.execute("UPDATE folders SET name = ? WHERE id = ?", (folder.name, folder_id))
|
cursor.execute("UPDATE folders SET name = ? WHERE id = ?", (folder.name, folder_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise HTTPException(status_code=404, detail="Папка не найдена")
|
raise HTTPException(status_code=404, detail="Папка не найдена")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
@app.delete("/api/folders/{folder_id}")
|
@app_post.delete("/api/folders/{folder_id}")
|
||||||
def delete_folder(folder_id: int):
|
def delete_folder(folder_id: int):
|
||||||
# Проверяем, не является ли папка "Несортированные"
|
conn, cursor = get_db()
|
||||||
cursor.execute("SELECT name FROM folders WHERE id = ?", (folder_id,))
|
|
||||||
folder_name = cursor.fetchone()
|
|
||||||
if folder_name and folder_name[0] == 'Несортированные':
|
|
||||||
raise HTTPException(status_code=403, detail="Папка 'Несортированные' не может быть удалена")
|
|
||||||
|
|
||||||
cursor.execute("DELETE FROM folders WHERE id = ?", (folder_id,))
|
cursor.execute("DELETE FROM folders WHERE id = ?", (folder_id,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise HTTPException(status_code=404, detail="Папка не найдена")
|
raise HTTPException(status_code=404, detail="Папка не найдена")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
# --- Installs API ---
|
@app_post.post("/api/install")
|
||||||
@app.get("/api/installs")
|
|
||||||
def get_installs():
|
|
||||||
cursor.execute("""
|
|
||||||
SELECT i.id, i.rust_id, i.computer_name, i.install_time, i.folder_id, f.name as folder_name, i.protocol, i.note
|
|
||||||
FROM installs i
|
|
||||||
LEFT JOIN folders f ON i.folder_id = f.id
|
|
||||||
""")
|
|
||||||
rows = cursor.fetchall()
|
|
||||||
# Обработка времени в разных форматах
|
|
||||||
def format_time(time_str):
|
|
||||||
if not time_str:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать ISO 8601 (с T и Z)
|
|
||||||
dt = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
||||||
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать наш читаемый формат
|
|
||||||
dt = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
|
|
||||||
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
return time_str # Возвращаем как есть, если формат не распознан
|
|
||||||
|
|
||||||
return [{"id": row[0], "rust_id": row[1], "computer_name": row[2],
|
|
||||||
"install_time": format_time(row[3]),
|
|
||||||
"folder_id": row[4], "folder_name": row[5], "protocol": row[6], "note": row[7]}
|
|
||||||
for row in rows]
|
|
||||||
|
|
||||||
@app.post("/api/install")
|
|
||||||
def add_install(data: InstallData):
|
def add_install(data: InstallData):
|
||||||
install_time = data.install_time or datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Форматируем в читаемый формат
|
install_time = data.install_time or datetime.datetime.now().isoformat()
|
||||||
folder_id = data.folder_id if data.folder_id is not None else unsorted_folder_id
|
conn, cursor = get_db()
|
||||||
protocol = data.protocol or 'rustdesk' # По умолчанию RustDesk для POST-запросов
|
cursor.execute("INSERT INTO installs (rust_id, computer_name, install_time, folder_id) VALUES (?, ?, ?, ?)",
|
||||||
note = data.note or '' # Новая заметка, по умолчанию пустая
|
(data.rust_id, data.computer_name, install_time, data.folder_id))
|
||||||
cursor.execute("INSERT INTO installs (rust_id, computer_name, install_time, folder_id, protocol, note) VALUES (?, ?, ?, ?, ?, ?)",
|
|
||||||
(data.rust_id, data.computer_name, install_time, folder_id, protocol, note))
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
@app.put("/api/install/{install_id}")
|
@app_post.put("/api/install/{install_id}")
|
||||||
def update_install(install_id: int, data: InstallData):
|
def update_install(install_id: int, data: InstallData):
|
||||||
cursor.execute("SELECT rust_id, computer_name, install_time, folder_id, protocol, note FROM installs WHERE id = ?", (install_id,))
|
conn, cursor = get_db()
|
||||||
current = cursor.fetchone()
|
|
||||||
if not current:
|
|
||||||
raise HTTPException(status_code=404, detail="Запись не найдена")
|
|
||||||
|
|
||||||
new_rust_id = data.rust_id if data.rust_id is not None else current[0]
|
|
||||||
new_computer_name = data.computer_name if data.computer_name is not None else current[1]
|
|
||||||
new_install_time = data.install_time if data.install_time is not None else current[2]
|
|
||||||
new_folder_id = data.folder_id if data.folder_id is not None else current[3]
|
|
||||||
new_protocol = data.protocol if data.protocol is not None else current[4]
|
|
||||||
new_note = data.note if data.note is not None else current[5]
|
|
||||||
|
|
||||||
# Форматируем время, если оно предоставлено в запросе
|
|
||||||
if new_install_time:
|
|
||||||
try:
|
|
||||||
# Проверяем, что время в формате YYYY-MM-DD HH:MM:SS
|
|
||||||
datetime.datetime.strptime(new_install_time, "%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
raise HTTPException(status_code=400, detail="Неверный формат времени. Используйте YYYY-MM-DD HH:MM:SS")
|
|
||||||
else:
|
|
||||||
new_install_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
UPDATE installs
|
UPDATE installs
|
||||||
SET rust_id = ?, computer_name = ?, install_time = ?, folder_id = ?, protocol = ?, note = ?
|
SET rust_id = ?, computer_name = ?, install_time = ?, folder_id = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
""", (new_rust_id, new_computer_name, new_install_time, new_folder_id, new_protocol, new_note, install_id))
|
""", (data.rust_id, data.computer_name, data.install_time or datetime.datetime.now().isoformat(),
|
||||||
|
data.folder_id, install_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
if cursor.rowcount == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Запись не найдена")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
@app.delete("/api/install/{install_id}")
|
@app_post.delete("/api/install/{install_id}")
|
||||||
def delete_install(install_id: int):
|
def delete_install(install_id: int):
|
||||||
|
conn, cursor = get_db()
|
||||||
cursor.execute("DELETE FROM installs WHERE id = ?", (install_id,))
|
cursor.execute("DELETE FROM installs WHERE id = ?", (install_id,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise HTTPException(status_code=404, detail="Запись не найдена")
|
raise HTTPException(status_code=404, detail="Запись не найдена")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
# --- CSV Export/Import API ---
|
# CORS для обоих приложений
|
||||||
@app.get("/api/export/csv")
|
for app in [app_get, app_post]:
|
||||||
async def export_csv(folder_id: int | None = Query(None, description="ID папки для экспорта, если None - экспортировать все папки")):
|
|
||||||
if folder_id:
|
|
||||||
cursor.execute("""
|
|
||||||
SELECT i.rust_id, i.computer_name, i.install_time, f.name as folder_name, i.protocol, i.note
|
|
||||||
FROM installs i
|
|
||||||
LEFT JOIN folders f ON i.folder_id = f.id
|
|
||||||
WHERE i.folder_id = ?
|
|
||||||
""", (folder_id,))
|
|
||||||
else:
|
|
||||||
cursor.execute("""
|
|
||||||
SELECT i.rust_id, i.computer_name, i.install_time, f.name as folder_name, i.protocol, i.note
|
|
||||||
FROM installs i
|
|
||||||
LEFT JOIN folders f ON i.folder_id = f.id
|
|
||||||
""")
|
|
||||||
rows = cursor.fetchall()
|
|
||||||
|
|
||||||
output = io.StringIO()
|
|
||||||
writer = csv.writer(output, lineterminator='\n')
|
|
||||||
writer.writerow(['ID подключения', 'Имя компьютера', 'Время установки', 'Папка', 'Протокол', 'Заметка'])
|
|
||||||
for row in rows:
|
|
||||||
# Обработка времени в разных форматах
|
|
||||||
install_time = format_time(row[2]) if row[2] else ""
|
|
||||||
writer.writerow([row[0], row[1], install_time, row[3], row[4], row[5]])
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Content-Disposition': 'attachment; filename="rustdesk_data.csv"',
|
|
||||||
'Content-Type': 'text/csv'
|
|
||||||
}
|
|
||||||
return StreamingResponse(iter([output.getvalue()]), headers=headers)
|
|
||||||
|
|
||||||
def format_time(time_str):
|
|
||||||
if not time_str:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать ISO 8601 (с T и Z)
|
|
||||||
dt = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
||||||
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать наш читаемый формат
|
|
||||||
dt = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
|
|
||||||
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
return time_str # Возвращаем как есть, если формат не распознан
|
|
||||||
|
|
||||||
@app.post("/api/import/csv")
|
|
||||||
async def import_csv(file: UploadFile = File(...), folder_id: int | None = Query(None, description="ID папки для импорта, если None - использовать 'Несортированные'")):
|
|
||||||
try:
|
|
||||||
contents = await file.read()
|
|
||||||
csv_data = io.StringIO(contents.decode('utf-8'))
|
|
||||||
reader = csv.DictReader(csv_data)
|
|
||||||
|
|
||||||
target_folder_id = folder_id if folder_id is not None else unsorted_folder_id
|
|
||||||
|
|
||||||
for row in reader:
|
|
||||||
rust_id = row['ID подключения']
|
|
||||||
computer_name = row['Имя компьютера']
|
|
||||||
install_time = row['Время установки']
|
|
||||||
folder_name = row.get('Папка', None)
|
|
||||||
protocol = row.get('Протокол', 'rustdesk')
|
|
||||||
note = row.get('Заметка', '')
|
|
||||||
|
|
||||||
# Проверяем, существует ли запись с таким rust_id
|
|
||||||
cursor.execute("SELECT id FROM installs WHERE rust_id = ?", (rust_id,))
|
|
||||||
if cursor.fetchone():
|
|
||||||
continue # Пропускаем дублирующуюся запись
|
|
||||||
|
|
||||||
# Проверяем и форматируем время
|
|
||||||
if install_time:
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать время в формате YYYY-MM-DD HH:MM:SS
|
|
||||||
dt = datetime.datetime.strptime(install_time, "%Y-%m-%d %H:%M:%S")
|
|
||||||
install_time = dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
# Пробуем разобрать ISO 8601 (если в CSV другой формат)
|
|
||||||
dt = datetime.datetime.strptime(install_time, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
||||||
install_time = dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
except ValueError:
|
|
||||||
raise HTTPException(status_code=400, detail=f"Неверный формат времени для записи с ID {rust_id}. Используйте YYYY-MM-DD HH:MM:SS или ISO 8601")
|
|
||||||
|
|
||||||
# Получаем или создаем ID папки
|
|
||||||
if folder_name:
|
|
||||||
cursor.execute("SELECT id FROM folders WHERE name = ?", (folder_name,))
|
|
||||||
folder = cursor.fetchone()
|
|
||||||
folder_id = folder[0] if folder else unsorted_folder_id
|
|
||||||
else:
|
|
||||||
folder_id = target_folder_id
|
|
||||||
|
|
||||||
cursor.execute("""
|
|
||||||
INSERT INTO installs (rust_id, computer_name, install_time, folder_id, protocol, note)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
|
||||||
""", (rust_id, computer_name, install_time, folder_id, protocol, note))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
return {"status": "success", "message": "Данные успешно импортированы"}
|
|
||||||
except Exception as e:
|
|
||||||
raise HTTPException(status_code=400, detail=f"Ошибка импорта: {str(e)}")
|
|
||||||
|
|
||||||
# CORS
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
|
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
|
||||||
|
|
@ -309,3 +149,9 @@ app.add_middleware(
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
# Запускаем два процесса Uvicorn для разных портов (опционально, для локального теста)
|
||||||
|
uvicorn.run(app_get, host="0.0.0.0", port=8001)
|
||||||
|
uvicorn.run(app_post, host="0.0.0.0", port=8002)
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
|
# /opt/rustdesk-organizer/docker-compose.yml
|
||||||
|
|
||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
rustdesk-organizer:
|
rustdesk-organizer:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "8001:8001"
|
- "8001:8001" # Порт для GET-запросов (веб-интерфейс)
|
||||||
|
- "8002:8002" # Порт для POST-запросов (API)
|
||||||
volumes:
|
volumes:
|
||||||
- ./db:/db
|
- ./db:/db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
Loading…
Reference in New Issue