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