From 251246e54d676f8cda3458b4e88c468f166d4462 Mon Sep 17 00:00:00 2001 From: Iam54r1n4 Date: Sun, 26 Jan 2025 13:30:05 +0000 Subject: [PATCH] Refactor and Document endpoints --- .../webpanel/routers/api/v1/config/config.py | 0 .../routers/api/v1/config/hysteria.py | 122 ++++++++++++++++-- .../routers/api/v1/config/normalsub.py | 28 ++++ .../webpanel/routers/api/v1/config/singbox.py | 23 ++++ .../routers/api/v1/config/telegram.py | 16 +++ .../webpanel/routers/api/v1/config/warp.py | 52 ++++++++ .../scripts/webpanel/routers/api/v1/server.py | 27 ++++ core/scripts/webpanel/routers/api/v1/user.py | 70 ++++++++++ core/scripts/webpanel/routers/warp.py | 15 --- 9 files changed, 328 insertions(+), 25 deletions(-) delete mode 100644 core/scripts/webpanel/routers/api/v1/config/config.py delete mode 100644 core/scripts/webpanel/routers/warp.py diff --git a/core/scripts/webpanel/routers/api/v1/config/config.py b/core/scripts/webpanel/routers/api/v1/config/config.py deleted file mode 100644 index e69de29..0000000 diff --git a/core/scripts/webpanel/routers/api/v1/config/hysteria.py b/core/scripts/webpanel/routers/api/v1/config/hysteria.py index a258998..1143cb0 100644 --- a/core/scripts/webpanel/routers/api/v1/config/hysteria.py +++ b/core/scripts/webpanel/routers/api/v1/config/hysteria.py @@ -6,8 +6,20 @@ import cli_api router = APIRouter() -@router.get('/install', response_model=DetailResponse) +@router.get('/install', response_model=DetailResponse, summary='Install Hysteria2') async def install(body: InstallInputBody): + """ + Installs Hysteria2 on the given port and uses the provided or default SNI value. + + Args: + body: An instance of InstallInputBody containing the new port and SNI value. + + Returns: + A DetailResponse with a message indicating the Hysteria2 installation was successful. + + Raises: + HTTPException: if an error occurs while installing Hysteria2. + """ try: cli_api.install_hysteria2(body.port, body.sni) return DetailResponse(detail=f'Hysteria2 installed successfully on port {body.port} with SNI {body.sni}.') @@ -15,8 +27,17 @@ async def install(body: InstallInputBody): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/uninstall', response_model=DetailResponse) +@router.get('/uninstall', response_model=DetailResponse, summary='Uninstall Hysteria2') async def uninstall(): + """ + Uninstalls Hysteria2. + + Returns: + A DetailResponse with a message indicating the Hysteria2 uninstallation was successful. + + Raises: + HTTPException: if an error occurs while uninstalling Hysteria2. + """ try: cli_api.uninstall_hysteria2() return DetailResponse(detail='Hysteria2 uninstalled successfully.') @@ -24,8 +45,17 @@ async def uninstall(): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/update', response_model=DetailResponse) +@router.get('/update', response_model=DetailResponse, summary='Update Hysteria2') async def update(): + """ + Updates Hysteria2. + + Returns: + A DetailResponse with a message indicating the Hysteria2 update was successful. + + Raises: + HTTPException: if an error occurs while updating Hysteria2. + """ try: cli_api.update_hysteria2() return DetailResponse(detail='Hysteria2 updated successfully.') @@ -33,8 +63,20 @@ async def update(): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/set-port/{port}', response_model=DetailResponse) +@router.get('/set-port/{port}', response_model=DetailResponse, summary='Set Hysteria2 port') async def set_port(port: int): + """ + Sets the port for Hysteria2. + + Args: + port: The new port value. + + Returns: + A DetailResponse with a message indicating the Hysteria2 port change was successful. + + Raises: + HTTPException: if an error occurs while changing the Hysteria2 port. + """ try: cli_api.change_hysteria2_port(port) return DetailResponse(detail=f'Hysteria2 port changed to {port} successfully.') @@ -42,8 +84,20 @@ async def set_port(port: int): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/set-sni/{sni}', response_model=DetailResponse) +@router.get('/set-sni/{sni}', response_model=DetailResponse, summary='Set Hysteria2 SNI') async def set_sni(sni: str): + """ + Sets the SNI for Hysteria2. + + Args: + sni: The new SNI value. + + Returns: + A DetailResponse with a message indicating the Hysteria2 SNI change was successful. + + Raises: + HTTPException: if an error occurs while changing the Hysteria2 SNI. + """ try: cli_api.change_hysteria2_sni(sni) return DetailResponse(detail=f'Hysteria2 SNI changed to {sni} successfully.') @@ -51,8 +105,17 @@ async def set_sni(sni: str): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/backup', response_model=DetailResponse) +@router.get('/backup', response_model=DetailResponse, summary='Backup Hysteria2 configuration') async def backup(): + """ + Backups the Hysteria2 configuration. + + Returns: + A DetailResponse with a message indicating the Hysteria2 configuration backup was successful. + + Raises: + HTTPException: if an error occurs while backing up the Hysteria2 configuration. + """ try: cli_api.backup_hysteria2() return DetailResponse(detail='Hysteria2 configuration backed up successfully.') @@ -60,8 +123,17 @@ async def backup(): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/enable-obfs', response_model=DetailResponse) +@router.get('/enable-obfs', response_model=DetailResponse, summary='Enable Hysteria2 obfs') async def enable_obfs(): + """ + Enables Hysteria2 obfs. + + Returns: + A DetailResponse with a message indicating the Hysteria2 obfs was enabled successfully. + + Raises: + HTTPException: if an error occurs while enabling Hysteria2 obfs. + """ try: cli_api.enable_hysteria2_obfs() return DetailResponse(detail='Hysteria2 obfs enabled successfully.') @@ -69,8 +141,17 @@ async def enable_obfs(): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/disable-obfs', response_model=DetailResponse) +@router.get('/disable-obfs', response_model=DetailResponse, summary='Disable Hysteria2 obfs') async def disable_obfs(): + """ + Disables Hysteria2 obfs. + + Returns: + A DetailResponse with a message indicating the Hysteria2 obfs was disabled successfully. + + Raises: + HTTPException: if an error occurs while disabling Hysteria2 obfs. + """ try: cli_api.disable_hysteria2_obfs() return DetailResponse(detail='Hysteria2 obfs disabled successfully.') @@ -78,8 +159,20 @@ async def disable_obfs(): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/enable-masquerade/{domain}', response_model=DetailResponse) +@router.get('/enable-masquerade/{domain}', response_model=DetailResponse, summary='Enable Hysteria2 masquerade') async def enable_masquerade(domain: str): + """ + Enables Hysteria2 masquerade for the given domain. + + Args: + domain: The domain to enable Hysteria2 masquerade for. + + Returns: + A DetailResponse with a message indicating the Hysteria2 masquerade was enabled successfully. + + Raises: + HTTPException: if an error occurs while enabling Hysteria2 masquerade. + """ try: cli_api.enable_hysteria2_masquerade(domain) return DetailResponse(detail='Hysteria2 masquerade enabled successfully.') @@ -87,8 +180,17 @@ async def enable_masquerade(domain: str): raise HTTPException(status_code=400, detail=f'Error: {str(e)}') -@router.get('/disable-masquerade', response_model=DetailResponse) +@router.get('/disable-masquerade', response_model=DetailResponse, summary='Disable Hysteria2 masquerade') async def disable_masquerade(): + """ + Disables Hysteria2 masquerade. + + Returns: + A DetailResponse with a message indicating the Hysteria2 masquerade was disabled successfully. + + Raises: + HTTPException: if an error occurs while disabling Hysteria2 masquerade. + """ try: cli_api.disable_hysteria2_masquerade() return DetailResponse(detail='Hysteria2 masquerade disabled successfully.') diff --git a/core/scripts/webpanel/routers/api/v1/config/normalsub.py b/core/scripts/webpanel/routers/api/v1/config/normalsub.py index 15f4c4a..356f80f 100644 --- a/core/scripts/webpanel/routers/api/v1/config/normalsub.py +++ b/core/scripts/webpanel/routers/api/v1/config/normalsub.py @@ -8,7 +8,23 @@ router = APIRouter() @router.get('/start', response_model=DetailResponse) async def start(body: StartInputBody): + """ + Starts the NormalSub service using the provided domain and port. + + Args: + body (StartInputBody): The request body containing the domain and port + information for starting the NormalSub service. + + Returns: + DetailResponse: A response object containing a success message indicating + that the NormalSub service has been started successfully. + + Raises: + HTTPException: If there is an error starting the NormalSub service, an + HTTPException with status code 400 and error details will be raised. + """ try: + cli_api.start_normalsub(body.domain, body.port) return DetailResponse(detail='Normalsub started successfully.') except Exception as e: @@ -17,6 +33,18 @@ async def start(body: StartInputBody): @router.get('/stop', response_model=DetailResponse) async def stop(): + """ + Stops the NormalSub service. + + Returns: + DetailResponse: A response object containing a success message indicating + that the NormalSub service has been stopped successfully. + + Raises: + HTTPException: If there is an error stopping the NormalSub service, an + HTTPException with status code 400 and error details will be raised. + """ + try: cli_api.stop_normalsub() return DetailResponse(detail='Normalsub stopped successfully.') diff --git a/core/scripts/webpanel/routers/api/v1/config/singbox.py b/core/scripts/webpanel/routers/api/v1/config/singbox.py index 6716a2f..a3976c7 100644 --- a/core/scripts/webpanel/routers/api/v1/config/singbox.py +++ b/core/scripts/webpanel/routers/api/v1/config/singbox.py @@ -8,6 +8,17 @@ router = APIRouter() @router.get('/start', response_model=DetailResponse) async def start(body: StartInputBody): + """ + Start the Singbox service. + + This endpoint starts the Singbox service if it is currently not running. + + Args: + body (StartInputBody): The domain name and port number for the service. + + Returns: + DetailResponse: The response with the result of the command. + """ try: cli_api.start_singbox(body.domain, body.port) return DetailResponse(detail='Singbox started successfully.') @@ -17,6 +28,18 @@ async def start(body: StartInputBody): @router.get('/stop', response_model=DetailResponse) async def stop(): + """ + Stop the Singbox service. + + This endpoint stops the Singbox service if it is currently running. + + Returns: + DetailResponse: A response model indicating the stop status of the Singbox service. + + Raises: + HTTPException: If there is an error stopping the Singbox service (400). + """ + try: cli_api.stop_singbox() return DetailResponse(detail='Singbox stopped successfully.') diff --git a/core/scripts/webpanel/routers/api/v1/config/telegram.py b/core/scripts/webpanel/routers/api/v1/config/telegram.py index f74c2b4..1b5b39c 100644 --- a/core/scripts/webpanel/routers/api/v1/config/telegram.py +++ b/core/scripts/webpanel/routers/api/v1/config/telegram.py @@ -8,6 +8,15 @@ router = APIRouter() @router.get('/start', response_model=DetailResponse) async def start(body: StartInputBody): + """ + Starts the Telegram bot. + + Args: + body (StartInputBody): The data containing the Telegram bot token and admin ID. + + Returns: + DetailResponse: The response containing the result of the action. + """ try: cli_api.start_telegram_bot(body.token, body.admin_id) return DetailResponse(detail='Telegram bot started successfully.') @@ -17,6 +26,13 @@ async def start(body: StartInputBody): @router.get('/stop', response_model=DetailResponse) async def stop(): + """ + Stops the Telegram bot. + + Returns: + DetailResponse: The response containing the result of the action. + """ + try: cli_api.stop_telegram_bot() except Exception as e: diff --git a/core/scripts/webpanel/routers/api/v1/config/warp.py b/core/scripts/webpanel/routers/api/v1/config/warp.py index 6dcaa7b..c2eda06 100644 --- a/core/scripts/webpanel/routers/api/v1/config/warp.py +++ b/core/scripts/webpanel/routers/api/v1/config/warp.py @@ -10,6 +10,15 @@ router = APIRouter() @router.get('/install', response_model=DetailResponse) async def install(): + """ + Installs WARP. + + Returns: + DetailResponse: A response indicating the success of the installation. + + Raises: + HTTPException: If an error occurs during installation, an HTTP 400 error is raised with the error details. + """ try: cli_api.install_warp() return DetailResponse(detail='WARP installed successfully.') @@ -19,6 +28,15 @@ async def install(): @router.get('/uninstall', response_model=DetailResponse) async def uninstall(): + """ + Uninstalls WARP. + + Returns: + DetailResponse: A response indicating the success of the uninstallation. + + Raises: + HTTPException: If an error occurs during uninstallation, an HTTP 400 error is raised with the error details. + """ try: cli_api.uninstall_warp() return DetailResponse(detail='WARP uninstalled successfully.') @@ -28,6 +46,18 @@ async def uninstall(): @router.get('/configure', response_model=DetailResponse) async def configure(body: ConfigureInputBody): + """ + Configures WARP with the given options. + + Args: + body: An instance of ConfigureInputBody containing configuration options. + + Returns: + DetailResponse: A response indicating the success of the configuration. + + Raises: + HTTPException: If an error occurs during configuration, an HTTP 400 error is raised with the error details. + """ try: cli_api.configure_warp(body.all, body.popular_sites, body.domestic_sites, body.block_adult_sites, body.warp_option, body.warp_key) @@ -38,6 +68,15 @@ async def configure(body: ConfigureInputBody): @router.get('/status', response_model=StatusResponse) async def status(): + """ + Retrieves the current status of WARP. + + Returns: + StatusResponse: A response model containing the current WARP status details. + + Raises: + HTTPException: If the WARP status is not available (404) or if there is an error processing the request (400). + """ try: if res := cli_api.warp_status(): return __parse_status(res) @@ -47,6 +86,19 @@ async def status(): def __parse_status(status: str) -> StatusResponse: + """ + Parses the output of the WARP status command to extract the current configuration settings. + + Args: + status: The output of the WARP status command as a string. + + Returns: + StatusResponse: A response model containing the current WARP status details. + + Raises: + ValueError: If the WARP status is invalid or incomplete. + """ + data = {} # Example output(status) from cli_api.warp_status(): # -------------------------------- diff --git a/core/scripts/webpanel/routers/api/v1/server.py b/core/scripts/webpanel/routers/api/v1/server.py index cbda9c1..70c4955 100644 --- a/core/scripts/webpanel/routers/api/v1/server.py +++ b/core/scripts/webpanel/routers/api/v1/server.py @@ -7,6 +7,20 @@ router = APIRouter() @router.get('/status', response_model=ServerStatusResponse) async def server_status(): + """ + Retrieve the server status. + + This endpoint provides information about the current server status, + including CPU usage, RAM usage, online users, and traffic statistics. + + Returns: + ServerStatusResponse: A response model containing server status details. + + Raises: + HTTPException: If the server information is not available (404) or + if there is an error processing the request (400). + """ + try: if res := cli_api.server_info(): return __parse_server_status(res) @@ -17,6 +31,19 @@ async def server_status(): def __parse_server_status(server_info: str) -> ServerStatusResponse: # Initial data with default values + """ + Parse the server information provided by cli_api.server_info() + and return a ServerStatusResponse instance. + + Args: + server_info (str): The output of cli_api.server_info() as a string. + + Returns: + ServerStatusResponse: A response model containing server status details. + + Raises: + ValueError: If the server information is invalid or incomplete. + """ data = { 'cpu_usage': '0%', 'total_ram': '0MB', diff --git a/core/scripts/webpanel/routers/api/v1/user.py b/core/scripts/webpanel/routers/api/v1/user.py index 1e6cd2f..214f843 100644 --- a/core/scripts/webpanel/routers/api/v1/user.py +++ b/core/scripts/webpanel/routers/api/v1/user.py @@ -9,6 +9,14 @@ router = APIRouter() @router.get('/', response_model=UserListResponse) async def list_users(): + """ + Get a list of all users. + + Returns: + List of user dictionaries. + Raises: + HTTPException: if no users are found, or if an error occurs. + """ try: if res := cli_api.list_users(): return res @@ -19,6 +27,18 @@ async def list_users(): @router.get('/{username}', response_model=UserInfoResponse) async def get_user(username: str): + """ + Get the details of a user. + + Args: + username: The username of the user to get. + + Returns: + A user dictionary. + + Raises: + HTTPException: if the user is not found, or if an error occurs. + """ try: if res := cli_api.get_user(username): return res @@ -29,6 +49,19 @@ async def get_user(username: str): @router.post('', response_model=DetailResponse) async def add_user(body: AddUserInputBody): + """ + Add a new user to the system. + + Args: + body: An instance of AddUserInputBody containing the user's details. + + Returns: + A DetailResponse with a message indicating the user has been added. + + Raises: + HTTPException: if an error occurs while adding the user. + """ + try: cli_api.add_user(body.username, body.traffic_limit, body.expiration_days, body.password, body.creation_date) return DetailResponse(detail=f'User {body.username} has been added.') @@ -38,6 +71,19 @@ async def add_user(body: AddUserInputBody): @router.patch('{username}', response_model=DetailResponse) async def edit_user(username: str, body: EditUserInputBody): + """ + Edit a user's details. + + Args: + username: The username of the user to edit. + body: An instance of EditUserInputBody containing the new user details. + + Returns: + A DetailResponse with a message indicating the user has been edited. + + Raises: + HTTPException: if an error occurs while editing the user. + """ try: cli_api.edit_user(username, body.new_username, body.new_traffic_limit, body.new_expiration_days, body.renew_password, body.renew_creation_date, body.blocked) @@ -48,6 +94,18 @@ async def edit_user(username: str, body: EditUserInputBody): @router.delete('/{username}', response_model=DetailResponse) async def remove_user(username: str): + """ + Remove a user. + + Args: + username: The username of the user to remove. + + Returns: + A DetailResponse with a message indicating the user has been removed. + + Raises: + HTTPException: if an error occurs while removing the user. + """ try: cli_api.remove_user(username) return DetailResponse(detail=f'User {username} has been removed.') @@ -57,6 +115,18 @@ async def remove_user(username: str): @router.get('/{username}/reset', response_model=DetailResponse) async def reset_user(username: str): + """ + Resets a user. + + Args: + username: The username of the user to reset. + + Returns: + A DetailResponse with a message indicating the user has been reset. + + Raises: + HTTPException: if an error occurs while resetting the user. + """ try: cli_api.reset_user(username) return DetailResponse(detail=f'User {username} has been reset.') diff --git a/core/scripts/webpanel/routers/warp.py b/core/scripts/webpanel/routers/warp.py deleted file mode 100644 index 891c1db..0000000 --- a/core/scripts/webpanel/routers/warp.py +++ /dev/null @@ -1,15 +0,0 @@ -from fastapi import APIRouter,Request - -router = APIRouter() - -@router.get('install') -async def install(request: Request): - pass - -@router.get('uninstall') -async def uninstall(request: Request): - pass - -@router.get('config') -async def config(request: Request): - pass \ No newline at end of file