Skip to main content

singbox_driver/codec/
profile_document_codec.rs

1//! Pure sing-box JSON document inspection.
2
3use lurker_core_contract::identity::EngineId;
4use lurker_core_contract::profile_document::{DocumentDiagnosticSnapshot, DocumentValidation};
5use lurker_core_contract::profile_document_identity::{ProfileFormatId, ProfileSchemaVersion};
6use lurker_core_ports::error::PortError;
7use lurker_core_ports::profile_document_codec::{
8    ProfileDocumentCodecPort, ProfileDocumentCodecScope,
9};
10
11/// The native format identifier of the sing-box JSON profile document.
12pub const PROFILE_FORMAT: &str = "sing-box-json";
13/// The schema version of the sing-box JSON profile document.
14pub const PROFILE_SCHEMA_VERSION: u32 = 1;
15
16/// The neutral sing-box JSON document codec.
17#[derive(Clone, Copy, Debug, Default)]
18pub struct SingBoxProfileDocumentCodec;
19
20impl ProfileDocumentCodecPort for SingBoxProfileDocumentCodec {
21    fn scope(&self) -> ProfileDocumentCodecScope {
22        ProfileDocumentCodecScope {
23            engine_id: EngineId::sing_box(),
24            format_id: ProfileFormatId::new(PROFILE_FORMAT)
25                .expect("static sing-box format ID is valid"),
26            schema_version: ProfileSchemaVersion::new(PROFILE_SCHEMA_VERSION)
27                .expect("sing-box schema version is positive"),
28        }
29    }
30
31    fn inspect(&self, raw_bytes: &[u8]) -> Result<DocumentValidation, PortError> {
32        let value: serde_json::Value = match serde_json::from_slice(raw_bytes) {
33            Ok(value) => value,
34            Err(error) => {
35                return Ok(DocumentValidation::Invalid {
36                    diagnostics: vec![DocumentDiagnosticSnapshot {
37                        line: Some(error.line()),
38                        column: Some(error.column()),
39                        message: "invalid sing-box JSON syntax".to_owned(),
40                    }],
41                });
42            }
43        };
44
45        if value.is_object() {
46            Ok(DocumentValidation::Valid)
47        } else {
48            Ok(DocumentValidation::Invalid {
49                diagnostics: vec![DocumentDiagnosticSnapshot {
50                    line: None,
51                    column: None,
52                    message: "sing-box configuration root must be a JSON object".to_owned(),
53                }],
54            })
55        }
56    }
57}
58
59#[cfg(test)]
60#[path = "profile_document_codec_tests.rs"]
61mod tests;