# 商户自有授权系统适配器示例

此 Python 3.10+ 示例实现 Launch 外部 HTTP 桥接，使用 SQLite 持久化事件和 nonce，并提供恢复工作进程。它**不会**生成许可证、验证受保护功能或替代你的授权系统。

实现提供以下钩子的 Python 模块：

```python
def apply_snapshot(snapshot):
    # Call your licensing system with snapshot["event_id"] as its durable
    # idempotency key. Apply desired_state and the absolute purchased dates.
    # Return only after confirming the original operation was applied.
    # Raise ValueError for a result requiring manual review.
    ...

def delivery(snapshot):
    # Read an existing result owned by this purchase; do not issue here.
    return {"type": "instructions", "value": "Your own delivery instructions", "expires_at": None}
```

配置后端前，必须用真实接入实现替换 `...`。如果没有配置后端模块，内置钩子会抛出 `NotImplementedError`；事件转入人工审核，绝不会声称已签发授权。示例工作进程可能在崩溃或结果不确定的错误后重试钩子，因此授权后端必须按同一事件 ID 去重和恢复结果。

通过环境变量配置适配器，密钥不得进入源码管理或命令历史：

- `CUSTOM_LICENSING_KEY`：32–128 个随机字节的标准 Base64 编码，必须与 Launch 一致。
- `CUSTOM_LICENSING_KEY_ID`：`key-1`，或你配置的密钥标识。
- `CUSTOM_LICENSING_CONNECTION_REF`：相匹配的连接引用。
- `CUSTOM_LICENSING_ENVIRONMENT`：`sandbox` 或 `live`。
- `CUSTOM_LICENSING_DATABASE`：源码目录之外私有且可写的 SQLite 路径；重启后仍须保留。
- `CUSTOM_LICENSING_BACKEND`：实现上述钩子、可导入的模块。
- `CUSTOM_LICENSING_PORT`：本地监听端口，默认 `18883`。

运行 `python server.py`。本地 sandbox 测试时，在 Launch 中配置 `http://127.0.0.1:18883`，并明确启用其回环 HTTP 例外。生产环境应使用 HTTPS 终止、进程监管、受保护的数据库备份，以及后端自身的 SDK 或运行时授权校验。只声明后端实际支持的购买和交付类型，相应调整 `capabilities`。

修复后端问题后，`python server.py --retry-event ORIGINAL_EVENT_UUID` 会在本地将原来保存的同一请求内容重新入队。还应在 Launch 的授权任务页重试原事件。不得通过更换 ID 或再次增加时长来恢复响应。

该示例只提供起点，不能作为生产验收证明。工作进程租约为 60 秒；钩子调用超时必须更短，或续租。接收正式购买前，应补齐监控、密钥轮换流程、更严格的业务与结构校验，以及部署所需的运维控制。[接入指南](/zh/launch-documents/external-licensing/)和 [OpenAPI](/zh/assets/launch/external-licensing-openapi.json) 定义了协议。绝不能把 Launch 状态响应当作运行受保护代码的许可。
