framework-web 26.8.150

lingting framework
Documentation
use crate::{WebError, WebRequest};
use anyhow::{Result, anyhow};
use bytes::Bytes;
use framework_core::MultiStringValue;
use serde_json::{Map, Value};
use std::future::Future;
use std::sync::{Arc, OnceLock};

pub struct WebContext {
    request: Arc<WebRequest>,
    body_json: OnceLock<Value>,
    query_json: OnceLock<Value>,
}

impl WebContext {
    pub fn new(request: Arc<WebRequest>) -> Self {
        Self {
            request,
            body_json: OnceLock::new(),
            query_json: OnceLock::new(),
        }
    }

    pub fn request(&self) -> &WebRequest {
        &self.request
    }

    pub fn request_arc(&self) -> Arc<WebRequest> {
        Arc::clone(&self.request)
    }

    pub fn query(&self) -> &MultiStringValue {
        &self.request.query
    }

    pub fn body(&self) -> Bytes {
        self.request.body.clone()
    }

    pub fn body_json(&self) -> Result<&Value> {
        if let Some(value) = self.body_json.get() {
            return Ok(value);
        }

        let value = serde_json::from_slice::<Value>(&self.request.body)
            .map_err(|error| WebError::parameter("请求体不是有效的 JSON", error))?;
        self.body_json
            .set(value)
            .map_err(|_| anyhow!("请求体 JSON 缓存设置失败"))?;
        self.body_json
            .get()
            .ok_or_else(|| anyhow!("请求体 JSON 缓存读取失败"))
    }

    pub fn query_json(&self) -> Result<&Value> {
        if let Some(value) = self.query_json.get() {
            return Ok(value);
        }

        let mut object = Map::new();
        self.request.query.for_each(|name, values| {
            let value = if values.len() == 1 {
                Value::String(values[0].clone())
            } else {
                Value::Array(
                    values
                        .iter()
                        .map(|item| Value::String(item.clone()))
                        .collect(),
                )
            };
            object.insert(name.clone(), value);
        });
        self.query_json
            .set(Value::Object(object))
            .map_err(|_| anyhow!("查询参数 JSON 缓存设置失败"))?;
        self.query_json
            .get()
            .ok_or_else(|| anyhow!("查询参数 JSON 缓存读取失败"))
    }
}

tokio::task_local! {
    static WEB_CONTEXT: Arc<WebContext>;
}

pub async fn scope_web<F>(context: Arc<WebContext>, future: F) -> F::Output
where
    F: Future,
{
    WEB_CONTEXT.scope(context, future).await
}

pub fn use_web() -> Result<Arc<WebContext>> {
    WEB_CONTEXT
        .try_with(Arc::clone)
        .map_err(|error| anyhow!("当前调用不在 Web 上下文作用域内:{error}"))
}