NAC_Blockchain/charter-service/src/main.rs

259 lines
8.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Charter HTTP Service - NAC L2层 Charter编译器HTTP服务
// 将 charter-compiler 包装为 HTTP API 服务
use actix_web::{web, App, HttpServer, HttpResponse, middleware};
use serde::{Deserialize, Serialize};
use std::process::Command;
use std::env;
use std::fs;
use std::path::Path;
use chrono::Utc;
#[derive(Deserialize)]
struct CompileRequest {
/// Charter 源代码
source: String,
/// 优化级别 (0-3)
#[serde(default = "default_optimization")]
optimization: u8,
/// 是否生成调试信息
#[serde(default)]
debug: bool,
}
fn default_optimization() -> u8 { 2 }
#[derive(Serialize)]
struct CompileResponse {
success: bool,
bytecode: Option<String>,
bytecode_size: Option<usize>,
error: Option<String>,
elapsed_ms: u64,
timestamp: String,
}
#[derive(Deserialize)]
struct CheckRequest {
source: String,
}
#[derive(Serialize)]
struct CheckResponse {
success: bool,
valid: bool,
errors: Vec<String>,
warnings: Vec<String>,
timestamp: String,
}
#[derive(Serialize)]
struct HealthResponse {
status: String,
service: String,
version: String,
layer: String,
protocol: String,
timestamp: String,
}
/// 健康检查
async fn health() -> HttpResponse {
HttpResponse::Ok().json(HealthResponse {
status: "running".to_string(),
service: "nac-charter-service".to_string(),
version: "1.0.0".to_string(),
layer: "L2".to_string(),
protocol: "Charter".to_string(),
timestamp: Utc::now().to_rfc3339(),
})
}
/// 编译 Charter 源代码
async fn compile(req: web::Json<CompileRequest>) -> HttpResponse {
let start = std::time::Instant::now();
// 写入临时文件
let tmp_dir = std::env::temp_dir();
let input_path = tmp_dir.join(format!("charter_input_{}.ch", std::process::id()));
let output_path = tmp_dir.join(format!("charter_output_{}.nvm", std::process::id()));
if let Err(e) = fs::write(&input_path, &req.source) {
return HttpResponse::InternalServerError().json(CompileResponse {
success: false,
bytecode: None,
bytecode_size: None,
error: Some(format!("写入临时文件失败: {}", e)),
elapsed_ms: start.elapsed().as_millis() as u64,
timestamp: Utc::now().to_rfc3339(),
});
}
// 调用 charter 编译器
let charter_bin = env::var("CHARTER_BIN").unwrap_or_else(|_| "/opt/nac/bin/charter".to_string());
let mut cmd = Command::new(&charter_bin);
cmd.arg("compile")
.arg("-i").arg(&input_path)
.arg("-o").arg(&output_path)
.arg("-O").arg(req.optimization.to_string());
if req.debug {
cmd.arg("--debug");
}
let output = match cmd.output() {
Ok(o) => o,
Err(e) => {
let _ = fs::remove_file(&input_path);
return HttpResponse::InternalServerError().json(CompileResponse {
success: false,
bytecode: None,
bytecode_size: None,
error: Some(format!("执行编译器失败: {}", e)),
elapsed_ms: start.elapsed().as_millis() as u64,
timestamp: Utc::now().to_rfc3339(),
});
}
};
let _ = fs::remove_file(&input_path);
let elapsed = start.elapsed().as_millis() as u64;
if output.status.success() {
// 读取输出字节码
match fs::read(&output_path) {
Ok(bytecode) => {
let _ = fs::remove_file(&output_path);
let size = bytecode.len();
let hex_bytecode = hex::encode(&bytecode);
log::info!("Charter编译成功字节码大小: {} 字节,耗时: {}ms", size, elapsed);
HttpResponse::Ok().json(CompileResponse {
success: true,
bytecode: Some(hex_bytecode),
bytecode_size: Some(size),
error: None,
elapsed_ms: elapsed,
timestamp: Utc::now().to_rfc3339(),
})
}
Err(e) => {
HttpResponse::InternalServerError().json(CompileResponse {
success: false,
bytecode: None,
bytecode_size: None,
error: Some(format!("读取字节码失败: {}", e)),
elapsed_ms: elapsed,
timestamp: Utc::now().to_rfc3339(),
})
}
}
} else {
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let error_msg = if !stderr.is_empty() { stderr } else { stdout };
log::warn!("Charter编译失败: {}", error_msg);
HttpResponse::Ok().json(CompileResponse {
success: false,
bytecode: None,
bytecode_size: None,
error: Some(error_msg),
elapsed_ms: elapsed,
timestamp: Utc::now().to_rfc3339(),
})
}
}
/// 语法检查
async fn check(req: web::Json<CheckRequest>) -> HttpResponse {
let tmp_dir = std::env::temp_dir();
let input_path = tmp_dir.join(format!("charter_check_{}.ch", std::process::id()));
if let Err(e) = fs::write(&input_path, &req.source) {
return HttpResponse::InternalServerError().json(CheckResponse {
success: false,
valid: false,
errors: vec![format!("写入临时文件失败: {}", e)],
warnings: vec![],
timestamp: Utc::now().to_rfc3339(),
});
}
let charter_bin = env::var("CHARTER_BIN").unwrap_or_else(|_| "/opt/nac/bin/charter".to_string());
let output = Command::new(&charter_bin)
.arg("check")
.arg("-i").arg(&input_path)
.output();
let _ = fs::remove_file(&input_path);
match output {
Ok(o) => {
let valid = o.status.success();
let stderr = String::from_utf8_lossy(&o.stderr).to_string();
let stdout = String::from_utf8_lossy(&o.stdout).to_string();
let errors = if !valid {
let msg = if !stderr.is_empty() { stderr } else { stdout };
msg.lines().map(|l| l.to_string()).filter(|l| !l.is_empty()).collect()
} else {
vec![]
};
HttpResponse::Ok().json(CheckResponse {
success: true,
valid,
errors,
warnings: vec![],
timestamp: Utc::now().to_rfc3339(),
})
}
Err(e) => HttpResponse::InternalServerError().json(CheckResponse {
success: false,
valid: false,
errors: vec![format!("执行检查器失败: {}", e)],
warnings: vec![],
timestamp: Utc::now().to_rfc3339(),
}),
}
}
/// 版本信息
async fn version() -> HttpResponse {
let charter_bin = env::var("CHARTER_BIN").unwrap_or_else(|_| "/opt/nac/bin/charter".to_string());
let output = Command::new(&charter_bin).arg("version").output();
let version_info = match output {
Ok(o) => String::from_utf8_lossy(&o.stdout).trim().to_string(),
Err(_) => "Charter Compiler 1.0.0 (NAC L2)".to_string(),
};
HttpResponse::Ok().json(serde_json::json!({
"service": "nac-charter-service",
"layer": "L2",
"protocol": "Charter",
"compiler_version": version_info,
"timestamp": Utc::now().to_rfc3339()
}))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
let host = env::var("CHARTER_HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
let port: u16 = env::var("CHARTER_PORT")
.unwrap_or_else(|_| "9555".to_string())
.parse()
.unwrap_or(9555);
log::info!("NAC Charter HTTP Service 启动中...");
log::info!("监听地址: {}:{}", host, port);
log::info!("Charter 编译器: {}", env::var("CHARTER_BIN").unwrap_or_else(|_| "/opt/nac/bin/charter".to_string()));
HttpServer::new(|| {
App::new()
.route("/health", web::get().to(health))
.route("/compile", web::post().to(compile))
.route("/check", web::post().to(check))
.route("/version", web::get().to(version))
})
.bind(format!("{}:{}", host, port))?
.run()
.await
}