154 lines
3.2 KiB
Go
154 lines
3.2 KiB
Go
package api
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"errors"
|
|
"net"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
"go.arsenm.dev/infinitime"
|
|
"go.arsenm.dev/itd/internal/types"
|
|
)
|
|
|
|
// Default socket address
|
|
const DefaultAddr = "/tmp/itd/socket"
|
|
|
|
// Client is the socket API client
|
|
type Client struct {
|
|
conn net.Conn
|
|
respCh chan types.Response
|
|
heartRateCh chan types.Response
|
|
battLevelCh chan types.Response
|
|
stepCountCh chan types.Response
|
|
motionCh chan types.Response
|
|
dfuProgressCh chan types.Response
|
|
readProgressCh chan types.FSTransferProgress
|
|
writeProgressCh chan types.FSTransferProgress
|
|
}
|
|
|
|
// New creates a new client and sets it up
|
|
func New(addr string) (*Client, error) {
|
|
conn, err := net.Dial("unix", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := &Client{
|
|
conn: conn,
|
|
respCh: make(chan types.Response, 5),
|
|
}
|
|
|
|
go func() {
|
|
scanner := bufio.NewScanner(conn)
|
|
for scanner.Scan() {
|
|
var res types.Response
|
|
err = json.Unmarshal(scanner.Bytes(), &res)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
out.handleResp(res)
|
|
}
|
|
}()
|
|
return out, err
|
|
}
|
|
|
|
func (c *Client) Close() error {
|
|
err := c.conn.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
close(c.respCh)
|
|
return nil
|
|
}
|
|
|
|
// request sends a request to itd and waits for and returns the response
|
|
func (c *Client) request(req types.Request) (types.Response, error) {
|
|
// Encode request into connection
|
|
err := json.NewEncoder(c.conn).Encode(req)
|
|
if err != nil {
|
|
return types.Response{}, err
|
|
}
|
|
|
|
res := <-c.respCh
|
|
|
|
if res.Error {
|
|
return res, errors.New(res.Message)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
// requestNoRes sends a request to itd and does not wait for the response
|
|
func (c *Client) requestNoRes(req types.Request) error {
|
|
// Encode request into connection
|
|
err := json.NewEncoder(c.conn).Encode(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// handleResp handles the received response as needed
|
|
func (c *Client) handleResp(res types.Response) error {
|
|
switch res.Type {
|
|
case types.ReqTypeWatchHeartRate:
|
|
c.heartRateCh <- res
|
|
case types.ReqTypeWatchBattLevel:
|
|
c.battLevelCh <- res
|
|
case types.ReqTypeWatchStepCount:
|
|
c.stepCountCh <- res
|
|
case types.ReqTypeWatchMotion:
|
|
c.motionCh <- res
|
|
case types.ReqTypeFwUpgrade:
|
|
c.dfuProgressCh <- res
|
|
case types.ReqTypeFS:
|
|
if res.Value == nil {
|
|
c.respCh <- res
|
|
break
|
|
}
|
|
var progress types.FSTransferProgress
|
|
if err := mapstructure.Decode(res.Value, &progress); err != nil {
|
|
c.respCh <- res
|
|
break
|
|
}
|
|
switch progress.Type {
|
|
case types.FSTypeRead:
|
|
c.readProgressCh <- progress
|
|
case types.FSTypeWrite:
|
|
c.writeProgressCh <- progress
|
|
default:
|
|
c.respCh <- res
|
|
}
|
|
default:
|
|
c.respCh <- res
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func decodeUint8(val interface{}) uint8 {
|
|
return uint8(val.(float64))
|
|
}
|
|
|
|
func decodeUint32(val interface{}) uint32 {
|
|
return uint32(val.(float64))
|
|
}
|
|
|
|
func decodeMotion(val interface{}) (infinitime.MotionValues, error) {
|
|
out := infinitime.MotionValues{}
|
|
err := mapstructure.Decode(val, &out)
|
|
if err != nil {
|
|
return out, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func decodeDFUProgress(val interface{}) (DFUProgress, error) {
|
|
out := DFUProgress{}
|
|
err := mapstructure.Decode(val, &out)
|
|
if err != nil {
|
|
return out, err
|
|
}
|
|
return out, nil
|
|
}
|