Files
4566704 b808e51b3e refactor: 重大架构升级 — HomeID/RoomID int64化 + 设备驱动重构 + 结构化日志
主要变更:

**类型系统重构**
- HomeInfo.ID/RoomInfo.ID/HomeID 从 string 改为 int64,json tag 使用 ,string
- GetHome/GetRooms/GetRoomDevices 接口同步修改
- 新增 int64FromStr 工具函数,更新 parseHomeInfo 解析逻辑

**新增 Speaker 设备**
- 新增 KindSpeaker 类型
- classify 映射覆盖 speaker/bluetooth-speaker/alarm-clock/media-player/playback/music

**设备驱动重构**
- AC 驱动彻底重写:从硬编码常量改为基于 SPEC ValueList 的动态 valMapper
- 所有设备(Fan/Humidifier/Light/OccupancySensor/Switch/TempHumiditySensor/Thermostat/Vacuum/WaterHeater/Cover)新增 GetState() 和 FetchState(ctx) 接口
- base.go 新增 specResolver.format() 方法

**MIoT 模块增强**
- MIoTClient 新增 homeIDs 字段,支持按家庭过滤设备
- RefreshDevices 支持 homeIDs 参数
- SpecStdLib 引入 logger.Logger,log.Printf 全部迁移为结构化日志

**其他**
- Config 新增 RedirectURL 和 HomeIDs 字段
- AuthInfo.ExpiresIn 类型从 int 改为 int32
- UUID 生成简化为 hex.EncodeToString
- 新增 github.com/sirupsen/logrus 依赖
- .gitignore 新增 examples/*/data/ 忽略规则
- 删除已提交的 config.json 敏感配置
2026-07-13 10:40:20 +08:00

104 lines
3.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# token 管理重构方案
> 2026-06-29
## 原则
- mloT 层方法签名不变(`Init()` / `NewMIoTClient` 等)
- xiaomi 层只改 `NewClient` 签名(架构必须改),其他全部不动
---
## 修改清单
### 1. miot: `Init()` 内部逻辑修复(签名不变)
当前 Init 从 entryData 取 token,storage 白读。改为优先读 storage,首次没数据才回退 entryData 并写入 storage:
```go
func (c *MIoTClient) Init() error {
// 尝试从 storage 取 token
if c.storage != nil {
authInfo := c.storage.LoadUserConfig(c.uid, c.cloudServer, nil)
if authInfo == nil {
// 首次:从 entryData 取,写入 storage
c.storage.UpdateUserConfig(c.uid, c.cloudServer, map[string]interface{}{
"access_token": c.entryData["access_token"],
"refresh_token": c.entryData["refresh_token"],
"expires_ts": c.entryData["expires_ts"],
}, true)
} else if t, ok := authInfo["access_token"].(string); ok && t != "" {
c.entryData["access_token"] = t // 覆盖给后续 HTTP/MIPS 创建用
}
}
// 后续现有逻辑不变...
}
```
### 2. miot: 新增 `RefreshAuthInfo()`(不破坏旧签名)
```go
// RefreshAuthInfo 手动触发 token 刷新(对齐 Python refresh_oauth_info_async)
// 返回 {access_token, refresh_token, expires_ts}
func (c *MIoTClient) RefreshAuthInfo() (map[string]interface{}, error)
```
内部复用现有的 `refreshAuthInfo` 逻辑,改为同步返回结果。
### 3. xiaomi: Config 改签名(唯一需要调用方改的地方)
```go
type Config struct {
AccessToken string
RefreshToken string // 可选,用于自动/手动刷新
}
```
`NewClient(ctx, Config)` 替代 `NewClient(inner, httpClient)`。内部把 `AccessToken` / `RefreshToken` 放进 entryData,Init 自动写入 storage。
### 4. xiaomi: 新增 `RefreshToken()`(其他方法不动)
```go
// RefreshToken 手动刷新 token,返回新值让调用方存库
func (c *Client) RefreshToken(ctx context.Context) (*TokenResult, error)
type TokenResult struct {
AccessToken string
RefreshToken string
ExpiresTS int64
}
```
### 5. 清理 entryData 无用字段
miot 中去掉 `country_code`,xiaomi 中不再出现。
---
## 影响范围
| 层 | 方法 | 改动 | 调用方影响 |
|----|------|------|------------|
| miot | `Init()` | 内部逻辑 | 无(签名不变) |
| miot | `RefreshAuthInfo()` | 新增 | 无(新增方法) |
| xiaomi | `NewClient` | 签名改为 `(ctx, Config)` | **调用方需改** |
| xiaomi | `Close()` | 新增 | 无 |
| xiaomi | `RefreshToken()` | 新增 | 无 |
| xiaomi | 其他所有方法 | 不动 | 无 |
---
## 使用示例
```go
client, err := xiaomi.NewClient(ctx, xiaomi.Config{
AccessToken: token,
RefreshToken: refreshToken,
})
defer client.Close()
// 手动刷新
result, err := client.RefreshToken(ctx)
db.Save(userID, result.AccessToken, result.RefreshToken)
```