X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=gfitsync.go;h=9eadde9efb66f919d278328f0daf06a0168840f7;hb=4c298110b1564f337cd0ceaad8e94fd4d4f7741f;hp=b7aa36d5d7a3964b5c6cbdb67f15bf7529749718;hpb=ad911fb5b8a17f238e6158b4f9479c5f8c428bff;p=kraftakt.git
diff --git a/gfitsync.go b/gfitsync.go
index b7aa36d..9eadde9 100644
--- a/gfitsync.go
+++ b/gfitsync.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
+ "sync"
"time"
"github.com/octo/gfitsync/app"
@@ -82,7 +83,11 @@ func indexHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u
}
haveGoogleToken := err == nil
- fmt.Fprintln(w, "
Fitbit to Google Fit sync
")
+ fmt.Fprintln(w, "Kraftakt")
+ fmt.Fprintln(w, "Kraftakt
")
+
+ fmt.Fprintln(w, "Kraftakt copies your Fitbit data to Google Fit, seconds after you sync.
")
+
fmt.Fprintf(w, "Hello %s
\n", user.Current(ctx).Email)
fmt.Fprintln(w, "")
@@ -94,7 +99,7 @@ func indexHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, u
}
fmt.Fprintln(w, "")
- fmt.Fprint(w, "- Google: ")
+ fmt.Fprint(w, "
- Google Fit: ")
if haveGoogleToken {
fmt.Fprint(w, `Authorized`)
} else {
@@ -121,8 +126,11 @@ func fitbitGrantHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
return err
}
- if err := c.Subscribe(ctx, "activities"); err != nil {
- return fmt.Errorf("c.Subscribe() = %v", err)
+ for _, collection := range []string{"activities", "sleep"} {
+ if err := c.Subscribe(ctx, collection); err != nil {
+ return fmt.Errorf("c.Subscribe(%q) = %v", collection, err)
+ }
+ log.Infof(ctx, "Successfully subscribed to %q", collection)
}
redirectURL := r.URL
@@ -201,6 +209,7 @@ func handleNotifications(ctx context.Context, payload []byte) error {
for _, s := range subscriptions {
if s.CollectionType != "activities" {
+ log.Warningf(ctx, "ignoring collection type %q", s.CollectionType)
continue
}
@@ -224,32 +233,126 @@ func handleNotification(ctx context.Context, s *fitbit.Subscription) error {
return err
}
- profile, err := fitbitClient.Profile(ctx)
- if err != nil {
- return err
+ var (
+ wg = &sync.WaitGroup{}
+ errs appengine.MultiError
+ summary *fitbit.ActivitySummary
+ profile *fitbit.Profile
+ )
+
+ wg.Add(1)
+ go func() {
+ var err error
+ summary, err = fitbitClient.ActivitySummary(ctx, s.Date)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("fitbitClient.ActivitySummary(%q) = %v", s.Date, err))
+ }
+ wg.Done()
+ }()
+
+ wg.Add(1)
+ go func() {
+ var err error
+ profile, err = fitbitClient.Profile(ctx)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("fitbitClient.Profile(%q) = %v", s.Date, err))
+ }
+ wg.Done()
+ }()
+
+ wg.Wait()
+ if len(errs) != 0 {
+ return errs
}
- log.Debugf(ctx, "profile = %+v", profile)
tm, err := time.ParseInLocation("2006-01-02", s.Date, profile.Timezone)
if err != nil {
return err
}
- summary, err := fitbitClient.ActivitySummary(tm)
- if err != nil {
- return err
- }
log.Debugf(ctx, "%s (%s) took %d steps on %s",
- profile.Name, u.Email, summary.Summary.Steps, s.Date)
+ profile.Name, u.Email, summary.Summary.Steps, tm)
gfitClient, err := gfit.NewClient(ctx, u)
if err != nil {
return err
}
- if err := gfitClient.SetSteps(ctx, summary.Summary.Steps, tm); err != nil {
- return fmt.Errorf("gfitClient.SetSteps(%d) = %v", summary.Summary.Steps, err)
- }
+ wg.Add(1)
+ go func() {
+ if err := gfitClient.SetSteps(ctx, summary.Summary.Steps, tm); err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetSteps(%d) = %v", summary.Summary.Steps, err))
+ }
+ wg.Done()
+ }()
+
+ wg.Add(1)
+ go func() {
+ if err := gfitClient.SetCalories(ctx, summary.Summary.CaloriesOut, tm); err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetCalories(%d) = %v", summary.Summary.CaloriesOut, err))
+ }
+ wg.Done()
+ }()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ var distanceMeters float64
+ for _, d := range summary.Summary.Distances {
+ if d.Activity != "total" {
+ continue
+ }
+ distanceMeters = 1000.0 * d.Distance
+ break
+ }
+ if err := gfitClient.SetDistance(ctx, distanceMeters, tm); err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetDistance(%d) = %v", distanceMeters, err))
+ return
+ }
+ }()
+ wg.Add(1)
+ go func() {
+ if err := gfitClient.SetHeartRate(ctx, summary.Summary.HeartRateZones, summary.Summary.RestingHeartRate, tm); err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetHeartRate() = %v", err))
+ }
+ wg.Done()
+ }()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ var activities []gfit.Activity
+ for _, a := range summary.Activities {
+ if !a.HasStartTime {
+ continue
+ }
+
+ startTime, err := time.ParseInLocation("2006-01-02T15:04", a.StartDate+"T"+a.StartTime, profile.Timezone)
+ if err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetActivities() = %v", err))
+ return
+ }
+ endTime := startTime.Add(time.Duration(a.Duration) * time.Millisecond)
+
+ activities = append(activities, gfit.Activity{
+ Start: startTime,
+ End: endTime,
+ Type: gfit.ParseFitbitActivity(a.Name),
+ })
+ }
+ if err := gfitClient.SetActivities(ctx, activities, tm); err != nil {
+ errs = append(errs, fmt.Errorf("gfitClient.SetActivities() = %v", err))
+ return
+ }
+ }()
+
+ wg.Wait()
+
+ if len(errs) != 0 {
+ return errs
+ }
return nil
}