# 附录 I：联邦路由实现指南（非规范性）

> **本文档为非规范性内容**：提供联邦路由的架构设计、实现建议、性能优化和部署指南，不是协议强制要求。

## I.1 联邦架构概述

AUN 是一个**联邦网络**（Federated Network），不同 Issuer 运营的 Gateway 之间可以互相通信，实现跨 Issuer 的消息传递。

**核心特性**：
- **去中心化**：没有中央服务器，每个 Issuer 独立运营
- **互联互通**：不同 Issuer 的用户可以互相通信
- **端到端加密**：消息在客户端加密，Gateway 无法解密
- **证书验证**：通过证书链验证对方身份

**类比**：
- 类似电子邮件（alice@gmail.com 可以发送给 bob@outlook.com）
- 类似 XMPP/Jabber（联邦即时通讯协议）
- 类似 Matrix（去中心化通信协议）

## I.2 路由场景

### I.2.1 场景 1：同 Gateway 路由

发送者和接收者连接到同一个 Gateway，Gateway 直接转发消息。

```
Alice (alice.aid.pub)
  │
  │ 1. message.send
  ↓
Gateway (gateway.aid.pub)
  │
  │ 2. 查找 bob.aid.pub 的连接
  │ 3. 直接转发消息
  ↓
Bob (bob.aid.pub)
  │
  │ 4. event/message.received
```

**特点**：
- 最快，无需跨网络
- Gateway 直接转发
- 延迟最低（< 10ms）

### I.2.2 场景 2：同 Issuer，不同 Gateway

Alice 和 Bob 都是同一 Issuer 的用户，但连接到不同的 Gateway。

```
Alice (alice.aid.pub)          Bob (bob.aid.pub)
  │                              │
  │ 连接到                        │ 连接到
  ↓                              ↓
Gateway 1 (gateway1.aid.pub)   Gateway 2 (gateway2.aid.pub)
  │                              │
  │ 1. message.send              │
  ↓                              │
  │ 2. 查找 bob.aid.pub          │
  │    → 发现在 Gateway 2        │
  │                              │
  │ 3. 内网转发 ─────────────────>│
  │    (gRPC/HTTP2)              │
  │                              │ 4. 转发给 Bob
  │                              ↓
  │                            Bob 收到消息
```

**特点**：
- Gateway 间通过内网通信（gRPC 或 HTTP/2）
- 同一 Issuer 的 Gateway 互相信任
- 延迟较低（< 50ms）

**推荐实现方式**：

**方式1：gRPC**
```protobuf
service GatewayFederation {
  rpc RouteMessage(MessageRequest) returns (MessageResponse);
  rpc QueryUserLocation(UserLocationRequest) returns (UserLocationResponse);
}

message MessageRequest {
  string from_aid = 1;
  string to_aid = 2;
  bytes encrypted_payload = 3;
  string message_id = 4;
  int64 timestamp = 5;
}
```

**方式2：HTTP/2**
```http
POST /internal/route HTTP/2
Host: gateway2.aid.pub
Content-Type: application/json

{
  "from": "alice.aid.pub",
  "to": "bob.aid.pub",
  "encrypted_payload": "...",
  "timestamp": 1710504000
}
```

### I.2.3 场景 3：跨 Issuer 路由（联邦路由）

Alice (`alice.aid.pub`) 发送消息给 Charlie (`charlie.example.com`)。

```
Alice (alice.aid.pub)                    Charlie (charlie.example.com)
  │                                        │
  │ 连接到                                  │ 连接到
  ↓                                        ↓
Gateway A (gateway.aid.pub)              Gateway B (gateway.example.com)
  │                                        │
  │ 1. message.send                        │
  │    to: charlie.example.com             │
  ↓                                        │
  │ 2. 解析目标 Issuer: example.com        │
  │ 3. 发现 Gateway B 地址                 │
  │                                        │
  │ 4. 建立 HTTPS 连接 ──────────────────>│
  │    (mTLS 双向认证)                     │
  │                                        │
  │ 5. 发送消息                            │
  │    POST /federation/rpc                │
  │    federation.send_message             │
  │                                        │
  │                                        │ 6. 验证发送者证书链
  │                                        │ 7. 查找 charlie 的连接
  │                                        │ 8. 转发消息
  │                                        ↓
  │                                      Charlie 收到消息
  │                                        │
  │<──────── 9. 返回 ACK ─────────────────│
```

## I.3 Gateway 发现

### I.3.1 发现方法

Gateway A 需要找到 Gateway B 的地址，按以下优先级尝试：

**方法 1：DNS SRV 查询**（推荐）
```bash
dig SRV _aun-gateway._tcp.example.com

# 返回格式：
# _aun-gateway._tcp.example.com. 300 IN SRV 10 100 443 gateway.example.com.
```

**方法 2：Well-Known 端点**
```bash
GET https://example.com/.well-known/aun-gateway

# 响应：
{
  "gateways": [
    {"url": "https://gateway.example.com/federation", "priority": 1}
  ]
}
```

**方法 3：默认约定**
```
https://gateway.{issuer}/federation
```

### I.3.2 发现流程实现

```javascript
async function discoverGateway(issuer) {
  // 1. 检查缓存
  const cached = cache.get(`gateway:${issuer}`);
  if (cached && !cached.expired) {
    return cached.url;
  }

  // 2. DNS SRV 查询
  try {
    const srv = await dns.resolveSrv(`_aun-gateway._tcp.${issuer}`);
    if (srv.length > 0) {
      const url = `https://${srv[0].name}:${srv[0].port}/federation`;
      cache.set(`gateway:${issuer}`, {url, ttl: 3600});
      return url;
    }
  } catch (err) {
    console.warn(`DNS SRV lookup failed for ${issuer}:`, err);
  }

  // 3. Well-Known 端点
  try {
    const res = await fetch(`https://${issuer}/.well-known/aun-gateway`);
    const config = await res.json();
    const url = config.gateways[0].url;
    cache.set(`gateway:${issuer}`, {url, ttl: 3600});
    return url;
  } catch (err) {
    console.warn(`Well-Known lookup failed for ${issuer}:`, err);
  }

  // 4. 默认约定
  const url = `https://gateway.${issuer}/federation`;
  cache.set(`gateway:${issuer}`, {url, ttl: 3600});
  return url;
}
```

### I.3.3 缓存策略

**推荐缓存内容**：
- Gateway 地址：TTL 1 小时
- mTLS 连接：保持连接，定期 ping
- 用户在线状态：TTL 5 分钟

**缓存失效条件**：
- 连接失败时立即失效
- TTL 过期时失效
- 收到 DNS 更新通知时失效

## I.4 mTLS 双向认证

### I.4.1 证书要求

Gateway 间必须使用 mTLS 双向认证：

**Gateway A 的证书**：
```
Subject: CN=gateway.aid.pub
Issuer: CN=aid.pub (Issuer CA)
  Issuer: CN=Root CA
```

**Gateway B 的证书**：
```
Subject: CN=gateway.example.com
Issuer: CN=example.com (Issuer CA)
  Issuer: CN=Root CA
```

### I.4.2 验证流程

```
Gateway A                          Gateway B
  │                                  │
  │ 1. TLS ClientHello ─────────────>│
  │    (携带 Gateway A 的证书)        │
  │                                  │
  │<──────── 2. TLS ServerHello ─────│
  │    (携带 Gateway B 的证书)        │
  │                                  │
  │ 3. 验证 Gateway B 证书链          │
  │    gateway.example.com           │
  │    ← example.com (Issuer CA)     │
  │    ← Root CA                     │
  │                                  │
  │                                  │ 4. 验证 Gateway A 证书链
  │                                  │    gateway.aid.pub
  │                                  │    ← aid.pub (Issuer CA)
  │                                  │    ← Root CA
  │                                  │
  │ 5. TLS 握手完成 ─────────────────>│
  │    (双向认证成功)                 │
```

**验证步骤**：
1. Gateway A 验证 Gateway B 的证书链到受信 Root CA
2. Gateway B 验证 Gateway A 的证书链到受信 Root CA
3. 双方验证证书的 CN 与域名匹配
4. 双方检查证书有效期和吊销状态（推荐）

## I.5 安全机制

### I.5.1 Issuer 验证

Gateway B 必须验证消息的 `from` 字段属于 Gateway A 的 Issuer：

```javascript
function verifyMessage(message, clientCert) {
  // 1. 从客户端证书提取 Issuer
  const issuerFromCert = extractIssuer(clientCert);
  // 例如：gateway.aid.pub → aid.pub

  // 2. 从消息提取发送者的 Issuer
  const issuerFromMessage = extractIssuer(message.from);
  // 例如：alice.aid.pub → aid.pub

  // 3. 验证两者匹配
  if (issuerFromCert !== issuerFromMessage) {
    throw new Error('Issuer mismatch');
  }

  // 4. 验证签名
  const senderPublicKey = await fetchPublicKey(message.from);
  if (!verify(message, senderPublicKey)) {
    throw new Error('Invalid signature');
  }

  return true;
}
```

**防止的攻击**：
- Gateway A 不能伪造来自 `example.com` 的消息
- 即使 Gateway A 被攻破，也只能影响 `aid.pub` 的用户

### I.5.2 端到端加密

消息内容在客户端加密，Gateway 无法解密：

```
Alice 的客户端
  │ 1. 获取 Charlie 的公钥
  │ 2. 用 Charlie 的公钥加密消息
  │ 3. 发送 encrypted_payload
  ↓
Gateway A (无法解密，只能转发)
  ↓
Gateway B (无法解密，只能转发)
  ↓
Charlie 的客户端
  │ 4. 用 Charlie 的私钥解密消息
```

**加密算法**：
- 密钥交换：ECDH (P-256/P-384/X25519)
- 对称加密：AES-256-GCM 或 ChaCha20-Poly1305

## I.6 离线消息处理

### I.6.1 接收者离线

如果接收者离线，Gateway B 可以选择：

**选项 1：入队等待**（推荐）
```json
{
  "status": "queued",
  "message_id": "msg-12345",
  "queued_at": 1710504001,
  "ttl": 604800  // 7 天
}
```

**选项 2：拒绝接收**
```json
{
  "status": "offline",
  "message_id": "msg-12345",
  "error": "User is offline and offline messages are disabled"
}
```

### I.6.2 离线消息存储

Gateway B 存储离线消息：

```
离线消息队列 (charlie.example.com)
├─ msg-12345 (from: alice.aid.pub, ttl: 7天)
├─ msg-12346 (from: bob.aid.pub, ttl: 7天)
└─ msg-12347 (from: david.example.com, ttl: 7天)
```

Charlie 上线时，Gateway B 推送所有离线消息：

```json
{
  "jsonrpc": "2.0",
  "method": "event/message.offline_messages",
  "params": {
    "messages": [
      {"from": "alice.aid.pub", "encrypted_payload": "...", "timestamp": 1710504000},
      {"from": "bob.aid.pub", "encrypted_payload": "...", "timestamp": 1710504100}
    ]
  }
}
```

---

## I.7 性能优化

### I.7.1 连接池

维护到其他 Gateway 的 HTTP/2 连接池：

```javascript
class GatewayConnectionPool {
  constructor() {
    this.connections = new Map();
  }

  async getConnection(gatewayUrl) {
    let conn = this.connections.get(gatewayUrl);

    if (!conn || !conn.isAlive()) {
      conn = await this.createConnection(gatewayUrl);
      this.connections.set(gatewayUrl, conn);
    }

    return conn;
  }

  async createConnection(gatewayUrl) {
    return http2.connect(gatewayUrl, {
      cert: fs.readFileSync('gateway-cert.pem'),
      key: fs.readFileSync('gateway-key.pem'),
      ca: fs.readFileSync('root-ca.pem'),
      keepAlive: true,
      keepAliveTimeout: 300000, // 5 分钟
    });
  }
}
```

**优点**：
- 避免重复 TLS 握手（节省 100-200ms）
- HTTP/2 多路复用（单连接支持多个并发请求）
- 减少延迟

**推荐配置**：
- 最大连接数：100
- 空闲超时：5 分钟
- 连接保活：每 30 秒 ping

### I.7.2 批量发送

当多个消息发往同一 Gateway 时，批量发送：

```javascript
class MessageBatcher {
  constructor(gateway, batchSize = 10, batchTimeout = 100) {
    this.gateway = gateway;
    this.batchSize = batchSize;
    this.batchTimeout = batchTimeout;
    this.pending = [];
    this.timer = null;
  }

  async send(message) {
    this.pending.push(message);

    if (this.pending.length >= this.batchSize) {
      await this.flush();
    } else if (!this.timer) {
      this.timer = setTimeout(() => this.flush(), this.batchTimeout);
    }
  }

  async flush() {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }

    if (this.pending.length === 0) return;

    const batch = this.pending.splice(0);
    await this.gateway.sendBatch(batch);
  }
}
```

**优点**：
- 减少 HTTP 请求数（10 条消息 → 1 个请求）
- 减少网络往返（节省 RTT）
- 提高吞吐量（10x+）

**推荐配置**：
- 批量大小：10-50 条消息
- 批量超时：100-500ms

### I.7.3 消息压缩

使用 HTTP/2 压缩和 Brotli/gzip：

```http
POST /federation/rpc HTTP/2
Content-Encoding: br
Accept-Encoding: br, gzip

{compressed-json-rpc-payload}
```

**压缩效果**：
- JSON 消息：压缩率 60-80%
- 大批量消息：压缩率更高


## I.8 故障处理

### I.8.1 Gateway 不可达

**重试策略**：
```javascript
async function sendWithRetry(gateway, message, maxRetries = 3) {
  const delays = [0, 1000, 5000]; // 立即、1秒、5秒

  for (let i = 0; i < maxRetries; i++) {
    try {
      if (delays[i] > 0) {
        await sleep(delays[i]);
      }
      return await gateway.send(message);
    } catch (err) {
      if (i === maxRetries - 1) {
        throw new Error(`Gateway unreachable after ${maxRetries} retries`);
      }
      console.warn(`Retry ${i + 1}/${maxRetries} failed:`, err.message);
    }
  }
}
```

**推荐策略**：
- 立即重试 1 次
- 1 秒后重试
- 5 秒后重试
- 失败后通知发送者

### I.8.2 消息丢失检测

**超时检测**：
```javascript
async function sendWithTimeout(gateway, message, timeout = 30000) {
  return Promise.race([
    gateway.send(message),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
}
```

**推荐配置**：
- 超时时间：30 秒
- 最大重试：3 次
- 重试间隔：指数退避（1s, 2s, 4s）

### I.8.3 证书过期处理

**证书验证**：
```javascript
function validateCertificate(cert) {
  const now = Date.now();
  const notBefore = new Date(cert.valid_from).getTime();
  const notAfter = new Date(cert.valid_to).getTime();

  if (now < notBefore) {
    throw new Error('Certificate not yet valid');
  }

  if (now > notAfter) {
    throw new Error('Certificate expired');
  }

  // 检查即将过期（30 天内）
  const thirtyDays = 30 * 24 * 60 * 60 * 1000;
  if (notAfter - now < thirtyDays) {
    console.warn('Certificate expires soon:', new Date(notAfter));
  }
}
```

**推荐策略**：
- 证书过期前 30 天发出告警
- 证书过期前 7 天发出紧急告警
- 证书过期后拒绝连接


## I.9 监控与日志

### I.9.1 监控指标

**推荐监控指标**：

| 指标 | 说明 | 告警阈值 |
|------|------|---------|
| `federation_message_sent_total` | 联邦消息发送总数 | - |
| `federation_message_success_rate` | 成功发送的消息比例 | < 95% |
| `federation_message_latency_ms` | 消息从发送到 ACK 的时间 | P99 > 1000ms |
| `federation_connection_failures` | 连接其他 Gateway 失败次数 | > 10/min |
| `federation_mtls_handshake_failures` | mTLS 握手失败次数 | > 5/min |
| `federation_offline_queue_length` | 离线消息队列长度 | > 1000 |

### I.9.2 日志记录

**推荐日志格式**：

```json
{
  "timestamp": "2026-03-15T10:00:00Z",
  "level": "info",
  "event": "federation_message_sent",
  "from": "alice.aid.pub",
  "to": "charlie.example.com",
  "to_gateway": "gateway.example.com",
  "message_id": "msg-12345",
  "status": "delivered",
  "latency_ms": 150
}
```

**隐私保护原则**：
- ✅ 记录：发送者 AID、接收者 AID、时间戳、状态
- ❌ 不记录：消息内容（已加密）
- ❌ 不记录：消息元数据（主题、附件名等）

**日志级别**：
- `INFO`：正常消息发送
- `WARN`：重试、超时、证书即将过期
- `ERROR`：发送失败、证书过期、签名验证失败


## I.10 部署建议

### I.10.1 单 Gateway 部署

**适用场景**：
- 小型 Issuer
- 用户数 < 10,000
- 单地域部署

**架构**：
```
Internet
   ↓
Gateway (gateway.aid.pub)
   ├─ WebSocket 服务（客户端连接）
   ├─ Federation API（联邦路由）
   └─ 内部服务（Auth、Message 等）
```

**推荐配置**：
- CPU：4 核
- 内存：8 GB
- 网络：1 Gbps
- 并发连接：10,000

### I.10.2 多 Gateway 部署

**适用场景**：
- 中大型 Issuer
- 用户数 > 10,000
- 需要高可用

**架构**：
```
Internet
   ↓
Load Balancer (DNS 轮询或 L4/L7 负载均衡)
   ├─ Gateway 1 (gateway1.aid.pub)
   ├─ Gateway 2 (gateway2.aid.pub)
   └─ Gateway 3 (gateway3.aid.pub)
        │
        ↓
   共享存储（Redis/数据库）
   ├─ 用户在线状态
   ├─ 离线消息队列
   └─ Gateway 路由表
```

**Gateway 间同步方式**：
- **共享存储**：通过 Redis 同步状态（推荐）
- **内网 gRPC**：Gateway 间直接通信
- **消息队列**：通过 Kafka/RabbitMQ 同步

**推荐配置**：
- 每个 Gateway：8 核 / 16 GB
- Redis：主从复制 + 哨兵
- 负载均衡：基于连接数或 CPU 使用率

### I.10.3 地理分布部署

**适用场景**：
- 全球用户
- 需要低延迟
- 跨地域高可用

**架构**：
```
美国用户 → Gateway US (gateway-us.aid.pub)
   ↓
欧洲用户 → Gateway EU (gateway-eu.aid.pub)
   ↓
亚洲用户 → Gateway Asia (gateway-asia.aid.pub)
```

**GeoDNS 配置示例**：
```
# 美国用户
gateway.aid.pub. IN A 203.0.113.10  (美国 IP)

# 欧洲用户
gateway.aid.pub. IN A 198.51.100.20  (欧洲 IP)

# 亚洲用户
gateway.aid.pub. IN A 192.0.2.30  (亚洲 IP)
```

**跨地域同步**：
- 用户在线状态：通过全局 Redis 集群同步
- 离线消息：存储在用户最近访问的地域
- 消息路由：优先本地 Gateway，跨地域时通过专线

**推荐配置**：
- 每个地域：至少 2 个 Gateway（高可用）
- 跨地域延迟：< 200ms
- 专线带宽：100 Mbps+

## I.11 与其他联邦协议的对比

| 特性 | AUN | Email (SMTP) | XMPP | Matrix |
|------|-----|--------------|------|--------|
| 传输协议 | HTTPS + mTLS | SMTP + STARTTLS | TCP + STARTTLS | HTTPS |
| 端到端加密 | 内置 (E2EE) | 可选 (PGP/S/MIME) | 可选 (OMEMO) | 内置 (Olm/Megolm) |
| 身份验证 | 证书链 | 域名 | SASL | 证书/密码 |
| 离线消息 | 支持 | 支持 | 支持 | 支持 |
| 实时性 | 实时 (WebSocket) | 非实时 | 实时 (TCP) | 实时 (HTTP 长轮询) |
| 复杂度 | 中等 | 简单 | 复杂 | 复杂 |

**AUN 的优势**：
- 基于 HTTPS，防火墙友好
- mTLS 双向认证，安全性高
- 内置端到端加密
- 证书链验证，防止身份伪造

---
