#neon #frame #macro #apps #channel

过程宏 neon-frame-macro

简化编写Neon应用程序的宏

2个版本

0.1.1 2022年10月2日
0.1.0 2022年4月9日

#622 in 过程宏

Apache-2.0

6KB
121

Neon Frame

"Crates",link="https://crates.io/crates/neon-frame" "Crates",link="https://crates.io/crates/neon-frame-macro" "npm (scoped)",link="https://npmjs.net.cn/package/@emeraldpay/neon-frame" "License"

一个高度定制的框架,用于构建基于Neon的Rust库,用于Node。 Neon Frame 为Rust库提供一个标准的接口,使其能够响应JavaScript。它负责处理错误并将响应转换回JS。

Neon Frame通过统一处理和转换结果和错误的方式简化了处理器的逻辑。现在您只需编写一个普通的返回 Result<T, E> 的方法,它将自动转换为Node。

您可以 可选 使用通道,在这种情况下,Neon Frame的JavaScript端将那些调用包装起来,只获取一个简单的 Promise<T>

安装

.Cargo.toml [源,toml]

[dependencies]
neon-frame = "0.1"
neon-frame-macro = "0.1"

.package.json [源,json]

"dependencies": {
    "@emeraldpay/neon-frame": "^0.1.1"
}

.JS导入 [源,typescript]

import {neonFrameCall} from "@emeraldpay/neon-frame";

对其使用的简短介绍

Rust端

.现在您可以使用 #[neon_frame_fn] 宏标记一个函数:[源,rust]

#[macro_use]
extern crate neon_frame_macro;

#[neon_frame_fn]
pub fn function_hello_world(_cx: &mut FunctionContext) -> Result<String, Errors> {
    Ok("Hello World".to_string())
}

该宏自动将Rust类型转换为Node类型。它可以是任何 Serializable 结构,而不仅仅是 String。内部它只是将其包装成一个JSON,这可以在Node端轻松处理。

JavaScript端

[源,typescript]

import {neonFrameDirectCall} from "@emeraldpay/neon-frame";

// eslint-disable-next-line @typescript-eslint/no-var-requires
const addon = require('path/to/index.node');

export function helloWorld(): string {
    return neonFrameDirectCall<string>(addon, "function_hello_world", []);
}

如果您想在单独的线程中处理某些内容,该怎么办?例如,在JavaScript中以Promise的形式异步获取它?

Rust端使用通道

.使用 #[neon_frame_fn) 宏,它提供了一个回调函数:[源,rust]

#[neon_frame_fn(channel)]
pub fn function_default_channel<H>(_cx: &mut FunctionContext, handler: H) -> Result<(), Errors>
    where
        H: FnOnce(Result<String, Errors>) + Send + 'static {

    std::thread::spawn(move || {
        let result = "Hello World".to_string();
        handler(Ok(result));
    });

    Ok(())
}

JavaScript端使用Promise

[源,typescript]

import {neonFrameHandlerCall} from "@emeraldpay/neon-frame";

// eslint-disable-next-line @typescript-eslint/no-var-requires
const addon = require('path/to/index.node');

export function default_channel(): Promise<string> {
    return neonFrameHandlerCall<string>(addon, "function_default_channel", []);
}

示例

/integration-tests 目录中,您可以找到交互测试,这些测试也可以作为实现示例。

如何与细节协同工作

作为响应,它使用类似JSON的格式:[源,json]

{
  "succeeded": true,
  "result": {
    "foo": "bar"
  }
}

{"foo": "bar"} 是一个实际结果。

如果方法失败,返回类似的内容

[源代码,JSON]

{
  "succeeded": false,
  "error": {
    "code": 100,
    "message": "Invalid input value for #0"
  }
}

作为一个 TypeScript 类型,它是

[源,typescript]

type Status<T> = {
    succeeded: boolean,
    result: T | undefined,
    error: {
        code: number,
        message: string
    } | undefined
}

要使用 Neon Frame,只需在你的方法上添加 #[neon_frame_fn]

[源代码,Rust]

#[neon_frame_fn]
pub fn hello_world(cx: &mut FunctionContext) -> Result<String, MyError> {
    Ok("Hello World".to_string())
}

注意:该方法预期有 cx: &mut FunctionContext,而不是 mut cx: FunctionContext

此外,您需要编写一个从 MyError(usize, String) 的转换器。即实现 impl From<MyError> for (usize, String) 特性。

[源代码,Rust]

impl From<MyError> for (usize, String) {
    fn from(err: MyError) -> Self {
        todo!()
    }
}

除了标准的同步调用之外,该库还为 Channel 处理器提供了同样的简化。在这种情况下,您使用 #[neon_frame_fn(channel)] 宏,并为处理响应的 FnOnce 函数添加额外的参数。

[源代码,Rust]

// function called from JS as:
//
// hello_world((x) => { ... });
//
#[neon_frame_fn(channel)]
pub fn hello_world<H>(cx: &mut FunctionContext, handler: H) -> Result<(), MyError>
    where
        H: FnOnce(Result<String, MyError>) + Send + 'static {

    std::thread::spawn(move || {
        handler(Ok("Hello World".to_string()));
    });
    Ok(())
}

默认情况下,它使用第一个 JS 参数作为处理函数。但如果您需要在不同的位置使用它,您可以将其指定为参数,如 #[neon_frame_fn(channel=2)]

[源代码,Rust]

// function called from JS as:
//
// hello_world("hi", "there", (x) => { ... });
//
// i.e. with handler at the 3rd position, which is 2 starting from zero
//
#[neon_frame_fn(channel=2)]
pub fn hello_world<H>(cx: &mut FunctionContext, handler: H) -> Result<(), MyError>
    where
        H: FnOnce(Result<String, MyError>) + Send + 'static {

    todo!()
}

许可证

版权所有 2022 EmeraldPay,Inc

根据 Apache License 2.0 版本(“许可证”);除非遵守许可证规定,否则不得使用此文件。您可以在以下位置获取许可证副本:

https://apache.ac.cn/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则在许可证下分发的软件按“原样”提供,不提供任何明示或暗示的保证或条件。有关许可证的具体语言、许可和限制,请参阅许可证。

依赖项

~1.5MB
~34K SLoC