X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=gfit%2Fgfit.go;h=78d28d747ec7d051353d1b3226625548a9db3aa3;hb=e0dd0f79fe96f749e19fac2401f751d841fc19b5;hp=eca961cfe44e629eac10bd6231a40653abb0d6ef;hpb=ab9dff1afb2dea96c1efbf979dc713f89a27f6da;p=kraftakt.git diff --git a/gfit/gfit.go b/gfit/gfit.go index eca961c..78d28d7 100644 --- a/gfit/gfit.go +++ b/gfit/gfit.go @@ -7,8 +7,8 @@ import ( "strings" "time" - "github.com/octo/gfitsync/app" - "github.com/octo/gfitsync/fitbit" + "github.com/octo/kraftakt/app" + "github.com/octo/kraftakt/fitbit" "golang.org/x/oauth2" oauth2google "golang.org/x/oauth2/google" fitness "google.golang.org/api/fitness/v1" @@ -28,28 +28,30 @@ const ( dataTypeNameActivitySegment = "com.google.activity.segment" ) -var oauthConfig = &oauth2.Config{ - ClientID: "@GOOGLE_CLIENT_ID@", - ClientSecret: "@GOOGLE_CLIENT_SECRET@", - Endpoint: oauth2google.Endpoint, - RedirectURL: "https://kraftakt.octo.it/google/grant", - Scopes: []string{ - fitness.FitnessActivityWriteScope, - fitness.FitnessBodyWriteScope, - fitness.FitnessLocationWriteScope, - }, +func oauthConfig() *oauth2.Config { + return &oauth2.Config{ + ClientID: app.Config.GoogleClientID, + ClientSecret: app.Config.GoogleClientSecret, + Endpoint: oauth2google.Endpoint, + RedirectURL: "https://kraftakt.octo.it/google/grant", + Scopes: []string{ + fitness.FitnessActivityWriteScope, + fitness.FitnessBodyWriteScope, + fitness.FitnessLocationWriteScope, + }, + } } func Application(ctx context.Context) *fitness.Application { return &fitness.Application{ - Name: "Fitbit to Google Fit sync", + Name: "Kraftakt", Version: appengine.VersionID(ctx), DetailsUrl: "", // optional } } func AuthURL() string { - return oauthConfig.AuthCodeURL(csrfToken, oauth2.AccessTypeOffline) + return oauthConfig().AuthCodeURL(csrfToken, oauth2.AccessTypeOffline) } func ParseToken(ctx context.Context, r *http.Request, u *app.User) error { @@ -57,7 +59,7 @@ func ParseToken(ctx context.Context, r *http.Request, u *app.User) error { return fmt.Errorf("invalid state parameter: %q", state) } - tok, err := oauthConfig.Exchange(ctx, r.FormValue("code")) + tok, err := oauthConfig().Exchange(ctx, r.FormValue("code")) if err != nil { return err } @@ -70,7 +72,7 @@ type Client struct { } func NewClient(ctx context.Context, u *app.User) (*Client, error) { - c, err := u.OAuthClient(ctx, "Google", oauthConfig) + c, err := u.OAuthClient(ctx, "Google", oauthConfig()) if err != nil { return nil, err } @@ -89,7 +91,7 @@ func DataStreamID(dataSource *fitness.DataSource) string { fields := []string{ dataSource.Type, dataSource.DataType.Name, - "@PROJECT_NUMBER@", // FIXME + app.Config.ProjectNumber, } if dev := dataSource.Device; dev != nil { @@ -120,7 +122,7 @@ func (c *Client) DataSourceCreate(ctx context.Context, dataSource *fitness.DataS } return DataStreamID(dataSource), nil } - log.Errorf(ctx, "c.Service.Users.DataSources.Create() = (%+v, %v)", res, err) + log.Errorf(ctx, "c.Service.Users.DataSources.Create(%q) = (%+v, %v)", dataSource, res, err) return "", err } return res.DataStreamId, nil @@ -225,13 +227,31 @@ type Activity struct { Type int64 } +func (a Activity) String() string { + return fmt.Sprintf("%s-%s %d", a.Start.Format("15:04:05"), a.End.Format("15:04:05"), a.Type) +} + func (c *Client) SetActivities(ctx context.Context, activities []Activity, startOfDay time.Time) error { - dataStreamID := DataStreamID(&fitness.DataSource{ + if len(activities) == 0 { + return nil + } + + dataStreamID, err := c.DataSourceCreate(ctx, &fitness.DataSource{ + Application: Application(ctx), DataType: &fitness.DataType{ + Field: []*fitness.DataTypeField{ + &fitness.DataTypeField{ + Name: "activity", + Format: "integer", + }, + }, Name: dataTypeNameActivitySegment, }, Type: "raw", }) + if err != nil { + return err + } endOfDay := startOfDay.Add(24 * time.Hour).Add(-1 * time.Nanosecond) @@ -249,13 +269,13 @@ Next: endTimeNanos := a.End.UnixNano() for _, p := range res.Point { - if p.StartTimeNanos == startTimeNanos && - p.EndTimeNanos == endTimeNanos && - p.Value[0].IntVal == a.Type { + if p.StartTimeNanos == startTimeNanos && p.EndTimeNanos == endTimeNanos && p.Value[0].IntVal == a.Type { + log.Debugf(ctx, "activity %s already stored in Google Fit", a) continue Next } } + log.Debugf(ctx, "activity %s will be added to Google Fit", a) dataPoints = append(dataPoints, &fitness.DataPoint{ DataTypeName: dataTypeNameActivitySegment, StartTimeNanos: startTimeNanos, @@ -324,7 +344,7 @@ func (c *Client) updateCumulative(ctx context.Context, dataSource *fitness.DataS if now := time.Now().In(startOfDay.Location()); now.Before(endOfDay) { endTime = now } - log.Debugf(ctx, "adding cumulative data point: %v-%v %+v", startTime, endTime, diffValue) + log.Debugf(ctx, "add cumulative data %s until %v: %+v", dataSource.DataStreamId, endTime, diffValue) return c.DataSetPatch(ctx, dataSource.DataStreamId, []*fitness.DataPoint{ &fitness.DataPoint{ @@ -346,6 +366,7 @@ func (c *Client) readCumulative(ctx context.Context, dataSource *fitness.DataSou } if len(res.Point) == 0 { + log.Debugf(ctx, "read cumulative data %s until %v: []", dataSource.DataStreamId, endTime) return &fitness.Value{}, startTime, nil }