mirror of
https://github.com/TheFunny/ArisuAutoSweeper
synced 2026-06-10 04:44:52 +00:00
Implement FastAPI backend with REST API and basic frontend
Co-authored-by: TheFunny <26841179+TheFunny@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
API routes for FastAPI backend
|
||||
"""
|
||||
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Configuration management API endpoints
|
||||
"""
|
||||
from typing import Dict, List, Any
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
from module.config.utils import alas_instance, alas_template, filepath_args, read_file
|
||||
from module.webui.fake import load_config, get_config_mod
|
||||
from module.webui.setting import State
|
||||
from module.logger import logger
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class ConfigValue(BaseModel):
|
||||
"""Config value update model"""
|
||||
path: str
|
||||
value: Any
|
||||
|
||||
|
||||
@router.get("/instances")
|
||||
async def get_instances():
|
||||
"""Get list of all alas instances"""
|
||||
return {
|
||||
"instances": alas_instance(),
|
||||
"templates": alas_template()
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{instance_name}")
|
||||
async def get_config(instance_name: str):
|
||||
"""Get configuration for a specific instance"""
|
||||
try:
|
||||
config_obj = load_config(instance_name)
|
||||
config_data = config_obj.read_file(instance_name)
|
||||
mod = get_config_mod(instance_name)
|
||||
|
||||
# Get menu and args for this instance
|
||||
menu = read_file(filepath_args("menu", mod))
|
||||
args = read_file(filepath_args("args", mod))
|
||||
|
||||
return {
|
||||
"name": instance_name,
|
||||
"mod": mod,
|
||||
"config": config_data,
|
||||
"menu": menu,
|
||||
"args": args
|
||||
}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=404, detail=f"Config not found: {instance_name}")
|
||||
|
||||
|
||||
@router.post("/{instance_name}")
|
||||
async def update_config(instance_name: str, updates: List[ConfigValue]):
|
||||
"""Update configuration values"""
|
||||
try:
|
||||
config_obj = load_config(instance_name)
|
||||
config_data = config_obj.read_file(instance_name)
|
||||
|
||||
# Apply updates
|
||||
for update in updates:
|
||||
path_parts = update.path.split(".")
|
||||
# Navigate to the nested dict and update
|
||||
current = config_data
|
||||
for part in path_parts[:-1]:
|
||||
if part not in current:
|
||||
current[part] = {}
|
||||
current = current[part]
|
||||
current[path_parts[-1]] = update.value
|
||||
|
||||
# Save config
|
||||
config_obj.write_file(instance_name, config_data)
|
||||
|
||||
logger.info(f"Updated config for {instance_name}")
|
||||
return {"status": "success", "message": "Config updated"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/create")
|
||||
async def create_instance(name: str, copy_from: str = "template-aas"):
|
||||
"""Create a new alas instance"""
|
||||
try:
|
||||
# Validate name
|
||||
if name in alas_instance():
|
||||
raise HTTPException(status_code=400, detail="Instance already exists")
|
||||
|
||||
if set(name) & set(".\\/:*?\"'<>|"):
|
||||
raise HTTPException(status_code=400, detail="Invalid characters in name")
|
||||
|
||||
if name.lower().startswith("template"):
|
||||
raise HTTPException(status_code=400, detail="Cannot start with 'template'")
|
||||
|
||||
# Copy config
|
||||
origin_config = load_config(copy_from).read_file(copy_from)
|
||||
State.config_updater.write_file(name, origin_config, get_config_mod(copy_from))
|
||||
|
||||
logger.info(f"Created new instance: {name}")
|
||||
return {"status": "success", "name": name}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{instance_name}")
|
||||
async def delete_instance(instance_name: str):
|
||||
"""Delete an alas instance"""
|
||||
try:
|
||||
# Add implementation for deleting instance
|
||||
# This would need to be added based on how configs are stored
|
||||
raise HTTPException(status_code=501, detail="Delete not implemented")
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Process management API endpoints
|
||||
"""
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
from module.webui.process_manager import ProcessManager
|
||||
from module.webui.updater import updater
|
||||
from module.logger import logger
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class ProcessCommand(BaseModel):
|
||||
"""Process command model"""
|
||||
task: Optional[str] = None
|
||||
|
||||
|
||||
@router.get("/{instance_name}/status")
|
||||
async def get_process_status(instance_name: str):
|
||||
"""Get process status"""
|
||||
try:
|
||||
alas = ProcessManager.get_manager(instance_name)
|
||||
return {
|
||||
"name": instance_name,
|
||||
"alive": alas.alive,
|
||||
"state": alas.state,
|
||||
"config_name": alas.config_name
|
||||
}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=404, detail=f"Process not found: {instance_name}")
|
||||
|
||||
|
||||
@router.post("/{instance_name}/start")
|
||||
async def start_process(instance_name: str, command: ProcessCommand = ProcessCommand()):
|
||||
"""Start a process"""
|
||||
try:
|
||||
alas = ProcessManager.get_manager(instance_name)
|
||||
alas.start(command.task, updater.event if command.task is None else None)
|
||||
logger.info(f"Started process: {instance_name}")
|
||||
return {"status": "success", "message": f"Started {instance_name}"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{instance_name}/stop")
|
||||
async def stop_process(instance_name: str):
|
||||
"""Stop a process"""
|
||||
try:
|
||||
alas = ProcessManager.get_manager(instance_name)
|
||||
alas.stop()
|
||||
logger.info(f"Stopped process: {instance_name}")
|
||||
return {"status": "success", "message": f"Stopped {instance_name}"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{instance_name}/restart")
|
||||
async def restart_process(instance_name: str):
|
||||
"""Restart a process"""
|
||||
try:
|
||||
alas = ProcessManager.get_manager(instance_name)
|
||||
alas.stop()
|
||||
alas.start(None, updater.event)
|
||||
logger.info(f"Restarted process: {instance_name}")
|
||||
return {"status": "success", "message": f"Restarted {instance_name}"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_all_processes():
|
||||
"""Get status of all processes"""
|
||||
try:
|
||||
processes = []
|
||||
for name, alas in ProcessManager._processes.items():
|
||||
processes.append({
|
||||
"name": name,
|
||||
"alive": alas.alive,
|
||||
"state": alas.state
|
||||
})
|
||||
return {"processes": processes}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
System management API endpoints
|
||||
"""
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
from module.webui.updater import updater
|
||||
from module.webui.setting import State
|
||||
from module.webui import lang
|
||||
from module.logger import logger
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class LanguageSetting(BaseModel):
|
||||
"""Language setting model"""
|
||||
language: str
|
||||
|
||||
|
||||
class ThemeSetting(BaseModel):
|
||||
"""Theme setting model"""
|
||||
theme: str
|
||||
|
||||
|
||||
@router.get("/info")
|
||||
async def get_system_info():
|
||||
"""Get system information"""
|
||||
return {
|
||||
"version": "1.0.0",
|
||||
"language": lang.LANG,
|
||||
"theme": State.deploy_config.Theme,
|
||||
"deploy_config": {
|
||||
"host": State.deploy_config.WebuiHost,
|
||||
"port": State.deploy_config.WebuiPort,
|
||||
"password_enabled": State.deploy_config.Password is not None,
|
||||
"remote_access": State.deploy_config.EnableRemoteAccess,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.post("/language")
|
||||
async def set_language(setting: LanguageSetting):
|
||||
"""Set system language"""
|
||||
try:
|
||||
lang.set_language(setting.language)
|
||||
State.deploy_config.Language = setting.language
|
||||
return {"status": "success", "language": setting.language}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/theme")
|
||||
async def set_theme(setting: ThemeSetting):
|
||||
"""Set system theme"""
|
||||
try:
|
||||
State.deploy_config.Theme = setting.theme
|
||||
State.theme = setting.theme
|
||||
return {"status": "success", "theme": setting.theme}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/update/status")
|
||||
async def get_update_status():
|
||||
"""Get update status"""
|
||||
try:
|
||||
return {
|
||||
"state": updater.state,
|
||||
"branch": updater.Branch,
|
||||
"local_commit": updater.get_commit(short_sha1=True),
|
||||
"upstream_commit": updater.get_commit(f"origin/{updater.Branch}", short_sha1=True)
|
||||
}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/update/check")
|
||||
async def check_update():
|
||||
"""Check for updates"""
|
||||
try:
|
||||
updater.check_update()
|
||||
return {"status": "success", "message": "Checking for updates"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/update/run")
|
||||
async def run_update():
|
||||
"""Run update"""
|
||||
try:
|
||||
updater.run_update()
|
||||
return {"status": "success", "message": "Update started"}
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/restart")
|
||||
async def restart_system():
|
||||
"""Restart the system"""
|
||||
try:
|
||||
if State.restart_event is not None:
|
||||
State.restart_event.set()
|
||||
return {"status": "success", "message": "Restart initiated"}
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="Restart not enabled")
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user