forked from Elara6331/itd
		
	Send response types in socket responses and create api package
This commit is contained in:
		
							
								
								
									
										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, | ||||||
| 					}) | 					}) | ||||||
| 				} | 				} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user