# 设备统计 API

[文档首页](./README.md) · [通用协议](./protocol.md)

这些接口用于**自愿匿名安装统计**，不是账号注册、设备管理权限或硬件身份。未注册也可访问未被限制的音乐接口，但网关可将请求归为未识别安装实例/IP活动。

## 1. 隐私说明

### `GET /api/device/privacy`

无参数。200：

```json
{
  "consent_required":true,
  "fields":["random_installation_id","last_ip","app_version","variant","last_activity"],
  "retention_days":30,
  "online_seconds":300,
  "legacy_ip_statistics":true,
  "note":"不采集硬件标识、音乐内容或关键词。匿名ID不是物理设备身份；清除数据可改变。"
}
```

封禁状态下仍允许访问；策略读取错误仍可能503。`legacy_ip_statistics`沿用历史字段命名，不表示所有无凭证访问都是旧版本。IP记录不能当作用户人数。

## 2. 注册

### `POST /api/device/register`

请求JSON：

| 字段 | 类型 | 必需 | 说明 |
| --- | --- | --- | --- |
| `consent` | boolean | 是 | 必须为真正的true，不接受字符串true/1 |
| `version` | string | 否 | 应用版本，网关转换字符串后截取32字符 |
| `variant` | string | 否 | phone/watch/desktop等，截取16字符 |

```json
{"consent":true,"version":"2.2.2","variant":"phone"}
```

200：

```json
{"token":"<32_HEX_ID>.<64_HEX_SIGNATURE>","device_id":"<32_HEX_ID>","online_window_seconds":300,"retention_days":30}
```

token为设备请求头凭证，应本地保护保存，不放查询参数、日志、网页截图或导出歌单。服务器不会读取IMEI、序列号或硬件指纹。

注册以网关识别IP为准，不接受用户传ip覆盖。每IP每小时5次，重复注册**生成新的匿名实例**，不是幂等“获取已有设备”；应保存既有token，不在每次启动时注册。

错误：400没有真实consent或请求结构无效；403IP/设备被限制；429注册过频；503策略/统计服务不可用。

## 3. 心跳

### `POST /api/device/heartbeat`

请求头 `X-Wristhyme-Device: <TOKEN>` 必需，建议同时带版本及variant头；JSON body为 `{}`。

200：`{"ok":true,"online_seconds":300}`。

在线定义为最近300秒API活动；普通音乐API也可计活动。客户端进入前台后约每120秒心跳，退出前台停止，不需要常驻后台轮询。服务器约30秒聚合活动、异步有界队列上报，200不保证每次都增加一次数据库requests。

错误：400请求无效；401设备凭证无效；403访问受限；503服务不可用。

## 4. 撤回统计

### `POST /api/device/forget`

请求头 `X-Wristhyme-Device: <TOKEN>` 必需，body为 `{}`。200：`{"ok":true}`。

- 删除该实例的活动记录。
- 保留30天单向哈希撤回标记，用于丢弃异步队列中的迟到活动；不是保留原始设备活动。
- 清除统计不会解除IP或设备封禁。有效凭证在封禁状态下仍允许该请求。
- 当前token签名没有被撤销列表永久作废，客户端必须停止携带旧token并停止心跳；不能把forget理解为服务器使token立即密码学失效。
- 关闭统计时先停止新心跳/活动携带；删除失败保留待删除凭证以重试，不应重新开启统计或丢掉唯一删除凭证。
- 随后无凭证请求仍可能记为独立IP活动；匿名实例统计撤回不等于关闭所有服务端IP安全/活动处理。

错误：400JSON等无效；401头部凭证无效；内部层另有400设备凭证无效分支；503策略/统计服务失败。封禁并不自动禁止合法forget。

## 5. POST 约束

三接口均要求application/json、JSON对象、单一Content-Length，body 1..4096字节，不接受Transfer-Encoding。注册/心跳/撤回没有管理Cookie或CSRF要求；不要因此混用管理员凭证。

网络统计信息可能延迟/丢失：队列最多1024条，工作线程批量最多64条，每次内部调用2秒；失败不会无界重试，以免阻塞媒体。后台“在线”和requests是活动观察值，不是精确播放计数。

## 6. 典型生命周期

1. 保持统计默认关闭，展示与产品一致的隐私说明。
2. 用户同意后register一次，将token存本地私有存储。
3. 仅向官方HTTPS `/api/`带身份头；禁止转发到第三方音频域名或重定向目标。
4. 前台按需heartbeat；普通网关活动也可刷新last。
5. 撤回时停止携带token和心跳，forget并清本地凭证；失败时仅保留删除重试所需token。

管理员 `/admin/api/forget` 是人工清除活动记录，不写用户撤回标记；两者不能混为同一隐私行为。
