# Aster

WebSocket 中继服务 + HTTP 事件 API，用于设备间通信。

## 服务端口

| 端口 | 协议 | 用途 |
|------|------|------|
| 8765 | WebSocket | 设备连接、消息广播/直发、在线状态 |
| 8766 | HTTP | 事件推送/查询 API、API 文档 |

端口可通过环境变量 `ASTER_PORT` 和 `ASTER_API_PORT` 覆盖。

## 鉴权

所有接口（WebSocket 连接和 HTTP API）共享同一个 token，通过环境变量 `ASTER_AUTH_TOKEN` 配置。

两种传递方式（任选其一）：

- 请求头：`Authorization: Bearer <token>`
- 查询参数：`?token=<token>`

`/health` 和 `/`（本文档）始终免鉴权。

## HTTP 事件 API（端口 8766）

### POST /event/push

推送事件数据。每次推送覆盖同名事件的旧数据。

**请求：**

```
POST /event/push
Authorization: Bearer <token>
Content-Type: application/json

{"name": "temperature", "data": {"value": 23.5, "unit": "celsius"}}
```

**响应 200：**

```json
{"status": "ok", "event": "temperature", "timestamp": 1719500000000}
```

**错误：**

| 状态码 | 说明 |
|--------|------|
| 400 | 缺少 `name` 或 `data` 字段，或 JSON 格式错误 |
| 401 | 未鉴权或 token 错误 |

### GET /event/latest

查询指定事件的最新数据。

**请求：**

```
GET /event/latest?name=temperature
Authorization: Bearer <token>
```

**响应 200：**

```json
{"event": "temperature", "data": {"value": 23.5, "unit": "celsius"}, "timestamp": 1719500000000}
```

**错误：**

| 状态码 | 说明 |
|--------|------|
| 400 | 缺少 `name` 参数 |
| 404 | 事件不存在 |
| 401 | 未鉴权或 token 错误 |

## WebSocket API（端口 8765）

### 连接

```
wss://aster.xindoo.xyz/?token=<token>&device_id=<device_id>&name=<device_name>
```

连接时通过 URL 参数自动注册（传 `device_id` 和 `name`）。

### 消息信封

```json
{
  "id": "uuid-v4",
  "type": "message.broadcast",
  "from": "device-1",
  "to": "broadcast",
  "timestamp": 1719500000000,
  "payload": {},
  "correlation_id": null,
  "requires_ack": false
}
```

### 消息类型

| 类型 | 方向 | 说明 |
|------|------|------|
| `device.registered` | 服务器→设备 | 注册确认，含心跳间隔 |
| `device.unregister` | 设备→服务器 | 主动断开 |
| `presence.announce` | 服务器→所有 | 新设备上线 |
| `presence.leave` | 服务器→所有 | 设备离线（`reason: "shutdown"` 或 `"timeout"`） |
| `presence.list` | 服务器→设备 | 在线设备列表 |
| `heartbeat` | 设备→服务器 | 心跳 |
| `heartbeat.ack` | 服务器→设备 | 心跳确认 |
| `message.broadcast` | 设备→服务器→所有 | 广播消息（排除发送者） |
| `message.direct` | 设备→服务器→设备 | 直发消息 |
| `system.error` | 服务器→设备 | 错误（`code`, `message`） |

### 广播示例

```json
{"id":"a1b2","type":"message.broadcast","from":"phone","to":"broadcast","timestamp":1719500000000,"payload":{"text":"hello"}}
```

所有其他设备收到相同消息。

### 直发示例

```json
{"id":"c3d4","type":"message.direct","from":"phone","to":"laptop","timestamp":1719500000000,"payload":{"text":"private"}}
```

### 连接生命周期

1. 设备连接 WebSocket（URL 参数带 `token`、`device_id`、`name`）
2. 服务器自动注册，返回 `device.registered` + `presence.list`
3. 服务器向其他设备广播 `presence.announce`
4. 设备每 30 秒发送 `heartbeat`，服务器回复 `heartbeat.ack`
5. 设备发送 `message.broadcast` / `message.direct`
6. 断开时服务器广播 `presence.leave`

## 健康检查

```
GET https://aster.xindoo.xyz/health
```

```json
{"status": "healthy", "devices": 3}
```
