#javascript #js #sandbox #secure #script #serde-json #applications

js-sandbox

在安全的沙盒中从Rust执行JavaScript代码,并将数据传输到/从JS插件

10个版本

0.2.0-rc.22023年9月12日
0.2.0-rc.12023年4月2日
0.2.0-rc.02022年2月28日
0.1.6 2021年4月18日
0.1.1 2020年9月17日

#1950 in Web编程

Download history 42/week @ 2024-04-14 47/week @ 2024-04-21 39/week @ 2024-04-28 46/week @ 2024-05-05 35/week @ 2024-05-12 39/week @ 2024-05-19 35/week @ 2024-05-26 45/week @ 2024-06-02 22/week @ 2024-06-09 50/week @ 2024-06-16 39/week @ 2024-06-23 3/week @ 2024-06-30 15/week @ 2024-07-07 24/week @ 2024-07-14 39/week @ 2024-07-21 70/week @ 2024-07-28

148 monthly downloads
用于 2 crates

Zlib许可证

25KB
241 代码行,不包括注释

js-sandbox

crates.io docs.rs

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

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

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

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

示例

从JavaScript打印

你好,世界”示例——使用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文件

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

如果您想在Rust二进制文件中静态嵌入UTF-8编码的文件,您还可以使用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(())
}

依赖项

约95MB
约2M SLoC