mirror of
https://github.com/fusion44/blitz_api.git
synced 2026-08-15 12:10:12 +02:00
feat: add shutdown/reboot SSE events on initiation
plus: * add some more documentation * add error handling when the script fails to run * a bit of refactoring refs #70
This commit is contained in:
parent
25ec9f0af5
commit
efdb1c1057
5 changed files with 70 additions and 28 deletions
|
|
@ -15,13 +15,19 @@ if PLATFORM == APIPlatform.RASPIBLITZ:
|
|||
HW_INFO_YIELD_TIME,
|
||||
get_hardware_info_impl,
|
||||
)
|
||||
from app.repositories.system_impl.raspiblitz import get_system_info_impl
|
||||
from app.repositories.system_impl.raspiblitz import (
|
||||
get_system_info_impl,
|
||||
shutdown_impl,
|
||||
)
|
||||
elif PLATFORM == APIPlatform.NATIVE_PYTHON:
|
||||
from app.repositories.hardware_impl.native_python import (
|
||||
HW_INFO_YIELD_TIME,
|
||||
get_hardware_info_impl,
|
||||
)
|
||||
from app.repositories.system_impl.native_python import get_system_info_impl
|
||||
from app.repositories.system_impl.native_python import (
|
||||
get_system_info_impl,
|
||||
shutdown_impl,
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(f"Unknown platform {PLATFORM}")
|
||||
|
||||
|
|
@ -83,12 +89,12 @@ def password_valid(password: str):
|
|||
return re.match("^[a-zA-Z0-9]*$", password)
|
||||
|
||||
|
||||
def name_valid(password : str):
|
||||
def name_valid(password: str):
|
||||
if len(password) < 3:
|
||||
return False
|
||||
if password.find(' ') >= 0:
|
||||
if password.find(" ") >= 0:
|
||||
return False
|
||||
return re.match('^[\.a-zA-Z0-9-_]*$', password)
|
||||
return re.match("^[\.a-zA-Z0-9-_]*$", password)
|
||||
|
||||
|
||||
async def get_system_info() -> SystemInfo:
|
||||
|
|
@ -104,6 +110,15 @@ async def get_hardware_info() -> map:
|
|||
return await get_hardware_info_impl()
|
||||
|
||||
|
||||
async def shutdown(reboot: bool) -> bool:
|
||||
if reboot:
|
||||
await send_sse_message(SSE.SYSTEM_REBOOT_NOTICE, {"reboot": True})
|
||||
else:
|
||||
await send_sse_message(SSE.SYSTEM_SHUTDOWN_NOTICE, {"shutdown": True})
|
||||
|
||||
return await shutdown_impl(reboot=reboot)
|
||||
|
||||
|
||||
async def subscribe_hardware_info(request: Request):
|
||||
while True:
|
||||
if await request.is_disconnected():
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import logging
|
||||
|
||||
from decouple import config
|
||||
|
||||
from app.constants import API_VERSION
|
||||
|
|
@ -43,3 +45,8 @@ async def get_system_info_impl() -> SystemInfo:
|
|||
ssh_address=ssh_address,
|
||||
chain=lninfo.chains[0].network,
|
||||
)
|
||||
|
||||
|
||||
async def shutdown_impl(reboot: bool) -> bool:
|
||||
logging.info("Shutdown / reboot not supported in native_python mode.")
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
from decouple import config
|
||||
|
|
@ -12,7 +13,7 @@ from app.models.system import (
|
|||
SystemInfo,
|
||||
)
|
||||
from app.repositories.lightning import get_ln_info
|
||||
from app.utils import redis_get
|
||||
from app.utils import SSE, redis_get, send_sse_message
|
||||
|
||||
SHELL_SCRIPT_PATH = config("shell_script_path")
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ async def get_system_info_impl() -> SystemInfo:
|
|||
)
|
||||
|
||||
|
||||
async def shutdown(reboot: bool):
|
||||
async def shutdown_impl(reboot: bool) -> bool:
|
||||
params = ""
|
||||
if reboot:
|
||||
params = "reboot"
|
||||
|
|
@ -59,8 +60,19 @@ async def shutdown(reboot: bool):
|
|||
|
||||
stdout, stderr = await proc.communicate()
|
||||
|
||||
print(f"[{cmd!r} exited with {proc.returncode}]")
|
||||
logging.info(f"[{cmd!r} exited with {proc.returncode}]")
|
||||
if stdout:
|
||||
print(f"[stdout]\n{stdout.decode()}")
|
||||
logging.info(f"[stdout]\n{stdout.decode()}")
|
||||
if stderr:
|
||||
print(f"[stderr]\n{stderr.decode()}")
|
||||
logging.error(f"[stderr]\n{stderr.decode()}")
|
||||
|
||||
if proc.returncode > 0:
|
||||
err = stderr.decode()
|
||||
if reboot:
|
||||
await send_sse_message(SSE.SYSTEM_REBOOT_ERROR, {"error_message": err})
|
||||
else:
|
||||
await send_sse_message(SSE.SYSTEM_SHUTDOWN_ERROR, {"error_message": err})
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@ from fastapi.params import Depends
|
|||
from app.auth.auth_bearer import JWTBearer
|
||||
from app.auth.auth_handler import sign_jwt
|
||||
from app.external.sse_starlette import EventSourceResponse
|
||||
from app.models.system import APIPlatform, LoginInput, RawDebugLogData, SystemInfo
|
||||
from app.models.system import LoginInput, RawDebugLogData, SystemInfo
|
||||
from app.repositories.system import (
|
||||
HW_INFO_YIELD_TIME,
|
||||
PLATFORM,
|
||||
call_script,
|
||||
get_debug_logs_raw,
|
||||
get_hardware_info,
|
||||
get_system_info,
|
||||
parse_key_value_text,
|
||||
password_valid,
|
||||
shutdown,
|
||||
subscribe_hardware_info,
|
||||
)
|
||||
from app.repositories.system_impl.raspiblitz import shutdown
|
||||
from app.routers.system_docs import (
|
||||
get_debug_logs_raw_desc,
|
||||
get_debug_logs_raw_resp_desc,
|
||||
get_debug_logs_raw_summary,
|
||||
get_hw_info_json,
|
||||
)
|
||||
from app.utils import SSE
|
||||
|
||||
_PREFIX = "system"
|
||||
|
||||
|
|
@ -137,29 +137,33 @@ async def hw_info_sub(request: Request):
|
|||
"/reboot",
|
||||
name=f"{_PREFIX}.reboot",
|
||||
summary="Reboots the system",
|
||||
description=f"""Attempts to reboot the system.
|
||||
Will send a `{SSE.SYSTEM_REBOOT_NOTICE}` SSE message immediately to
|
||||
all connected clients.
|
||||
""",
|
||||
response_description=f"""True if successful. False on failure.
|
||||
A failure will also send an error message with id `{SSE.SYSTEM_REBOOT_ERROR}`
|
||||
to all connected clients.
|
||||
""",
|
||||
dependencies=[Depends(JWTBearer())],
|
||||
)
|
||||
async def reboot_system() -> bool:
|
||||
if PLATFORM == APIPlatform.RASPIBLITZ:
|
||||
await shutdown(True)
|
||||
return True
|
||||
else:
|
||||
raise HTTPException(
|
||||
status.HTTP_501_NOT_IMPLEMENTED, detail="Not implemented on native"
|
||||
)
|
||||
return await shutdown(False)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/shutdown",
|
||||
name=f"{_PREFIX}.shutdown",
|
||||
summary="Shuts the system down",
|
||||
description=f"""Attempts to shutdown the system.
|
||||
Will send a `{SSE.SYSTEM_SHUTDOWN_NOTICE}` SSE message immediately to all
|
||||
connected clients.
|
||||
""",
|
||||
response_description=f"""True if successful. False on failure.
|
||||
A failure will also send an error message with id {SSE.SYSTEM_SHUTDOWN_ERROR}
|
||||
to all connected clients.
|
||||
""",
|
||||
dependencies=[Depends(JWTBearer())],
|
||||
)
|
||||
async def shutdown() -> bool:
|
||||
if PLATFORM == APIPlatform.RASPIBLITZ:
|
||||
await shutdown(False)
|
||||
return True
|
||||
else:
|
||||
raise HTTPException(
|
||||
status.HTTP_501_NOT_IMPLEMENTED, detail="Not implemented on native"
|
||||
)
|
||||
async def shutdown_path() -> bool:
|
||||
return await shutdown(False)
|
||||
|
|
|
|||
|
|
@ -179,6 +179,10 @@ async def redis_get(key: str) -> str:
|
|||
|
||||
class SSE:
|
||||
SYSTEM_INFO = "system_info"
|
||||
SYSTEM_SHUTDOWN_NOTICE = "system_shutdown_initiated"
|
||||
SYSTEM_SHUTDOWN_ERROR = "system_shutdown_error"
|
||||
SYSTEM_REBOOT_NOTICE = "system_reboot_initiated"
|
||||
SYSTEM_REBOOT_ERROR = "system_reboot_error"
|
||||
HARDWARE_INFO = "hardware_info"
|
||||
|
||||
INSTALLED_APP_STATUS = "installed_app_status"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue