Send response types in socket responses and create api package

This commit is contained in:
2021-10-22 20:47:57 -07:00
parent f001dd6079
commit 80a5867d6b
6 changed files with 317 additions and 4 deletions

102
api/client.go Normal file
View File

@@ -0,0 +1,102 @@
package api
import (
"bufio"
"encoding/json"
"errors"
"net"
"github.com/mitchellh/mapstructure"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/types"
)
const DefaultAddr = "/tmp/itd/socket"
type Client struct {
conn net.Conn
respCh chan types.Response
heartRateCh chan uint8
battLevelCh chan uint8
stepCountCh chan uint32
motionCh chan infinitime.MotionValues
dfuProgressCh chan DFUProgress
}
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) 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
}
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
}
func (c *Client) handleResp(res types.Response) error {
switch res.Type {
case types.ResTypeWatchHeartRate:
c.heartRateCh <- uint8(res.Value.(float64))
case types.ResTypeWatchBattLevel:
c.battLevelCh <- uint8(res.Value.(float64))
case types.ResTypeWatchStepCount:
c.stepCountCh <- uint32(res.Value.(float64))
case types.ResTypeWatchMotion:
out := infinitime.MotionValues{}
err := mapstructure.Decode(res.Value, &out)
if err != nil {
return err
}
c.motionCh <- out
case types.ResTypeDFUProgress:
out := DFUProgress{}
err := mapstructure.Decode(res.Value, &out)
if err != nil {
return err
}
c.dfuProgressCh <- out
default:
c.respCh <- res
}
return nil
}

121
api/info.go Normal file
View File

@@ -0,0 +1,121 @@
package api
import (
"github.com/mitchellh/mapstructure"
"go.arsenm.dev/infinitime"
"go.arsenm.dev/itd/internal/types"
)
func (c *Client) Address() (string, error) {
res, err := c.request(types.Request{
Type: types.ReqTypeBtAddress,
})
if err != nil {
return "", err
}
return res.Value.(string), nil
}
func (c *Client) Version() (string, error) {
res, err := c.request(types.Request{
Type: types.ReqTypeFwVersion,
})
if err != nil {
return "", err
}
return res.Value.(string), nil
}
func (c *Client) BatteryLevel() (uint8, error) {
res, err := c.request(types.Request{
Type: types.ReqTypeBattLevel,
})
if err != nil {
return 0, err
}
return uint8(res.Value.(float64)), nil
}
func (c *Client) WatchBatteryLevel() (<-chan uint8, error) {
c.battLevelCh = make(chan uint8, 2)
err := c.requestNoRes(types.Request{
Type: types.ReqTypeBattLevel,
})
if err != nil {
return nil, err
}
return c.battLevelCh, nil
}
func (c *Client) HeartRate() (uint8, error) {
res, err := c.request(types.Request{
Type: types.ReqTypeHeartRate,
})
if err != nil {
return 0, err
}
return uint8(res.Value.(float64)), nil
}
func (c *Client) WatchHeartRate() (<-chan uint8, error) {
c.heartRateCh = make(chan uint8, 2)
err := c.requestNoRes(types.Request{
Type: types.ReqTypeWatchHeartRate,
})
if err != nil {
return nil, err
}
return c.heartRateCh, nil
}
func (c *Client) StepCount() (uint32, error) {
res, err := c.request(types.Request{
Type: types.ReqTypeStepCount,
})
if err != nil {
return 0, err
}
return uint32(res.Value.(float64)), nil
}
func (c *Client) WatchStepCount() (<-chan uint32, error) {
c.stepCountCh = make(chan uint32, 2)
err := c.requestNoRes(types.Request{
Type: types.ReqTypeWatchStepCount,
})
if err != nil {
return nil, err
}
return c.stepCountCh, nil
}
func (c *Client) Motion() (infinitime.MotionValues, error) {
out := infinitime.MotionValues{}
res, err := c.request(types.Request{
Type: types.ReqTypeMotion,
})
if err != nil {
return out, err
}
err = mapstructure.Decode(res.Value, &out)
if err != nil {
return out, err
}
return out, nil
}
func (c *Client) WatchMotion() (<-chan infinitime.MotionValues, error) {
c.motionCh = make(chan infinitime.MotionValues, 2)
err := c.requestNoRes(types.Request{
Type: types.ReqTypeWatchMotion,
})
if err != nil {
return nil, err
}
return c.motionCh, nil
}

29
api/time.go Normal file
View File

@@ -0,0 +1,29 @@
package api
import (
"time"
"go.arsenm.dev/itd/internal/types"
)
func (c *Client) SetTime(t time.Time) error {
_, err := c.request(types.Request{
Type: types.ReqTypeSetTime,
Data: t.Format(time.RFC3339),
})
if err != nil {
return err
}
return nil
}
func (c *Client) SetTimeNow() error {
_, err := c.request(types.Request{
Type: types.ReqTypeSetTime,
Data: "now",
})
if err != nil {
return err
}
return nil
}

33
api/upgrade.go Normal file
View File

@@ -0,0 +1,33 @@
package api
import (
"encoding/json"
"go.arsenm.dev/itd/internal/types"
)
type DFUProgress types.DFUProgress
type UpgradeType uint8
const (
UpgradeTypeArchive UpgradeType = iota
UpgradeTypeFiles
)
func (c *Client) FirmwareUpgrade(upgType UpgradeType, files ...string) (<-chan DFUProgress, error) {
err := json.NewEncoder(c.conn).Encode(types.Request{
Type: types.ReqTypeFwUpgrade,
Data: types.ReqDataFwUpgrade{
Type: int(upgType),
Files: files,
},
})
if err != nil {
return nil, err
}
c.dfuProgressCh = make(chan DFUProgress, 5)
return c.dfuProgressCh, nil
}