e_utils/system/cmd/
rlog.rs

1use once_cell::sync::Lazy;
2use regex::Regex;
3
4use super::CmdResult;
5use crate::AnyRes as _;
6use crate::Result;
7
8/// 使用 once_cell 来避免每次调用都重新编译正则表达式
9pub static REGEX_R_LOG: Lazy<Regex> = Lazy::new(|| Regex::new(r"R<(?s:.*?)>R").unwrap());
10
11#[inline]
12/// 解析 rlog 字符串
13pub fn parse_rlog_str(stdout: String) -> Result<String> {
14  if let Some(plog) = parse_rlog(&stdout) {
15    let plog = plog?;
16    if !plog.status {
17      return Err(plog.content.into());
18    }
19    Ok(plog.content)
20  } else {
21    Ok(stdout)
22  }
23}
24#[inline]
25/// 解析 rlog 字符串
26pub fn parse_rlog(stdout: &str) -> Option<Result<CmdResult<serde_json::Value>>> {
27  if let Some(cap) = REGEX_R_LOG.find_iter(stdout).last() {
28    let json_str = &stdout[cap.start() + 2..cap.end() - 2];
29    Some(serde_json::from_str::<CmdResult<serde_json::Value>>(json_str).any())
30  } else {
31    None
32  }
33}
34#[inline]
35/// 解析 rlog 字符串并验证
36pub fn parse_and_validate_log(stdout: &str) -> Result<String> {
37  match parse_rlog(stdout) {
38    Some(Ok(res)) if res.status => Ok(res.content.to_string()),
39    Some(Ok(res)) => Err(res.content.into()),
40    Some(Err(e)) => Err(e.to_string().into()),
41    None => Err(format!("{}...", &crate::share::get_safe_preview(stdout, 200)).into()),
42  }
43}
44
45/// 异步解析 rlog 字符串并验证
46#[cfg(feature = "tokio")]
47#[inline]
48pub async fn a_parse_and_validate_log(stdout: &str) -> crate::Result<String> {
49  use crate::share::get_safe_preview;
50  use memchr::memmem::find;
51
52  // 克隆 stdout 以避免生命周期问题
53  let stdout_clone = stdout.to_owned();
54
55  // 在线程池中执行搜索和解析
56  let result = tokio::task::spawn_blocking(move || {
57    if let Some(start_pos) = find(stdout_clone.as_bytes(), b"R<") {
58      if let Some(cap) = REGEX_R_LOG.find_at(&stdout_clone, start_pos) {
59        let json_str = &stdout_clone[cap.start() + 2..cap.end() - 2];
60        // 在同一个闭包内解析 JSON
61        match serde_json::from_str::<CmdResult<serde_json::Value>>(json_str) {
62          Ok(res) if res.status => Ok(res.content),
63          Ok(res) => Err(res.content),
64          Err(_) => Err(format!("{}...", &get_safe_preview(stdout_clone, 100))),
65        }
66      } else {
67        Err("Cannot find R<...>R tag".into())
68      }
69    } else {
70      Err("Cannot find start position R<".into())
71    }
72  })
73  .await
74  .map_err(|_| "Thread error: a_parse_and_validate_log")??;
75  Ok(result)
76}