reworked api interfaces

This commit is contained in:
2025-09-22 16:41:49 -07:00
parent f2256a9cfe
commit 1b3fb04dcd
44 changed files with 1356 additions and 207 deletions

View File

@@ -6,7 +6,7 @@ import (
"sort"
"time"
types "github.com/sstent/go-garth/internal/models/types"
garth "github.com/sstent/go-garth/pkg/garth/types"
shared "github.com/sstent/go-garth/shared/interfaces"
)
@@ -19,38 +19,92 @@ type BodyBatteryReading struct {
}
// ParseBodyBatteryReadings converts body battery values array to structured readings
// Accepts mixed numeric types (int, int64, float64, json.Number) for robustness.
func ParseBodyBatteryReadings(valuesArray [][]any) []BodyBatteryReading {
readings := make([]BodyBatteryReading, 0)
readings := make([]BodyBatteryReading, 0, len(valuesArray))
toInt := func(v any) (int, bool) {
switch t := v.(type) {
case int:
return t, true
case int32:
return int(t), true
case int64:
return int(t), true
case float32:
return int(t), true
case float64:
return int(t), true
case json.Number:
i, err := t.Int64()
if err == nil {
return int(i), true
}
f, err := t.Float64()
if err == nil {
return int(f), true
}
return 0, false
default:
return 0, false
}
}
toFloat64 := func(v any) (float64, bool) {
switch t := v.(type) {
case float32:
return float64(t), true
case float64:
return t, true
case int:
return float64(t), true
case int32:
return float64(t), true
case int64:
return float64(t), true
case json.Number:
f, err := t.Float64()
if err == nil {
return f, true
}
return 0, false
default:
return 0, false
}
}
for _, values := range valuesArray {
if len(values) < 4 {
continue
}
timestamp, ok1 := values[0].(float64)
ts, ok1 := toInt(values[0])
status, ok2 := values[1].(string)
level, ok3 := values[2].(float64)
version, ok4 := values[3].(float64)
lvl, ok3 := toInt(values[2])
ver, ok4 := toFloat64(values[3])
if !ok1 || !ok2 || !ok3 || !ok4 {
continue
}
readings = append(readings, BodyBatteryReading{
Timestamp: int(timestamp),
Timestamp: ts,
Status: status,
Level: int(level),
Version: version,
Level: lvl,
Version: ver,
})
}
sort.Slice(readings, func(i, j int) bool {
return readings[i].Timestamp < readings[j].Timestamp
})
return readings
}
// BodyBatteryDataWithMethods embeds types.DetailedBodyBatteryData and adds methods
// BodyBatteryDataWithMethods embeds garth.DetailedBodyBatteryData and adds methods
type BodyBatteryDataWithMethods struct {
types.DetailedBodyBatteryData
garth.DetailedBodyBatteryData
}
func (d *BodyBatteryDataWithMethods) Get(day time.Time, c shared.APIClient) (interface{}, error) {
@@ -71,14 +125,14 @@ func (d *BodyBatteryDataWithMethods) Get(day time.Time, c shared.APIClient) (int
data2 = []byte("[]")
}
var result types.DetailedBodyBatteryData
var result garth.DetailedBodyBatteryData
if len(data1) > 0 {
if err := json.Unmarshal(data1, &result); err != nil {
return nil, fmt.Errorf("failed to parse Body Battery data: %w", err)
}
}
var events []types.BodyBatteryEvent
var events []garth.BodyBatteryEvent
if len(data2) > 0 {
if err := json.Unmarshal(data2, &events); err == nil {
result.Events = events
@@ -111,3 +165,48 @@ func (d *BodyBatteryDataWithMethods) GetDayChange() int {
return readings[len(readings)-1].Level - readings[0].Level
}
// Added for test compatibility and public API alignment
// DailyBodyBatteryStress wraps garth.DetailedBodyBatteryData and provides a Get method compatible with existing tests.
// See [type DailyBodyBatteryStress](internal/data/body_battery.go:0) and [func (*DailyBodyBatteryStress).Get](internal/data/body_battery.go:0)
type DailyBodyBatteryStress struct {
garth.DetailedBodyBatteryData
}
// Get retrieves Body Battery daily stress data and associated events for a given day.
// Mirrors logic in BodyBatteryDataWithMethods.Get to maintain a consistent behavior.
// Returns (*DailyBodyBatteryStress, nil) on success, (nil, nil) when no data available.
func (d *DailyBodyBatteryStress) Get(day time.Time, c shared.APIClient) (interface{}, error) {
dateStr := day.Format("2006-01-02")
// Get main Body Battery data
path1 := fmt.Sprintf("/wellness-service/wellness/dailyStress/%s", dateStr)
data1, err := c.ConnectAPI(path1, "GET", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get Body Battery stress data: %w", err)
}
// Get Body Battery events
path2 := fmt.Sprintf("/wellness-service/wellness/bodyBattery/%s", dateStr)
data2, err := c.ConnectAPI(path2, "GET", nil, nil)
if err != nil {
// Events might not be available, continue without them
data2 = []byte("[]")
}
var result garth.DetailedBodyBatteryData
if len(data1) > 0 {
if err := json.Unmarshal(data1, &result); err != nil {
return nil, fmt.Errorf("failed to parse Body Battery data: %w", err)
}
}
var events []garth.BodyBatteryEvent
if len(data2) > 0 {
if err := json.Unmarshal(data2, &events); err == nil {
result.Events = events
}
}
return &DailyBodyBatteryStress{DetailedBodyBatteryData: result}, nil
}