mirror of
https://github.com/sstent/aicyclingcoach-go.git
synced 2026-01-27 09:32:08 +00:00
113 lines
3.5 KiB
Go
113 lines
3.5 KiB
Go
package garmin
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/sstent/fitness-tui/internal/storage"
|
|
)
|
|
|
|
// Sync performs the complete synchronization process
|
|
func (c *Client) Sync(ctx context.Context, storage *storage.ActivityStorage, logger Logger) (int, error) {
|
|
// Create a context with timeout for the entire sync process
|
|
timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Minute)
|
|
defer cancel()
|
|
|
|
// Authenticate
|
|
logger.Infof("Authenticating with Garmin Connect...")
|
|
if err := c.Connect(logger); err != nil {
|
|
logger.Errorf("Authentication failed: %v", err)
|
|
if _, ok := err.(*AuthenticationError); ok {
|
|
return 0, fmt.Errorf("authentication failed: please check your credentials and try again")
|
|
}
|
|
return 0, err
|
|
}
|
|
logger.Infof("Authentication successful")
|
|
|
|
// Get all activities metadata
|
|
logger.Infof("Fetching activity metadata...")
|
|
activities, err := c.GetAllActivities(timeoutCtx, logger)
|
|
if err != nil {
|
|
logger.Errorf("Failed to fetch activities: %v", err)
|
|
return 0, err
|
|
}
|
|
logger.Infof("Found %d activities", len(activities))
|
|
|
|
// Download files for each activity
|
|
downloadedFiles := 0
|
|
for i := range activities {
|
|
activity := &activities[i]
|
|
// Check if context has been cancelled
|
|
select {
|
|
case <-timeoutCtx.Done():
|
|
logger.Warnf("Sync cancelled due to timeout")
|
|
return downloadedFiles, timeoutCtx.Err()
|
|
default:
|
|
}
|
|
|
|
logger.Infof("Processing activity %d/%d: %s", i+1, len(activities), activity.Name)
|
|
|
|
// Only download if file doesn't exist
|
|
if activity.FilePath == "" {
|
|
logger.Infof("File missing for activity %s, attempting download...", activity.ID)
|
|
var data []byte
|
|
var format string
|
|
var err error
|
|
|
|
// First try FIT (preferred)
|
|
logger.Infof("Trying FIT download for %s...", activity.ID)
|
|
data, err = c.DownloadActivityFile(timeoutCtx, activity.ID, "fit", logger)
|
|
if err == nil {
|
|
format = "fit"
|
|
logger.Infof("FIT download successful for %s (%d bytes)", activity.ID, len(data))
|
|
} else {
|
|
logger.Warnf("FIT download failed for %s: %v", activity.ID, err)
|
|
|
|
// Fallback to GPX
|
|
logger.Infof("Trying GPX download for %s...", activity.ID)
|
|
data, err = c.DownloadActivityFile(timeoutCtx, activity.ID, "gpx", logger)
|
|
if err == nil {
|
|
format = "gpx"
|
|
logger.Infof("GPX download successful for %s (%d bytes)", activity.ID, len(data))
|
|
} else {
|
|
logger.Warnf("GPX download failed for %s: %v", activity.ID, err)
|
|
|
|
// Fallback to TCX
|
|
logger.Infof("Trying TCX download for %s...", activity.ID)
|
|
data, err = c.DownloadActivityFile(timeoutCtx, activity.ID, "tcx", logger)
|
|
if err != nil {
|
|
logger.Errorf("TCX download failed for %s: %v", activity.ID, err)
|
|
continue
|
|
}
|
|
format = "tcx"
|
|
logger.Infof("TCX download successful for %s (%d bytes)", activity.ID, len(data))
|
|
}
|
|
}
|
|
|
|
// Save file to storage
|
|
logger.Infof("Saving %s file for %s...", format, activity.ID)
|
|
filePath, err := storage.SaveActivityFile(activity, data, format)
|
|
if err != nil {
|
|
logger.Errorf("Failed to save activity file for %s: %v", activity.ID, err)
|
|
continue
|
|
}
|
|
logger.Infof("Saved file to %s", filePath)
|
|
|
|
// Update activity with file path
|
|
activity.FilePath = filePath
|
|
downloadedFiles++
|
|
} else {
|
|
logger.Infof("File already exists for %s: %s", activity.ID, activity.FilePath)
|
|
}
|
|
|
|
// Save updated activity metadata
|
|
logger.Infof("Saving metadata for %s...", activity.ID)
|
|
if err := storage.Save(activity); err != nil {
|
|
logger.Errorf("Failed to save activity metadata for %s: %v", activity.ID, err)
|
|
}
|
|
}
|
|
|
|
return downloadedFiles, nil
|
|
}
|