//! NAC CNNL HTTP 服务 //! //! 将 CNNL 编译器封装为 RESTful HTTP API,供立法 IDE、宪法沙箱等工具调用。 //! //! # 接口列表 //! - POST /api/v1/compile - 编译 CNNL 源代码 //! - POST /api/v1/parse - 解析 CNNL 源代码(仅返回 AST) //! - POST /api/v1/validate - 验证 CNNL 语法(不生成字节码) //! - GET /api/v1/health - 健康检查 //! - GET /api/v1/version - 版本信息 use actix_web::{web, App, HttpServer, HttpResponse, Responder}; use serde::{Deserialize, Serialize}; use std::time::Instant; use chrono::Utc; use log::{info, warn}; // ============================================================ // 请求/响应数据结构 // ============================================================ /// 编译请求 #[derive(Debug, Deserialize)] pub struct CompileRequest { /// CNNL 源代码 pub source: String, /// 是否启用形式化验证 #[serde(default)] pub enable_verification: bool, /// 是否生成调试信息 #[serde(default)] pub debug_info: bool, /// 是否生成宪法状态文件 #[serde(default = "default_true")] pub generate_state: bool, } fn default_true() -> bool { true } /// 解析请求 #[derive(Debug, Deserialize)] pub struct ParseRequest { /// CNNL 源代码 pub source: String, } /// 验证请求 #[derive(Debug, Deserialize)] pub struct ValidateRequest { /// CNNL 源代码 pub source: String, } /// 通用 API 响应 #[derive(Debug, Serialize)] pub struct ApiResponse { pub success: bool, pub data: Option, pub error: Option, pub timestamp: String, pub duration_ms: u64, } impl ApiResponse { pub fn ok(data: T, duration_ms: u64) -> Self { Self { success: true, data: Some(data), error: None, timestamp: Utc::now().to_rfc3339(), duration_ms, } } pub fn err(msg: String, duration_ms: u64) -> ApiResponse { ApiResponse { success: false, data: None, error: Some(msg), timestamp: Utc::now().to_rfc3339(), duration_ms, } } } /// 编译结果 #[derive(Debug, Serialize)] pub struct CompileResult { /// 字节码(hex 编码) pub bytecode_hex: String, /// 字节码长度(字节) pub bytecode_size: usize, /// 宪法状态 JSON(可选) pub state_json: Option, /// 条款数量 pub clause_count: usize, /// 条款摘要 pub clauses: Vec, } /// 解析结果 #[derive(Debug, Serialize)] pub struct ParseResult { /// 条款数量 pub clause_count: usize, /// 测试块数量 pub test_count: usize, /// 条款详情 pub clauses: Vec, } /// 验证结果 #[derive(Debug, Serialize)] pub struct ValidateResult { /// 是否有效 pub valid: bool, /// 错误列表 pub errors: Vec, /// 警告列表 pub warnings: Vec, /// 条款数量 pub clause_count: usize, } /// 条款摘要 #[derive(Debug, Serialize)] pub struct ClauseSummary { pub id: String, pub level: String, pub title: String, pub parameter_count: usize, pub predicate_count: usize, pub obligation_count: usize, } /// 条款详情 #[derive(Debug, Serialize)] pub struct ClauseDetail { pub id: String, pub level: String, pub title: String, pub name: Option, pub version: Option, pub description: Option, pub depends_on: Vec, pub parameters: Vec, pub predicates: Vec, pub obligations: Vec, } /// 参数详情 #[derive(Debug, Serialize)] pub struct ParameterDetail { pub name: String, pub type_name: String, pub value: String, pub description: Option, } /// 谓词详情 #[derive(Debug, Serialize)] pub struct PredicateDetail { pub name: String, pub params: Vec<(String, String)>, pub return_type: String, } /// 义务详情 #[derive(Debug, Serialize)] pub struct ObligationDetail { pub name: String, pub frequency: String, pub enforcer: String, pub penalty: String, pub description: Option, } /// 版本信息 #[derive(Debug, Serialize)] pub struct VersionInfo { pub service: String, pub version: String, pub compiler_version: String, pub build_time: String, } /// 健康状态 #[derive(Debug, Serialize)] pub struct HealthStatus { pub status: String, pub uptime_seconds: u64, } // ============================================================ // 全局状态 // ============================================================ pub struct AppState { pub start_time: Instant, } // ============================================================ // API 处理函数 // ============================================================ /// POST /api/v1/compile - 编译 CNNL 源代码 async fn handle_compile( _state: web::Data, req: web::Json, ) -> impl Responder { let start = Instant::now(); info!("收到编译请求,源代码长度: {} 字节", req.source.len()); let options = cnnl_compiler::CompilerOptions { enable_verification: req.enable_verification, debug_info: req.debug_info, output_dir: None, generate_state_file: req.generate_state, }; match cnnl_compiler::compile(&req.source, options) { Ok(result) => { let bytecode_hex = hex::encode(&result.bytecode); let state_json = result.state_json.as_ref().and_then(|s| { serde_json::from_str(s).ok() }); let clauses: Vec = result.ast.clauses.iter().map(|c| ClauseSummary { id: c.id.clone(), level: c.level.to_string(), title: c.title.clone(), parameter_count: c.parameters.len(), predicate_count: c.predicates.len(), obligation_count: c.obligations.len(), }).collect(); let clause_count = clauses.len(); let compile_result = CompileResult { bytecode_hex, bytecode_size: result.bytecode.len(), state_json, clause_count, clauses, }; let duration_ms = start.elapsed().as_millis() as u64; info!("编译成功,字节码大小: {} 字节,耗时: {}ms", compile_result.bytecode_size, duration_ms); HttpResponse::Ok().json(ApiResponse::ok(compile_result, duration_ms)) } Err(e) => { let duration_ms = start.elapsed().as_millis() as u64; warn!("编译失败: {}", e); HttpResponse::BadRequest().json(ApiResponse::::err( format!("{}", e), duration_ms, )) } } } /// POST /api/v1/parse - 解析 CNNL 源代码 async fn handle_parse( _state: web::Data, req: web::Json, ) -> impl Responder { let start = Instant::now(); info!("收到解析请求,源代码长度: {} 字节", req.source.len()); match cnnl_compiler::Parser::new(&req.source) { Ok(mut parser) => { match parser.parse() { Ok(ast) => { let clauses: Vec = ast.clauses.iter().map(|c| ClauseDetail { id: c.id.clone(), level: c.level.to_string(), title: c.title.clone(), name: c.name.clone(), version: c.version.clone(), description: c.description.clone(), depends_on: c.depends_on.clone(), parameters: c.parameters.iter().map(|p| ParameterDetail { name: p.name.clone(), type_name: p.ty.to_string(), value: format!("{}", p.value), description: p.description.clone(), }).collect(), predicates: c.predicates.iter().map(|pred| PredicateDetail { name: pred.name.clone(), params: pred.params.iter().map(|(n, t)| (n.clone(), t.to_string())).collect(), return_type: pred.return_type.to_string(), }).collect(), obligations: c.obligations.iter().map(|o| ObligationDetail { name: o.name.clone(), frequency: format!("{:?}", o.frequency), enforcer: o.enforcer.clone(), penalty: o.penalty.clone(), description: o.description.clone(), }).collect(), }).collect(); let test_count = ast.tests.len(); let clause_count = clauses.len(); let parse_result = ParseResult { clause_count, test_count, clauses, }; let duration_ms = start.elapsed().as_millis() as u64; info!("解析成功,条款数: {},测试块数: {},耗时: {}ms", clause_count, test_count, duration_ms); HttpResponse::Ok().json(ApiResponse::ok(parse_result, duration_ms)) } Err(e) => { let duration_ms = start.elapsed().as_millis() as u64; warn!("解析失败: {}", e); HttpResponse::BadRequest().json(ApiResponse::::err( format!("{}", e), duration_ms, )) } } } Err(e) => { let duration_ms = start.elapsed().as_millis() as u64; warn!("词法分析失败: {}", e); HttpResponse::BadRequest().json(ApiResponse::::err( format!("{}", e), duration_ms, )) } } } /// POST /api/v1/validate - 验证 CNNL 语法 async fn handle_validate( _state: web::Data, req: web::Json, ) -> impl Responder { let start = Instant::now(); info!("收到验证请求,源代码长度: {} 字节", req.source.len()); let mut errors = Vec::new(); let warnings = Vec::new(); let mut clause_count = 0; match cnnl_compiler::Parser::new(&req.source) { Ok(mut parser) => { match parser.parse() { Ok(ast) => { clause_count = ast.clauses.len(); // 语义分析 let mut analyzer = cnnl_compiler::semantic::SemanticAnalyzer::new(); if let Err(e) = analyzer.analyze(&ast) { errors.push(format!("语义错误: {}", e)); } } Err(e) => { errors.push(format!("语法错误: {}", e)); } } } Err(e) => { errors.push(format!("词法错误: {}", e)); } } let valid = errors.is_empty(); let validate_result = ValidateResult { valid, errors, warnings, clause_count, }; let duration_ms = start.elapsed().as_millis() as u64; info!("验证完成,有效: {},耗时: {}ms", valid, duration_ms); HttpResponse::Ok().json(ApiResponse::ok(validate_result, duration_ms)) } /// GET /api/v1/health - 健康检查 async fn handle_health(state: web::Data) -> impl Responder { let uptime_seconds = state.start_time.elapsed().as_secs(); let health = HealthStatus { status: "ok".to_string(), uptime_seconds, }; HttpResponse::Ok().json(ApiResponse::ok(health, 0)) } /// GET /api/v1/version - 版本信息 async fn handle_version(_state: web::Data) -> impl Responder { let version = VersionInfo { service: "nac-cnnl-service".to_string(), version: env!("CARGO_PKG_VERSION").to_string(), compiler_version: "0.1.0".to_string(), build_time: env!("CARGO_PKG_VERSION").to_string(), }; HttpResponse::Ok().json(ApiResponse::ok(version, 0)) } // ============================================================ // 根路径 - API 文档页面 // ============================================================ async fn handle_root() -> impl Responder { let html = r#" NAC CNNL 编译服务
宪政神经网络语言编译服务
v0.1.0 · 运行中

API 端点

POST
/api/v1/compile
编译 CNNL 源代码,生成 NVM 字节码和宪法状态文件
POST
/api/v1/parse
解析 CNNL 源代码,返回抽象语法树(AST)
POST
/api/v1/validate
验证 CNNL 语法正确性,不生成字节码
GET
/api/v1/health
服务健康检查,返回运行状态和运行时长
GET
/api/v1/version
服务版本信息

快速示例

# 编译一个 CNNL 条款 curl -X POST https://cnnl.newassetchain.io/api/v1/compile \ -H "Content-Type: application/json" \ -d '{ "source": "clause XTZH_GOLD_COVERAGE {\n level: eternal\n title: \"黄金储备覆盖率底线\"\n parameter XTZH_GOLD_COVERAGE_MIN: f64 = 1.25\n}", "generate_state": true }'

服务信息

服务名称
nac-cnnl-service
编译器版本
CNNL v0.1.0
目标虚拟机
NVM (NAC VM)
协议
HTTPS / TLS 1.3
"#; HttpResponse::Ok() .content_type("text/html; charset=utf-8") .body(html) } // ============================================================ // 主函数 // ============================================================ #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); let host = std::env::var("CNNL_HOST").unwrap_or_else(|_| "0.0.0.0".to_string()); let port: u16 = std::env::var("CNNL_PORT") .unwrap_or_else(|_| "8080".to_string()) .parse() .unwrap_or(8080); info!("NAC CNNL HTTP 服务启动中..."); info!("监听地址: {}:{}", host, port); let app_state = web::Data::new(AppState { start_time: Instant::now(), }); HttpServer::new(move || { App::new() .app_data(app_state.clone()) .app_data(web::JsonConfig::default().limit(1024 * 1024)) // 1MB 请求体限制 // API 路由 .route("/", web::get().to(handle_root)) .route("/api/v1/compile", web::post().to(handle_compile)) .route("/api/v1/parse", web::post().to(handle_parse)) .route("/api/v1/validate", web::post().to(handle_validate)) .route("/api/v1/health", web::get().to(handle_health)) .route("/api/v1/version", web::get().to(handle_version)) }) .bind(format!("{}:{}", host, port))? .run() .await }