#js #sandbox #macro #procedural #javascript #proc-macro #applications

js-sandbox-macros

为js-sandbox编写的过程宏

3个版本

0.2.0-rc.22023年9月12日
0.2.0-rc.12023年4月2日
0.2.0-rc.02022年2月28日

过程宏中排名第1563

Download history 55/week @ 2024-03-13 55/week @ 2024-03-20 99/week @ 2024-03-27 144/week @ 2024-04-03 111/week @ 2024-04-10 69/week @ 2024-04-17 51/week @ 2024-04-24 122/week @ 2024-05-01 115/week @ 2024-05-08 128/week @ 2024-05-15 169/week @ 2024-05-22 58/week @ 2024-05-29 92/week @ 2024-06-05 100/week @ 2024-06-12 84/week @ 2024-06-19 49/week @ 2024-06-26

每月下载量330
3个包中使用(通过js-sandbox-ios

Zlib 许可证

7KB
179

js-sandbox

crates.io docs.rs

js-sandbox 是一个Rust库,用于在安全沙盒中执行从Rust调用的JavaScript代码。它基于Deno项目,并使用serde_json进行序列化。

该库的主要重点是 将JS作为脚本语言嵌入到Rust中。它不提供两种语言之间所有可能的集成,也不针对JS作为网络客户端/服务器端语言的最大领域进行定制。

相反,js-sandbox 专注于从Rust调用独立的JS代码,并试图尽可能简单。典型用例是一个核心Rust应用程序,该应用程序与外部用户的脚本集成,例如插件系统或运行外部mod的游戏。

该库处于早期开发阶段,API基本但强大。API可能还会发生重大变化。

示例

从JavaScript打印

Hello World 示例——使用JavaScript打印某物——只有一行,应该如此

fn main() {
    js_sandbox::eval_json("console.log('Hello Rust from JS')").expect("JS runs");
}

调用JS函数

一个非常基础的程序从Rust调用JavaScript函数 sub()。它传递一个参数并接受一个返回值,两者都通过JSON序列化

use js_sandbox::{Script, AnyError};

fn main() -> Result<(), AnyError> {
    let js_code = "function sub(a, b) { return a - b; }";
    let mut script = Script::from_string(js_code)?;

    let result: i32 = script.call("sub", (7, 5))?;

    assert_eq!(result, 2);
    Ok(())
}

一个示例,它序列化一个JSON对象(Rust -> JS)并格式化一个字符串(JS -> Rust)

use js_sandbox::{Script, AnyError};
use serde::Serialize;

#[derive(Serialize)]
struct Person {
    name: String,
    age: u8,
}

fn main() -> Result<(), AnyError> {
    let src = r#"
        function toString(person) {
            return "A person named " + person.name + " of age " + person.age;
        }"#;

    let mut script = Script::from_string(src)?;

    let person = Person { name: "Roger".to_string(), age: 42 };
    let result: String = script.call("toString", (person,))?;

    assert_eq!(result, "A person named Roger of age 42");
    Ok(())
}

加载JS文件

可以在运行时从任何Path加载JavaScript文件(例如第三方mod)。

如果您想将UTF-8编码的文件静态嵌入Rust二进制文件中,您还可以使用std::include_str宏。

use js_sandbox::Script;

fn main() {
    // (1) at runtime:
    let mut script = Script::from_file("script.js").expect("load + init succeeds");

    // (2) at compile time:
    let code: &'static str = include_str!("script.js");
    let mut script = Script::from_string(code).expect("init succeeds");

    // use script as usual
}

在JavaScript中维护状态

可以初始化一个有状态的JS脚本,然后使用函数随时间修改该状态。以下示例在两次调用中追加一个字符串,然后在第三次调用中获取结果

use js_sandbox::{Script, AnyError};

fn main() -> Result<(), AnyError> {
    let src = r#"
        var total = '';
        function append(str) { total += str; }
        function get()       { return total; }"#;

    let mut script = Script::from_string(src)?;

    let _: () = script.call("append", ("hello",))?;
    let _: () = script.call("append", (" world",))?;
    let result: String = script.call("get", ())?;

    assert_eq!(result, "hello world");
    Ok(())
}

带有超时的脚本调用

JS代码可能包含长循环或永久运行的循环,这会阻塞Rust代码。可以在设置超时后中止JavaScript执行。

use js_sandbox::{Script, JsError};

fn main() -> Result<(), JsError> {
    use std::time::Duration;
    let js_code = "function run_forever() { for(;;) {} }";
    let mut script = Script::from_string(js_code)?
        .with_timeout(Duration::from_millis(1000));

    let result: Result<String, JsError> = script.call("run_forever", ());

    assert_eq!(
        result.unwrap_err().to_string(),
        "Uncaught Error: execution terminated".to_string()
    );

    Ok(())
}

依赖项

~270–720KB
~17K SLoC