# MeshRay-Core 架构规范

> Core 是通用的数据传输引擎，通过 ProtocolPlugin 接口适配不同协议。当前默认内置 WG 插件。

---

## 一、目录结构

```
core/
├── core.go                          # 进程入口
├── engine.go                        # 引擎实例
├── metrics.go                       # 监控指标
│
├── connect/                         # 建连层
│   ├── strategy.go                  # 策略调度
│   ├── stun.go                      # STUN 协议
│   ├── direct.go                    # Layer 1
│   ├── fake_tcp.go                  # Layer 2
│   ├── real_tcp.go                  # Layer 3
│   ├── turn.go                      # Layer 4/6/7
│   ├── turn_quic.go                 # Layer 5
│   ├── ice.go                       # Layer 8
│   └── ws.go                        # Layer 9
│
├── transport/                       # 传输层
│   ├── conn_manager.go              # 连接索引
│   ├── relay.go                     # 转发循环
│   └── plugin.go                    # Plugin 接口
│
└── plugins/                         # 协议插件
    └── wg/
        └── wgparse.go               # WG 插件实现
```

---

## 二、各文件职责

### 2.1 根目录（4 个文件）

| 文件 | 职责 | 持有什么 | 不做什么 |
|------|------|---------|----------|
| `core.go` | 进程入口，管理多个 Engine | `map[engineID]*Engine` | 不做建连、不转发数据 |
| `engine.go` | 一个组网的引擎实例 | strategy、conn_manager、relay、plugin | 不直接调用 connect，由 relay 调用 |
| `metrics.go` | 监控指标采集 | 原子计数器（连接数、字节数、切换次数） | 不做业务逻辑 |

**关键关系**：
- `core.go` 持有多个 `engine.go`
- `internal/ctr/ctr.go` 直接调用 `core.go` 和 `engine.go` (进程内函数调用)
- `engine.go` 持有 connect/、transport/、plugins/ 的实例

### 2.2 connect/（9 个文件）— 建连层

**职责**：通过各种网络方式建立连接，最终返回 `net.Conn`。

**对外暴露的唯一入口**：`strategy.go` 的 `Connect()` 方法。其他 connect 文件只被 `strategy.go` 调用。

| 文件 | 对应层级 | 职责 | 返回什么 |
|------|---------|------|---------|
| `strategy.go` | 全部 | 按优先级尝试各层，不通自动切换，定期探测恢复 | `net.Conn` + 当前层级名 |
| `stun.go` | 被 direct/ice 调用 | STUN 协议：发送 Binding Request，获取本机公网地址 | `*net.UDPAddr`（地址，不是连接） |
| `direct.go` | Layer 1 | 调用 stun 获取候选地址，然后 UDP 打洞 | `net.Conn` |
| `fake_tcp.go` | Layer 2 | UDP 包外层封装 TCP 头部，欺骗防火墙 | `net.Conn` |
| `real_tcp.go` | Layer 3 | 真正的 TCP 直连打洞 | `net.Conn` |
| `turn.go` | Layer 4/6/7 | TURN 协议协商（Allocate/Permission/ChannelBind），参数区分 UDP/TCP/TLS | `net.Conn` |
| `turn_quic.go` | Layer 5 | TURN-QUIC 私有扩展（RFC 9000） | `net.Conn` |
| `ice.go` | Layer 8 | ICE 协商 + WebRTC DataChannel，内部调用 stun 收集候选 | `net.Conn` |
| `ws.go` | Layer 9 | WS/WSS 握手 + 帧收发 + 身份标识 | `net.Conn` |

**9 层完整编号**：

| 层级 | 链路名称 | 文件 | 传输方式 | 穿透力 |
|------|---------|------|---------|--------|
| 1 | Direct-UDP | direct.go | P2P 直连 | 弱（性能最好） |
| 2 | Direct-FakeTCP | fake_tcp.go | P2P 直连 | 弱 |
| 3 | Direct-RealTCP | real_tcp.go | P2P 直连 | 中 |
| 4 | TURN-UDP | turn.go | 中继 | 中 |
| 5 | TURN-QUIC | turn_quic.go | 中继 | 中 |
| 6 | TURN-TCP | turn.go | 中继 | 强 |
| 7 | TURN-TLS | turn.go | 中继 | 强 |
| 8 | WebRTC | ice.go | ICE/TURN | 强 |
| 9 | WS/WSS | ws.go | 隧道 | 最强（兜底） |

**strategy.go 的自动切换逻辑**：
- 单包超时 500ms → 切到下一层
- 10s 滑动窗口丢包率 > 10% → 切到下一层
- 当前在第 N 层时，每 30s 探测 Layer 1 → 连续 2 次成功直接切回 Layer 1（不逐层回退）

**stun.go 的特殊地位**：唯一被多处调用的 connect 文件（direct.go 和 ice.go 都需要它），所以独立存在。

### 2.3 transport/（3 个文件）— 传输层

**职责**：用 `net.Conn` 转发数据。不感知具体协议，通过 ProtocolPlugin 接口适配。

| 文件 | 职责 | 不做什么 |
|------|------|---------|
| `conn_manager.go` | 连接索引：`peer_key → net.Conn` 的映射 | 不做建连、不转发数据 |
| `relay.go` | Read/Write 循环：从本地端口收包 → 查路由 → 通过 conn 发送；从 conn 收包 → 发到本地端口 | 不做建连 |
| `plugin.go` | 定义 ProtocolPlugin 接口 | 不实现任何协议 |

**relay.go 的工作流程**：

```
本地端口收到 WG 密文包
  → 调用 plugin.IsControlPacket() 判断包类型
    → true：控制包，按已建链路透传
  → 调用 plugin.IsDataPacket() 判断
    → true：调用 plugin.ExtractRouteID() 提取路由标识
      → 查路由标识映射表 → 发往对应本地端口
  → 都不是：丢弃
```

**关键**：relay.go 不知道 WireGuard，不知道 receiver index，只知道 route_id。

### 2.4 plugins/wg/（1 个文件）— 协议插件

**职责**：实现 ProtocolPlugin 接口，处理 WG 协议特有的包解析。

| 文件 | 职责 | 不做什么 |
|------|------|---------|
| `wgparse.go` | 实现 `IsDataPacket`/`ExtractRouteID`/`IsControlPacket` | 不做建连、不转发数据 |

**WG 插件的具体实现**：

| 方法 | 逻辑 |
|------|------|
| `IsControlPacket(packet)` | `packet[0]` ∈ {1, 2, 3} → true |
| `IsDataPacket(packet)` | `packet[0]` == 4 → true |
| `ExtractRouteID(packet)` | 读取 `packet[4:8]`，网络字节序解析为 uint32（即 WG receiver index） |

### 2.5 plugins/wg/（1 个文件）

| 文件 | 职责 |
|------|------|
| `wgparse.go` | WireGuard 数据包解析和封装 |

---

## 三、分层架构图

```
┌─────────────────────────────────────────────────────────┐
│              internal/ctr/ctr.go                         │
│        直接调用 Core (进程内函数调用)                     │
└────────────────────────┬────────────────────────────────┘
                         │ 函数调用
┌────────────────────────▼────────────────────────────────┐
│                     core.go                              │
│              管理多个 Engine 实例                          │
└───┬─────────────────────────────────────────────────────┘
    │ 每个组网一个 Engine
    ▼
┌─────────────────────────────────────────────────────────┐
│                     engine.go                            │
│  持有：strategy + conn_manager + relay + plugin          │
│  协调 connect/ 和 transport/ 工作                         │
└───┬─────────────────────────────────────────────────────┘
    │
    ├──────────────────────────────────────────┐
    ▼                                          ▼
┌───────────────────────┐          ┌───────────────────────┐
│     connect/          │          │     transport/        │
│     建连层             │          │     传输层             │
│                       │          │                       │
│  strategy.go          │  返回    │  relay.go             │
│  ├─ direct.go   (L1)  │  net.Conn├─ plugin.go           │
│  ├─ fake_tcp.go (L2)  │────────►│  │  ProtocolPlugin    │
│  ├─ real_tcp.go (L3)  │         │  │                    │
│  ├─ turn.go     (L4/6/7)        │  │  插件调用           │
│  ├─ turn_quic.go(L5)  │         │  ▼                    │
│  ├─ ice.go      (L8)  │         │  plugins/wg/          │
│  └─ ws.go       (L9)  │         │  └─ wgparse.go        │
│                       │          │                       │
│  stun.go (被 direct/ice 调用)   │  conn_manager.go      │
└───────────────────────┘          └───────────────────────┘
```

---

## 四、调用关系

### 4.1 Engine 创建时

```
engine.go
  → 创建 WGPlugin（plugins/wg/wgparse.go）
  → 创建 Relay，传入 plugin（transport/relay.go）
  → 创建 Strategy（connect/strategy.go）
  → 创建 ConnManager（transport/conn_manager.go）
```

### 4.2 Bind 流程

```
ctr 直接调用：Bind()
  → engine.go 接收函数调用
  → engine.go 调用 strategy.Connect()
    → strategy 按优先级尝试各层
      → Layer 1: direct.go 调用 stun.go 获取候选，尝试 UDP 打洞
      → 不通？→ Layer 4: turn.go 调用 TURN 协商
      → 不通？→ Layer 9: ws.go 调用 WS 握手
    → 返回 net.Conn + 当前层级名
  → engine.go 把 net.Conn 注册到 conn_manager
  → engine.go 启动 relay 的 Read/Write 循环
```

### 4.3 数据转发流程

```
WG 发出密文包 → 本地端口
  → relay.go 收到
  → 调用 plugin.IsControlPacket()
    → true：按已建链路透传（conn_manager 查 conn）
  → 调用 plugin.IsDataPacket()
    → true：调用 plugin.ExtractRouteID() 获取 route_id
      → 查路由标识映射表 → 找到本地端口 → 发送
  → 都不是：丢弃
```

---

## 五、通用层与插件层的边界

| 层 | 知道什么 | 不知道什么 |
|---|---------|-----------|
| **connect/** | 网络协议（STUN/TURN/WS/WebRTC） | WireGuard、route_id |
| **transport/** | net.Conn、route_id、ProtocolPlugin 接口 | WireGuard、receiver index |
| **plugins/wg/** | WG 包格式、receiver index | 网络连接、net.Conn |
| **engine.go** | 协调 connect/ 和 transport/ | WG 包格式细节 |

**如果将来要支持其他协议**：
- 新建 `plugins/xxx/xxxparse.go`
- 实现 `ProtocolPlugin` 接口的三个方法
- `engine.go` 里换成 `xxx.NewPlugin()`
- connect/、transport/、core.go 的代码完全不用改

---

## 六、Core 接口（直接被 ctr 调用）

| 方法 | 调用方 | 说明 |
|------|--------|------|
| `CreateEngine` | ctr | 创建一个 Engine 实例（直接函数调用） |
| `Bind` | ctr | 为每个 Peer 开启本地端口，开始建链 |
| `Unbind` | ctr | 停止指定 Peer 的端口监听 |
| `Start` | ctr | 启动转发主循环 |
| `Stop` | ctr | 停止 Engine |
| `GetStatus` | ctr | 查询 Engine 状态 |
| `NotifyPeerInfo` | ctr | 下发对端候选地址和 route_id |

**实现位置**：
- 所有方法都在 `engine.go` 中实现
- `core.go` 提供 Engine 实例管理
- ctr通过`coreInst.CreateEngine(...)`直接调用

---

## 七、文件清单汇总

| 目录 | 文件数 | 文件 |
|------|--------|------|
| 根目录 | 3 | core.go, engine.go, metrics.go |
| connect/ | 9 | strategy.go, stun.go, direct.go, fake_tcp.go, real_tcp.go, turn.go, turn_quic.go, ice.go, ws.go |
| transport/ | 3 | conn_manager.go, relay.go, plugin.go |
| plugins/wg/ | 1 | wgparse.go |
| **总计** | **16** | |

**已删除的文件**：
- ~~grpc_service.go~~ - 不再需要（改为直接函数调用）
- ~~pool/connpool.go~~ - 不再需要（无连接池）
- ~~proto/core.proto~~ - 不再需要 gRPC