diff --git a/README.md b/README.md index 10da20f..f4ebc33 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,25 @@ func main() { `auth.json` 包含 `serviceToken`、`passToken`、`ssecurity` 等敏感认证数据。库写入该文件时使用 `0600` 权限;请保持此权限,并且不要将该文件提交到版本库。 +Web/GUI 应用可通过 `WithQRWriter` 接收登录输出,再将其展示给用户: + +```go +var loginOutput bytes.Buffer +client, err := mijia.NewClient("", mijia.WithQRWriter(&loginOutput)) +if err != nil { + return err +} + +if _, err := client.Login(ctx); err != nil { + return err +} + +// loginOutput 包含二维码 URL 和终端二维码文本,可交给 Web/GUI 展示层。 +renderLoginOutput(loginOutput.String()) +``` + +Writer 接收的内容包含登录二维码 URL,属于敏感登录信息;调用方不得将其写入日志、监控事件或其他持久化记录。 + ## 底层 API 以下示例展示设备、属性和 action 的直接调用。`GetDevices` 的 `homeID` 传空字符串时查询所有家庭。 diff --git a/client.go b/client.go index 0c3857b..d7b9465 100644 --- a/client.go +++ b/client.go @@ -36,6 +36,17 @@ func WithHTTPClient(httpClient *http.Client) Option { } } +// WithQRWriter configures where QR login output is written. +func WithQRWriter(writer io.Writer) Option { + return func(client *Client) error { + if writer == nil { + return fmt.Errorf("QR writer must not be nil") + } + client.qrWriter = writer + return nil + } +} + type Client struct { authPath string authMu sync.RWMutex diff --git a/client_test.go b/client_test.go index 1a11dc8..1c8c6e0 100644 --- a/client_test.go +++ b/client_test.go @@ -12,12 +12,41 @@ import ( "net/http/cookiejar" "net/http/httptest" "net/url" + "os" "strings" "sync" "testing" "time" ) +func TestWithQRWriter(t *testing.T) { + var output bytes.Buffer + client, err := NewClient(t.TempDir(), WithQRWriter(&output)) + if err != nil { + t.Fatal(err) + } + if client.qrWriter != &output { + t.Fatalf("qrWriter = %v, want custom writer", client.qrWriter) + } +} + +func TestWithQRWriterRejectsNil(t *testing.T) { + _, err := NewClient(t.TempDir(), WithQRWriter(nil)) + if err == nil || err.Error() != "QR writer must not be nil" { + t.Fatalf("error = %v, want QR writer must not be nil", err) + } +} + +func TestDefaultQRWriterIsStdout(t *testing.T) { + client, err := NewClient(t.TempDir()) + if err != nil { + t.Fatal(err) + } + if client.qrWriter != os.Stdout { + t.Fatalf("qrWriter = %v, want os.Stdout", client.qrWriter) + } +} + func TestRequestEncryptedPostAndPlainResponse(t *testing.T) { var received url.Values handlerErrors := make(chan error, 1)