xui-rs 1.0.2

A modern, typed async Rust SDK for the 3x-ui panel API
Documentation
use std::collections::BTreeSet;

use serde_json::Value;

const SDK_ROUTES: &[(&str, &str, Option<&str>)] = &[
    (
        "post",
        "/panel/api/setting/all",
        Some("post_panel_api_setting_all"),
    ),
    (
        "post",
        "/panel/api/setting/defaultSettings",
        Some("post_panel_api_setting_defaultSettings"),
    ),
    (
        "post",
        "/panel/api/setting/factoryDefaults",
        Some("post_panel_api_setting_factoryDefaults"),
    ),
    (
        "post",
        "/panel/api/setting/update",
        Some("post_panel_api_setting_update"),
    ),
    (
        "post",
        "/panel/api/setting/validateRegex",
        Some("post_panel_api_setting_validateRegex"),
    ),
    (
        "post",
        "/panel/api/setting/updateUser",
        Some("post_panel_api_setting_updateUser"),
    ),
    (
        "post",
        "/panel/api/setting/restartPanel",
        Some("post_panel_api_setting_restartPanel"),
    ),
    (
        "get",
        "/panel/api/setting/getDefaultJsonConfig",
        Some("get_panel_api_setting_getDefaultJsonConfig"),
    ),
    (
        "get",
        "/panel/api/setting/apiTokens",
        Some("get_panel_api_setting_apiTokens"),
    ),
    (
        "post",
        "/panel/api/setting/apiTokens/create",
        Some("post_panel_api_setting_apiTokens_create"),
    ),
    (
        "post",
        "/panel/api/setting/apiTokens/delete/{id}",
        Some("post_panel_api_setting_apiTokens_delete_id"),
    ),
    (
        "post",
        "/panel/api/setting/apiTokens/setEnabled/{id}",
        Some("post_panel_api_setting_apiTokens_setEnabled_id"),
    ),
    (
        "post",
        "/panel/api/setting/testSmtp",
        Some("post_panel_api_setting_testSmtp"),
    ),
    (
        "post",
        "/panel/api/setting/testTgBot",
        Some("post_panel_api_setting_testTgBot"),
    ),
    (
        "get",
        "/panel/api/xray/getDefaultJsonConfig",
        Some("get_panel_api_xray_getDefaultJsonConfig"),
    ),
    (
        "get",
        "/panel/api/xray/getOutboundsTraffic",
        Some("get_panel_api_xray_getOutboundsTraffic"),
    ),
    (
        "get",
        "/panel/api/xray/getXrayResult",
        Some("get_panel_api_xray_getXrayResult"),
    ),
    ("post", "/panel/api/xray/", Some("post_panel_api_xray")),
    (
        "post",
        "/panel/api/xray/warp/{action}",
        Some("post_panel_api_xray_warp_action"),
    ),
    (
        "post",
        "/panel/api/xray/nord/{action}",
        Some("post_panel_api_xray_nord_action"),
    ),
    (
        "post",
        "/panel/api/xray/pia/{action}",
        Some("post_panel_api_xray_pia_action"),
    ),
    (
        "get",
        "/panel/api/xray/geodata/files",
        Some("get_panel_api_xray_geodata_files"),
    ),
    (
        "get",
        "/panel/api/xray/geodata/categories",
        Some("get_panel_api_xray_geodata_categories"),
    ),
    (
        "get",
        "/panel/api/xray/geodata/entries",
        Some("get_panel_api_xray_geodata_entries"),
    ),
    (
        "post",
        "/panel/api/xray/geodata/validate",
        Some("post_panel_api_xray_geodata_validate"),
    ),
    (
        "post",
        "/panel/api/xray/update",
        Some("post_panel_api_xray_update"),
    ),
    (
        "post",
        "/panel/api/xray/resetOutboundsTraffic",
        Some("post_panel_api_xray_resetOutboundsTraffic"),
    ),
    (
        "post",
        "/panel/api/xray/testOutbound",
        Some("post_panel_api_xray_testOutbound"),
    ),
    (
        "post",
        "/panel/api/xray/testOutbounds",
        Some("post_panel_api_xray_testOutbounds"),
    ),
    (
        "post",
        "/panel/api/xray/balancerStatus",
        Some("post_panel_api_xray_balancerStatus"),
    ),
    (
        "post",
        "/panel/api/xray/balancerOverride",
        Some("post_panel_api_xray_balancerOverride"),
    ),
    (
        "post",
        "/panel/api/xray/routeTest",
        Some("post_panel_api_xray_routeTest"),
    ),
    (
        "get",
        "/panel/api/xray/outbound-subs",
        Some("get_panel_api_xray_outbound_subs"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs",
        Some("post_panel_api_xray_outbound_subs"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs/{id}/refresh",
        Some("post_panel_api_xray_outbound_subs_id_refresh"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs/{id}/move",
        Some("post_panel_api_xray_outbound_subs_id_move"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs/{id}",
        Some("post_panel_api_xray_outbound_subs_id"),
    ),
    (
        "delete",
        "/panel/api/xray/outbound-subs/{id}",
        Some("delete_panel_api_xray_outbound_subs_id"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs/{id}/del",
        Some("post_panel_api_xray_outbound_subs_id_del"),
    ),
    (
        "post",
        "/panel/api/xray/outbound-subs/parse",
        Some("post_panel_api_xray_outbound_subs_parse"),
    ),
];

#[test]
fn sdk_covers_openapi_and_source_routes() {
    let openapi: Value =
        serde_json::from_str(include_str!("../../spec/3x-ui-v3.7.0.openapi.json")).unwrap();
    let documented = openapi["paths"]
        .as_object()
        .unwrap()
        .iter()
        .flat_map(|(path, item)| {
            item.as_object().into_iter().flat_map(move |operations| {
                operations
                    .iter()
                    .filter(|(_, operation)| {
                        operation["tags"].as_array().is_some_and(|tags| {
                            tags.iter().any(|tag| {
                                matches!(
                                    tag.as_str(),
                                    Some("Settings" | "API Tokens" | "Xray Settings")
                                )
                            })
                        })
                    })
                    .map(move |(method, operation)| {
                        (
                            method.as_str(),
                            path.as_str(),
                            operation["operationId"].as_str().unwrap(),
                        )
                    })
            })
        })
        .collect::<BTreeSet<_>>();
    let implemented_openapi = SDK_ROUTES
        .iter()
        .filter_map(|(method, path, operation)| {
            operation.map(|operation| (*method, *path, operation))
        })
        .collect::<BTreeSet<_>>();
    assert_eq!(documented.len(), 40);
    assert_eq!(documented, implemented_openapi);

    let snapshot: Value =
        serde_json::from_str(include_str!("../../spec/3x-ui-v3.7.0.settings-routes.json")).unwrap();
    let source = snapshot["routes"]
        .as_array()
        .unwrap()
        .iter()
        .map(|route| {
            (
                route["method"].as_str().unwrap(),
                route["path"].as_str().unwrap(),
            )
        })
        .collect::<BTreeSet<_>>();
    let implemented = SDK_ROUTES
        .iter()
        .map(|(method, path, _)| (*method, *path))
        .collect::<BTreeSet<_>>();
    assert_eq!(source.len(), 40);
    assert_eq!(source, implemented);
}