neutralts/bif/
parse_bif_debug.rs

1#![doc = include_str!("../../doc/bif-debug.md")]
2
3use crate::{bif::constants::*, bif::Bif, bif::BifError, constants::*, utils::*};
4use std::fs;
5use std::path::Path;
6use std::time::{Duration, SystemTime};
7
8impl<'a> Bif<'a> {
9    /*
10        {:debug; data->key :}
11    */
12    pub(crate) fn parse_bif_debug(&mut self) -> Result<(), BifError> {
13        if self.mod_scope {
14            return Err(self.bif_error(BIF_ERROR_MODIFIER_NOT_ALLOWED));
15        }
16
17        let debug_enable = self.debug_enable();
18
19        if self.mod_negate {
20            if debug_enable {
21                self.out = UNPRINTABLE.to_string();
22            } else {
23                self.out = EMPTY_STRING;
24            }
25
26            return Ok(());
27        }
28
29        if !debug_enable {
30            self.out = EMPTY_STRING;
31            if self.mod_negate {
32                return Ok(());
33            } else {
34                return Err(self.bif_error(
35                    "Debug is disabled. Remember to remove the bif debug in production.",
36                ));
37            }
38        }
39
40        self.extract_params_code(true);
41
42        let mut schema = &self.shared.schema;
43        let mut key_name = self.code.clone();
44        if key_name.starts_with("local::") {
45            key_name = key_name.strip_prefix("local::").unwrap_or("").to_string();
46            schema = &self.shared.schema["__indir"][&self.inherit.indir];
47        }
48
49        let k = if self.code.is_empty() {
50            self.out = VERSION.to_string();
51            return Ok(());
52        } else if key_name == "full-schema" {
53            "".to_string()
54        } else {
55            format!("/{}", key_name).replace(BIF_ARRAY, "/")
56        };
57
58        self.out = match schema.pointer(&k) {
59            Some(value) => match serde_json::to_string_pretty(value) {
60                Ok(json_str) => json_str,
61                Err(e) => format!("Error formatting JSON: {}", e),
62            },
63            None => format!("Undefined: '{}'", self.code),
64        };
65
66        if self.mod_filter {
67            // unescape_chars for prevent double encoding
68            let tmp = unescape_chars(&self.out, true);
69            self.out = escape_chars(&tmp, true).into_owned();
70        }
71
72        Ok(())
73    }
74
75    /// check if debug is enabled
76    pub(crate) fn debug_enable(&self) -> bool {
77        if self.shared.debug_file.is_empty() {
78            return false;
79        }
80
81        let path = Path::new(&self.shared.debug_file);
82
83        if !path.exists() || !path.is_file() {
84            return false;
85        }
86
87        let metadata = match fs::metadata(path) {
88            Ok(md) => md,
89            Err(_) => return false,
90        };
91
92        let modified_time = match metadata.modified() {
93            Ok(time) => time,
94            Err(_) => return false,
95        };
96
97        let now = SystemTime::now();
98
99        match now.duration_since(modified_time) {
100            Ok(duration) => duration < Duration::from_secs(self.shared.debug_expire),
101            Err(_) => false,
102        }
103    }
104}
105
106#[cfg(test)]
107#[path = "parse_bif_debug_tests.rs"]
108mod tests;