Send response types in socket responses and create api package
This commit is contained in:
parent
b63960ed88
commit
a235903583
102
api/client.go
Normal file
102
api/client.go
Normal 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
121
api/info.go
Normal 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
29
api/time.go
Normal 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
33
api/upgrade.go
Normal 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
|
||||
}
|
@ -16,6 +16,22 @@ const (
|
||||
ReqTypeWatchStepCount
|
||||
)
|
||||
|
||||
const (
|
||||
ResTypeHeartRate = iota
|
||||
ResTypeBattLevel
|
||||
ResTypeFwVersion
|
||||
ResTypeDFUProgress
|
||||
ResTypeBtAddress
|
||||
ResTypeNotify
|
||||
ResTypeSetTime
|
||||
ResTypeWatchHeartRate
|
||||
ResTypeWatchBattLevel
|
||||
ResTypeMotion
|
||||
ResTypeWatchMotion
|
||||
ResTypeStepCount
|
||||
ResTypeWatchStepCount
|
||||
)
|
||||
|
||||
const (
|
||||
UpgradeTypeArchive = iota
|
||||
UpgradeTypeFiles
|
||||
@ -27,6 +43,7 @@ type ReqDataFwUpgrade struct {
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Type int
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
Message string `json:"msg,omitempty"`
|
||||
Error bool `json:"error"`
|
||||
|
19
socket.go
19
socket.go
@ -102,6 +102,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
}
|
||||
// Encode heart rate to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeHeartRate,
|
||||
Value: heartRate,
|
||||
})
|
||||
case types.ReqTypeWatchHeartRate:
|
||||
@ -113,6 +114,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
go func() {
|
||||
for heartRate := range heartRateCh {
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeWatchHeartRate,
|
||||
Value: heartRate,
|
||||
})
|
||||
}
|
||||
@ -126,17 +128,19 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
}
|
||||
// Encode battery level to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeBattLevel,
|
||||
Value: battLevel,
|
||||
})
|
||||
case types.ReqTypeWatchBattLevel:
|
||||
battLevelCh, err := dev.WatchBatteryLevel()
|
||||
if err != nil {
|
||||
connErr(conn, err, "Error getting heart rate channel")
|
||||
connErr(conn, err, "Error getting battery level channel")
|
||||
break
|
||||
}
|
||||
go func() {
|
||||
for battLevel := range battLevelCh {
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeWatchBattLevel,
|
||||
Value: battLevel,
|
||||
})
|
||||
}
|
||||
@ -150,6 +154,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
}
|
||||
// Encode battery level to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeMotion,
|
||||
Value: motionVals,
|
||||
})
|
||||
case types.ReqTypeWatchMotion:
|
||||
@ -161,6 +166,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
go func() {
|
||||
for motionVals := range motionValCh {
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeWatchMotion,
|
||||
Value: motionVals,
|
||||
})
|
||||
}
|
||||
@ -174,6 +180,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
}
|
||||
// Encode battery level to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeStepCount,
|
||||
Value: stepCount,
|
||||
})
|
||||
case types.ReqTypeWatchStepCount:
|
||||
@ -185,6 +192,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
go func() {
|
||||
for stepCount := range stepCountCh {
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeWatchStepCount,
|
||||
Value: stepCount,
|
||||
})
|
||||
}
|
||||
@ -193,16 +201,18 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
// Get firmware version from watch
|
||||
version, err := dev.Version()
|
||||
if err != nil {
|
||||
connErr(conn, err, "Error getting battery level")
|
||||
connErr(conn, err, "Error getting firmware version")
|
||||
break
|
||||
}
|
||||
// Encode version to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeFwVersion,
|
||||
Value: version,
|
||||
})
|
||||
case types.ReqTypeBtAddress:
|
||||
// Encode bluetooth address to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeBtAddress,
|
||||
Value: dev.Address(),
|
||||
})
|
||||
case types.ReqTypeNotify:
|
||||
@ -229,7 +239,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
break
|
||||
}
|
||||
// Encode empty types.Response to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{})
|
||||
json.NewEncoder(conn).Encode(types.Response{Type: types.ResTypeNotify})
|
||||
case types.ReqTypeSetTime:
|
||||
// If no data, return error
|
||||
if req.Data == nil {
|
||||
@ -261,7 +271,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
break
|
||||
}
|
||||
// Encode empty types.Response to connection
|
||||
json.NewEncoder(conn).Encode(types.Response{})
|
||||
json.NewEncoder(conn).Encode(types.Response{Type: types.ResTypeSetTime})
|
||||
case types.ReqTypeFwUpgrade:
|
||||
// If no data, return error
|
||||
if req.Data == nil {
|
||||
@ -326,6 +336,7 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||
for event := range progress {
|
||||
// Encode event on connection
|
||||
json.NewEncoder(conn).Encode(types.Response{
|
||||
Type: types.ResTypeDFUProgress,
|
||||
Value: event,
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user