# hsnet-rpc-macro

Proc macro 实现，为 hsnet-rpc 提供 `#[rpc(server)]` 宏。

## 目的

**消除重复的 handler 注册代码。**

### 手动注册的问题

```rust
// 需要写两遍：trait 定义 + 手动注册
trait MyService {
    async fn start(&self, config: Config) -> Result<String, RpcError>;
    async fn stop(&self, force: bool) -> Result<String, RpcError>;
}

// 手动注册（容易出错）
let server = RpcServer::new()
    .handle("start", {
        let service = service.clone();
        move |config: Config| {
            let service = service.clone();
            async move { service.start(config).await }
        }
    })
    .handle("stop", {
        let service = service.clone();
        move |force: bool| {
            let service = service.clone();
            async move { service.stop(force).await }
        }
    });
```

问题：
- 注册代码重复且容易出错
- 方法名字符串（`"start"`）容易拼写错误
- 参数类型重复声明
- 闭包嵌套深，难以阅读

### 使用宏后

```rust
#[rpc(server)]
trait MyService {
    #[method(name = "start")]
    async fn start(&self, config: Config) -> Result<String, RpcError>;

    #[method(name = "stop")]
    async fn stop(&self, force: bool) -> Result<String, RpcError>;
}

// 自动生成注册代码
let server = service.into_rpc();
```

## 使用方法

### 1. 标记 trait

```rust
use hsnet_rpc::{rpc, RpcError};
use async_trait::async_trait;

#[async_trait]
#[rpc(server)]
pub trait ControlRpc {
    #[method(name = "start")]
    async fn start(&self, config: Config) -> Result<String, RpcError>;

    #[method(name = "stop")]
    async fn stop(&self, force: bool) -> Result<String, RpcError>;

    // 无参数方法
    #[method(name = "status")]
    async fn status(&self) -> Result<String, RpcError>;
}
```

### 2. 实现 trait

```rust
pub struct ControlService { /* ... */ }

#[async_trait]
impl ControlRpc for ControlService {
    async fn start(&self, config: Config) -> Result<String, RpcError> {
        // 业务逻辑
        Ok("started".to_string())
    }

    async fn stop(&self, force: bool) -> Result<String, RpcError> {
        Ok("stopped".to_string())
    }

    async fn status(&self) -> Result<String, RpcError> {
        Ok("running".to_string())
    }
}
```

### 3. 使用生成的 `into_rpc()` 方法

```rust
use hsnet_rpc::IntoRpcServer; // 宏生成的 trait

let service = Arc::new(ControlService::new());
let server = service.into_rpc();  // 自动注册所有方法

server.run_unix("/tmp/control.sock").await?;
```

## 宏展开后的代码

输入：

```rust
#[rpc(server)]
pub trait ControlRpc {
    #[method(name = "start")]
    async fn start(&self, config: Config) -> Result<String, RpcError>;

    #[method(name = "stop")]
    async fn stop(&self, force: bool) -> Result<String, RpcError>;
}
```

展开为：

```rust
// 1. 保留原始 trait 定义（去掉 #[rpc] 和 #[method] 属性）
pub trait ControlRpc {
    async fn start(&self, config: Config) -> Result<String, RpcError>;
    async fn stop(&self, force: bool) -> Result<String, RpcError>;
}

// 2. 生成扩展 trait
pub trait IntoRpcServer {
    fn into_rpc(self: std::sync::Arc<Self>) -> hsnet_rpc::RpcServer;
}

// 3. 为所有实现了 ControlRpc 的类型实现 IntoRpcServer
impl<T: ControlRpc + Send + Sync + 'static> IntoRpcServer for T {
    fn into_rpc(self: std::sync::Arc<Self>) -> hsnet_rpc::RpcServer {
        let service = self;
        let mut server = hsnet_rpc::RpcServer::new();

        // 注册 "start" 方法（单参数）
        server = server.handle("start", {
            let service = service.clone();
            move |config: Config| {
                let service = service.clone();
                async move { service.start(config).await }
            }
        });

        // 注册 "stop" 方法（单参数）
        server = server.handle("stop", {
            let service = service.clone();
            move |force: bool| {
                let service = service.clone();
                async move { service.stop(force).await }
            }
        });

        server
    }
}
```

## 支持的特性

### 1. 条件编译（`#[cfg]`）

```rust
#[rpc(server)]
pub trait ControlRpc {
    // 所有平台都有
    #[method(name = "start")]
    async fn start(&self, config: Config) -> Result<String, RpcError>;

    // 仅 Windows 平台
    #[cfg(windows)]
    #[method(name = "restart")]
    async fn restart(&self) -> Result<String, RpcError>;

    // 仅 Unix 平台
    #[cfg(unix)]
    #[method(name = "reload_config")]
    async fn reload_config(&self) -> Result<String, RpcError>;
}
```

宏会自动处理 `#[cfg]` 属性，生成条件编译的注册代码：

```rust
impl<T: ControlRpc + Send + Sync + 'static> IntoRpcServer for T {
    fn into_rpc(self: Arc<Self>) -> RpcServer {
        let mut server = RpcServer::new();

        server = server.handle("start", /* ... */);

        #[cfg(windows)]
        {
            server = server.handle("restart", /* ... */);
        }

        #[cfg(unix)]
        {
            server = server.handle("reload_config", /* ... */);
        }

        server
    }
}
```

### 2. 无参数方法

```rust
#[method(name = "status")]
async fn status(&self) -> Result<String, RpcError>;
```

生成：

```rust
server = server.handle("status", {
    let service = service.clone();
    move |_: ()| {
        let service = service.clone();
        async move { service.status().await }
    }
});
```

客户端调用：

```rust
let status: String = client.call("status", ()).await?;
```

### 3. 单参数方法

```rust
#[method(name = "start")]
async fn start(&self, config: Config) -> Result<String, RpcError>;
```

生成：

```rust
server = server.handle("start", {
    let service = service.clone();
    move |config: Config| {
        let service = service.clone();
        async move { service.start(config).await }
    }
});
```

## 限制

### 1. 仅支持单参数方法

```rust
// ✅ 支持
#[method(name = "method1")]
async fn method1(&self) -> Result<String, RpcError>;

#[method(name = "method2")]
async fn method2(&self, param: Config) -> Result<String, RpcError>;

// ❌ 不支持（会生成编译错误）
#[method(name = "method3")]
async fn method3(&self, p1: String, p2: u32) -> Result<String, RpcError>;
```

**原因：** 保持简单性。多参数可以用结构体包装：

```rust
#[derive(Serialize, Deserialize)]
struct Method3Params {
    p1: String,
    p2: u32,
}

#[method(name = "method3")]
async fn method3(&self, params: Method3Params) -> Result<String, RpcError>;
```

### 2. 参数必须是值类型

```rust
// ✅ 正确
#[method(name = "start")]
async fn start(&self, config: Config) -> Result<String, RpcError>;

// ❌ 错误（编译失败）
#[method(name = "start")]
async fn start(&self, config: &Config) -> Result<String, RpcError>;
```

**原因：** 生成的闭包跨任务边界，需要 `'static` 生命周期。

**解决方案：**
- 小对象直接传值（如 `bool`, `u32`）
- 大对象使用 `String`、`Vec`、`Arc` 等拥有所有权的类型
- trait 方法内部可以转换为引用使用

### 3. 返回值必须是 `Result<T, RpcError>`

```rust
// ✅ 正确
#[method(name = "start")]
async fn start(&self, config: Config) -> Result<String, RpcError>;

// ❌ 错误（类型不匹配）
#[method(name = "start")]
async fn start(&self, config: Config) -> String;
```

**原因：** RPC 调用需要统一的错误处理。

### 4. 必须和 `#[async_trait]` 配合使用

```rust
use async_trait::async_trait;

#[async_trait]  // 必须
#[rpc(server)]
pub trait ControlRpc {
    // async fn 在 trait 中需要 async_trait
    #[method(name = "start")]
    async fn start(&self, config: Config) -> Result<String, RpcError>;
}
```

**原因：** Rust trait 中的 async fn 需要 `async_trait` 宏支持。

## 实现细节

### 宏处理流程

1. **解析 trait 定义**
   - 使用 `syn::parse_macro_input` 解析 `TokenStream`
   - 提取 trait 名称、可见性、泛型等

2. **提取 RPC 方法**
   - 遍历 trait items，查找带 `#[method]` 属性的方法
   - 解析 `#[method(name = "xxx")]` 提取方法名
   - 提取参数类型（跳过 `&self`）
   - 提取 `#[cfg]` 属性用于条件编译

3. **生成 handler 注册代码**
   - 为每个方法生成闭包：
     - 无参数：`move |_: ()| { ... }`
     - 单参数：`move |param: T| { ... }`
     - 多参数：生成编译错误

4. **生成最终代码**
   - 保留原始 trait（去掉宏属性）
   - 生成 `IntoRpcServer` trait
   - 生成 `impl<T: OriginalTrait> IntoRpcServer for T`

### 关键代码片段

```rust
// 解析方法名
fn parse_method_name(attr: &Attribute) -> String {
    if let Meta::List(meta_list) = &attr.meta {
        let tokens_str = meta_list.tokens.to_string();
        // 简单解析 name = "xxx"
        if let Some(start) = tokens_str.find('"') {
            if let Some(end) = tokens_str[start + 1..].find('"') {
                return tokens_str[start + 1..start + 1 + end].to_string();
            }
        }
    }
    String::new()
}

// 生成 handler 注册代码
if method.params.is_empty() {
    // 无参数
    quote! {
        server = server.handle(#rpc_name, {
            let service = service.clone();
            move |_: ()| {
                let service = service.clone();
                async move { service.#method_name().await }
            }
        });
    }
} else if method.params.len() == 1 {
    // 单参数
    let param_name = &method.params[0].0;
    let param_type = &method.params[0].1;
    quote! {
        server = server.handle(#rpc_name, {
            let service = service.clone();
            move |#param_name: #param_type| {
                let service = service.clone();
                async move { service.#method_name(#param_name).await }
            }
        });
    }
}
```

## 调试宏展开

使用 `cargo expand` 查看宏展开后的代码：

```bash
# 安装 cargo-expand
cargo install cargo-expand

# 展开特定文件的宏
cargo expand --package client --lib ctrl_ipc::service

# 或者展开整个 crate
cargo expand --package client
```

## 实际使用示例

参考 `client/src/ctrl_ipc/service.rs`，这是生产环境中的完整示例：

```rust
#[async_trait]
#[rpc(server)]
pub trait ControlRpc {
    // 通用方法
    #[method(name = "wg_start")]
    async fn wg_start(&self, config: WgConfig) -> Result<String, RpcError>;

    #[method(name = "wg_stop")]
    async fn wg_stop(&self, force: bool) -> Result<String, RpcError>;

    // Windows 专用方法
    #[cfg(windows)]
    #[method(name = "restart")]
    async fn restart(&self) -> Result<String, RpcError>;

    #[cfg(windows)]
    #[method(name = "cmd_svc")]
    async fn cmd_svc(&self, msg: IpcCommand) -> Result<String, RpcError>;

    // ... 共 18 个方法
}

// 实现
pub struct ControlService { /* ... */ }

#[async_trait]
impl ControlRpc for ControlService {
    async fn wg_start(&self, config: WgConfig) -> Result<String, RpcError> {
        // 业务逻辑
    }
    // ...
}

// 使用
let service = ControlService::new(...);
let server = service.into_rpc();
server.run_pipe(r"\\.\pipe\hsnetv2_ctrl_ipc").await?;
```

## 技术栈

- **syn**: 解析 Rust 语法树
- **quote**: 生成 Rust 代码
- **proc-macro2**: 过程宏基础设施

## 相关文档

- [hsnet-rpc 文档](../hsnet-rpc/README.md) - 框架主文档
- [Rust Proc Macro Book](https://doc.rust-lang.org/reference/procedural-macros.html)

## License

MIT
