mirror of
https://github.com/sstent/GarminSync.git
synced 2026-01-25 16:42:20 +00:00
107 lines
2.7 KiB
Go
107 lines
2.7 KiB
Go
package garmin
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
garminconnect "github.com/abrander/garmin-connect"
|
|
"github.com/sstent/garminsync/internal/config"
|
|
)
|
|
|
|
// Client represents a Garmin Connect API client
|
|
type Client struct {
|
|
client *garminconnect.Client
|
|
cfg *config.Config
|
|
lastAuth time.Time
|
|
}
|
|
|
|
const (
|
|
defaultSessionTimeout = 30 * time.Minute
|
|
)
|
|
|
|
// NewClient creates a new Garmin Connect client
|
|
func NewClient(cfg *config.Config) (*Client, error) {
|
|
// Create client with session persistence
|
|
client := garminconnect.NewClient(garminconnect.Credentials(cfg.GarminEmail, cfg.GarminPassword))
|
|
client.SessionFile = cfg.SessionPath
|
|
|
|
// Attempt to load existing session
|
|
if err := client.Authenticate(); err != nil {
|
|
return nil, fmt.Errorf("authentication failed: %w", err)
|
|
}
|
|
|
|
return &Client{
|
|
client: client,
|
|
cfg: cfg,
|
|
lastAuth: time.Now(),
|
|
}, nil
|
|
}
|
|
|
|
// checkSession checks if session is still valid, refreshes if expired
|
|
func (c *Client) checkSession() error {
|
|
timeout := c.cfg.SessionTimeout
|
|
if timeout == 0 {
|
|
timeout = defaultSessionTimeout
|
|
}
|
|
|
|
if time.Since(c.lastAuth) > timeout {
|
|
if err := c.client.Authenticate(); err != nil {
|
|
return fmt.Errorf("session refresh failed: %w", err)
|
|
}
|
|
c.lastAuth = time.Now()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetActivities retrieves activities from Garmin Connect
|
|
func (c *Client) GetActivities() ([]Activity, error) {
|
|
// Check and refresh session if needed
|
|
if err := c.checkSession(); err != nil {
|
|
return nil, err
|
|
}
|
|
// Get activities from Garmin Connect
|
|
garminActivities, err := c.client.Activities("", 0, 100) // Empty string = current user
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get activities: %w", err)
|
|
}
|
|
|
|
// Convert to our Activity struct
|
|
var activities []Activity
|
|
for _, ga := range garminActivities {
|
|
activities = append(activities, Activity{
|
|
ActivityId: int(ga.ID),
|
|
StartTime: time.Time(ga.StartLocal),
|
|
Filename: fmt.Sprintf("activity_%d_%s.fit", ga.ID, ga.StartLocal.Time().Format("20060102")),
|
|
Downloaded: false,
|
|
})
|
|
}
|
|
|
|
return activities, nil
|
|
}
|
|
|
|
// DownloadActivityFIT downloads a specific FIT file
|
|
func (c *Client) DownloadActivityFIT(activityId int, filename string) error {
|
|
// Check and refresh session if needed
|
|
if err := c.checkSession(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Apply rate limiting
|
|
time.Sleep(c.cfg.RateLimit)
|
|
|
|
// Create file for writing
|
|
file, err := os.Create(filename)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// Download FIT file
|
|
if err := c.client.ExportActivity(activityId, file, garminconnect.ActivityFormatFIT); err != nil {
|
|
return fmt.Errorf("failed to export activity %d: %w", activityId, err)
|
|
}
|
|
|
|
return nil
|
|
}
|