convd 2.6.12

A profile converter for surge/clash.
Documentation
pub mod subscription {
    use crate::server::app_state::AppState;
    use crate::server::response::{ApiError, ApiResponse};
    use crate::server::router::{OptionalScheme, parse_query};
    use axum::extract::{Path, RawQuery, State};
    use axum_extra::TypedHeader;
    use axum_extra::extract::Host;
    use axum_extra::headers::UserAgent;
    use convertor::config::client_config::ProxyClient;
    use convertor::config::provider_config::Provider;
    use convertor::provider_api::BosLifeLogs;
    use convertor::url::url_builder::UrlBuilder;
    use convertor::url::url_result::UrlResult;
    use std::sync::Arc;

    #[allow(unused)]
    pub async fn subscription(
        Path((client, provider)): Path<(ProxyClient, Provider)>,
        Host(host): Host,
        scheme: Option<OptionalScheme>,
        TypedHeader(user_agent): TypedHeader<UserAgent>,
        State(state): State<Arc<AppState>>,
        RawQuery(query_string): RawQuery,
    ) -> Result<ApiResponse<UrlResult>, ApiError> {
        let query = parse_query(state.as_ref(), scheme, host.as_str(), query_string)?.check_for_subscription()?;
        let url_builder = UrlBuilder::from_convertor_query(query, &state.config.secret, client, provider)?;
        let api = state.api_map.get(&provider).ok_or_else(|| ApiError::NoSubProvider)?;
        let raw_profile = api.get_raw_profile(client, user_agent).await?;
        let policies = match client {
            ProxyClient::Surge => {
                let mut profile = state
                    .surge_service
                    .try_get_profile(url_builder.clone(), raw_profile)
                    .await?;
                std::mem::take(&mut profile.sorted_policy_list)
            }
            ProxyClient::Clash => {
                let mut profile = state
                    .clash_service
                    .try_get_profile(url_builder.clone(), raw_profile)
                    .await?;
                std::mem::take(&mut profile.sorted_policy_list)
            }
        };
        let raw_url = url_builder.build_raw_url();
        let raw_profile_url = url_builder.build_raw_profile_url()?;
        let profile_url = url_builder.build_profile_url()?;
        let sub_logs_url = url_builder.build_sub_logs_url()?;
        let rule_providers_url = policies
            .iter()
            .map(|policy| url_builder.build_rule_provider_url(policy))
            .collect::<color_eyre::Result<Vec<_>, _>>()?;
        let url_result = UrlResult {
            raw_url,
            raw_profile_url,
            profile_url,
            sub_logs_url,
            rule_providers_url,
        };
        Ok(ApiResponse::ok(url_result))
    }

    pub async fn sub_logs(
        Path(provider): Path<Provider>,
        Host(host): Host,
        scheme: Option<OptionalScheme>,
        State(state): State<Arc<AppState>>,
        RawQuery(query_string): RawQuery,
    ) -> Result<ApiResponse<BosLifeLogs>, ApiError> {
        parse_query(state.as_ref(), scheme, host.as_str(), query_string)?.check_for_sub_logs(&state.config.secret)?;
        let api = state.api_map.get(&provider).ok_or_else(|| ApiError::NoSubProvider)?;
        match api.get_sub_logs().await {
            Ok(sub_logs) => Ok(ApiResponse::ok(sub_logs)),
            Err(err) => Ok(ApiResponse::error_with_message(format!("{err:?}"))),
        }
    }
}