+func DataStreamID(dataSource *fitness.DataSource) string {
+ fields := []string{
+ dataSource.Type,
+ dataSource.DataType.Name,
+ "@PROJECT_NUMBER@", // FIXME
+ }
+
+ if dev := dataSource.Device; dev != nil {
+ if dev.Manufacturer != "" {
+ fields = append(fields, dev.Manufacturer)
+ }
+ if dev.Model != "" {
+ fields = append(fields, dev.Model)
+ }
+ if dev.Uid != "" {
+ fields = append(fields, dev.Uid)
+ }
+ }
+
+ return strings.Join(fields, ":")
+}
+
+func (c *Client) DataSourceCreate(ctx context.Context, dataSource *fitness.DataSource) (string, error) {
+ res, err := c.Service.Users.DataSources.Create(userID, dataSource).Context(ctx).Do()
+ if err != nil {
+ if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == http.StatusConflict {
+ if dataSource.DataStreamId != "" {
+ return dataSource.DataStreamId, nil
+ }
+ return DataStreamID(dataSource), nil
+ }
+ log.Errorf(ctx, "c.Service.Users.DataSources.Create() = (%+v, %v)", res, err)
+ return "", err
+ }
+ return res.DataStreamId, nil
+}
+
+func (c *Client) DataSetPatch(ctx context.Context, dataSourceID string, points []*fitness.DataPoint) error {
+ startTimeNanos, endTimeNanos := int64(-1), int64(-1)
+ for _, p := range points {
+ if startTimeNanos == -1 || startTimeNanos > p.StartTimeNanos {
+ startTimeNanos = p.StartTimeNanos
+ }
+ if endTimeNanos == -1 || endTimeNanos < p.EndTimeNanos {
+ endTimeNanos = p.EndTimeNanos
+ }
+ }
+ datasetID := fmt.Sprintf("%d-%d", startTimeNanos, endTimeNanos)
+
+ dataset := &fitness.Dataset{
+ DataSourceId: dataSourceID,
+ MinStartTimeNs: startTimeNanos,
+ MaxEndTimeNs: endTimeNanos,
+ Point: points,
+ }
+
+ _, err := c.Service.Users.DataSources.Datasets.Patch(userID, dataSourceID, datasetID, dataset).Context(ctx).Do()
+ if err != nil {
+ log.Errorf(ctx, "c.Service.Users.DataSources.Datasets.Patch() = %v", err)
+ return err
+ }
+ return nil
+}
+