noxue_compiler/
lang.rs

1use serde::{Deserialize, Serialize};
2
3use crate::exec::{exec, Output};
4
5#[derive(Serialize, Deserialize)]
6struct RunTpl {
7    image: String,            // docker iamge 名字
8    file: String,             // 代码要保存的文件路径
9    prev_cmd: Option<String>, // 写入之前执行的命令,主要用于设置一些变量,给cmd中的命令使用
10    cmd: String,              // 保存代码之后要执行的命令
11    timeout: i32,             // 容器执行超时时间
12    memory: String,           // 允许容器使用的内存,例如:20MB
13    cpuset: String,           // 使用的cpu核心
14}
15
16/// 根据语言选择特定的执行模板来编译运行代码
17///
18/// ## 参数
19///
20/// * `tpl` - 指定的运行模板内容,使用模板更加方便扩展任意编程语言
21/// * `code` - 要编译的代码
22/// * `input` - 标准输入,用户给程序的输入数据
23///
24/// ## 模板格式:
25/// ```json
26/// {
27///     "image": "gcc",  // 要使用那个docker imgage
28///     "file": "test.c", // 代码保存的文件名
29///     "cmd": "gcc test.c -o test\nif test -f \"./test\"; then\n./test\nfi",  // 代码保存后要执行的命令
30///     "timeout": 10, // 超时时间,是从启动docker开始计算
31///     "memory": "20MB", // 允许占用的内存
32///     "cpuset":"0-3", // 使用的cpu核心
33/// }
34/// ```
35///
36/// ## 调用方式
37///
38/// ```
39/// use noxue_compiler::lang::run;
40/// fn main(){
41///     let code = r#"
42/// #include <stdio.h>
43///
44/// int main(){
45///     printf("hello");
46///     return 0;
47/// }"#;
48///     let tpl = r#"
49/// {
50/// "image": "gcc",
51/// "file": "test.c",
52/// "cmd": "gcc test.c -o test\nif test -f \"./test\"; then\n./test\nfi",
53/// "timeout": 10,
54/// "memory":"20MB",
55/// "cpuset":"0-3"
56/// }
57/// "#;
58///     let out = run(tpl, code, "");
59///     assert_eq!(out.unwrap().stdout, "hello");
60/// }
61/// ```
62///
63pub fn run(tpl: &str, code: &str, input: &str) -> Result<Output, String> {
64    /***
65     * 根据参数生成命令
66     *
67     * 1. 根据模板json数据,解析成结构体 RunTpl
68     * 2. 拼接 写入文件 编译运行文件 命令
69     * 3. 调用exec函数执行 以上命令
70     */
71
72    let run_tpl: RunTpl = match serde_json::from_str(&tpl) {
73        Ok(v) => v,
74        Err(e) => {
75            return Err(format!("运行模板不正确:{}", e));
76        }
77    };
78
79    // 开始结束字符串,随机生成防止内容中包含该字符串导致输入结束
80    let eof = format!("{}", uuid::Uuid::new_v4());
81
82    let cmd = format!(
83        "{}\ncat>{}<<\\{}\n{}\n{}\n{}",
84        if let Some(v) = run_tpl.prev_cmd {
85            v
86        } else {
87            "".to_owned()
88        },
89        run_tpl.file,
90        eof,
91        code,
92        eof,
93        run_tpl.cmd
94    );
95
96    exec(
97        &run_tpl.image,
98        &cmd,
99        input,
100        run_tpl.timeout,
101        &run_tpl.memory,
102        &run_tpl.cpuset,
103    )
104}