Add support events for HomeKit client
This commit is contained in:
@@ -41,6 +41,9 @@ type Client struct {
|
|||||||
|
|
||||||
Conn net.Conn
|
Conn net.Conn
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
|
|
||||||
|
res chan *http.Response
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(rawURL string) (*Client, error) {
|
func NewClient(rawURL string) (*Client, error) {
|
||||||
@@ -216,6 +219,8 @@ func (c *Client) Dial() (err error) {
|
|||||||
// new reader for new conn
|
// new reader for new conn
|
||||||
c.reader = bufio.NewReaderSize(c.Conn, 32*1024) // 32K like default request body
|
c.reader = bufio.NewReaderSize(c.Conn, 32*1024) // 32K like default request body
|
||||||
|
|
||||||
|
go c.eventsReader()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +233,32 @@ func (c *Client) Close() error {
|
|||||||
return conn.Close()
|
return conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) eventsReader() {
|
||||||
|
c.res = make(chan *http.Response)
|
||||||
|
|
||||||
|
for {
|
||||||
|
var res *http.Response
|
||||||
|
if res, c.err = ReadResponse(c.reader, nil); c.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var body []byte
|
||||||
|
if body, c.err = io.ReadAll(res.Body); c.err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Body = io.NopCloser(bytes.NewReader(body))
|
||||||
|
|
||||||
|
if res.Proto != ProtoEvent {
|
||||||
|
c.res <- res
|
||||||
|
} else if c.OnEvent != nil {
|
||||||
|
c.OnEvent(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(c.res)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetAccessories() ([]*Accessory, error) {
|
func (c *Client) GetAccessories() ([]*Accessory, error) {
|
||||||
res, err := c.Get(PathAccessories)
|
res, err := c.Get(PathAccessories)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hap
|
package hap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -22,6 +23,9 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
|||||||
if err := req.Write(c.Conn); err != nil {
|
if err := req.Write(c.Conn); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if c.res != nil {
|
||||||
|
return <-c.res, c.err
|
||||||
|
}
|
||||||
return http.ReadResponse(c.reader, req)
|
return http.ReadResponse(c.reader, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,3 +58,27 @@ func (c *Client) Post(path, contentType string, body io.Reader) (*http.Response,
|
|||||||
func (c *Client) Put(path, contentType string, body io.Reader) (*http.Response, error) {
|
func (c *Client) Put(path, contentType string, body io.Reader) (*http.Response, error) {
|
||||||
return c.Request("PUT", path, contentType, body)
|
return c.Request("PUT", path, contentType, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProtoEvent = "EVENT/1.0"
|
||||||
|
|
||||||
|
func ReadResponse(r *bufio.Reader, req *http.Request) (*http.Response, error) {
|
||||||
|
b, err := r.Peek(9)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != ProtoEvent {
|
||||||
|
return http.ReadResponse(r, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(b, "HTTP/1.1 ")
|
||||||
|
|
||||||
|
res, err := http.ReadResponse(r, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Proto = ProtoEvent
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
package hap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventReader struct {
|
|
||||||
r io.Reader
|
|
||||||
ch chan []byte
|
|
||||||
err error
|
|
||||||
left []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEventReader(r io.Reader) *EventReader {
|
|
||||||
e := &EventReader{r: r, ch: make(chan []byte, 1)}
|
|
||||||
go e.background()
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventReader) background() {
|
|
||||||
b := make([]byte, 32*1024)
|
|
||||||
for {
|
|
||||||
n, err := e.r.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
e.err = err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if n >= 6 && string(b[:6]) == "EVENT " {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy because will be overwriten
|
|
||||||
buf := make([]byte, n)
|
|
||||||
copy(buf, b)
|
|
||||||
e.ch <- buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EventReader) Read(p []byte) (n int, err error) {
|
|
||||||
if e.err != nil {
|
|
||||||
return 0, e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if something left after previous reading
|
|
||||||
if e.left != nil {
|
|
||||||
// if still something left
|
|
||||||
if n = copy(p, e.left); n < len(e.left) {
|
|
||||||
e.left = e.left[n:]
|
|
||||||
} else {
|
|
||||||
e.left = nil
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-time.After(time.Second * 5):
|
|
||||||
return 0, os.ErrDeadlineExceeded
|
|
||||||
case b := <-e.ch:
|
|
||||||
if n = copy(p, b); n < len(b) {
|
|
||||||
e.left = b[n:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
+2
-1
@@ -66,7 +66,8 @@ type JSONCharacters struct {
|
|||||||
type JSONCharacter struct {
|
type JSONCharacter struct {
|
||||||
AID uint8 `json:"aid"`
|
AID uint8 `json:"aid"`
|
||||||
IID uint64 `json:"iid"`
|
IID uint64 `json:"iid"`
|
||||||
Value any `json:"value"`
|
Value any `json:"value,omitempty"`
|
||||||
|
Event any `json:"ev,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SanitizePin(pin string) (string, error) {
|
func SanitizePin(pin string) (string, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user