incyclist-services 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,16 @@
1
1
  /// <reference types="node" />
2
2
  import { IncyclistService } from "../../base/service";
3
- import { Observer } from "../../base/types/observer";
3
+ import { Observer, PromiseObserver } from "../../base/types/observer";
4
4
  import { DeviceData } from "incyclist-devices";
5
5
  import { ExtendedIncyclistCapability, HealthStatus } from "../../devices";
6
- import { ActivitiesRepository, ActivityDetails, ActivityLogRecord, ActivityRouteType, ScreenShotInfo } from "../base";
6
+ import { ActivitiesRepository, ActivityConverterFactory, ActivityDetails, ActivityLogRecord, ActivityRouteType, ScreenShotInfo } from "../base";
7
7
  import { FreeRideStartSettings } from "../../routes/list/types";
8
8
  import { RoutePoint } from "../../routes/base/types";
9
9
  import { ActivityState } from "./types";
10
10
  import { Route } from "../../routes/base/model/route";
11
11
  import { ActivityStatsCalculator } from "./stats";
12
12
  import { ActivityDuration } from "./duration";
13
+ import { ActivityUploadFactory } from "../upload";
13
14
  export declare class ActivityRideService extends IncyclistService {
14
15
  protected observer: Observer;
15
16
  protected activity: ActivityDetails;
@@ -26,6 +27,7 @@ export declare class ActivityRideService extends IncyclistService {
26
27
  routeDistance: number;
27
28
  speed: number;
28
29
  };
30
+ protected saveObserver: PromiseObserver<boolean>;
29
31
  protected statsCalculator: ActivityStatsCalculator;
30
32
  protected durationCalculator: ActivityDuration;
31
33
  protected deviceDataHandler: any;
@@ -47,13 +49,14 @@ export declare class ActivityRideService extends IncyclistService {
47
49
  init(id?: string): Observer;
48
50
  start(): void;
49
51
  stop(): void;
50
- private updateActivityTime;
51
52
  pause(autoResume?: boolean): void;
52
53
  resume(requester?: 'user' | 'system'): void;
53
54
  getDashboardDisplayProperties(): any[];
54
55
  getActivitySummaryDisplayProperties(): void;
55
56
  getActivity(): ActivityDetails;
56
- save(): Promise<void>;
57
+ setTitle(title: string): void;
58
+ delete(): Promise<void>;
59
+ save(): PromiseObserver<boolean>;
57
60
  getObserver(): Observer;
58
61
  addSceenshot(screenshot: ScreenShotInfo): void;
59
62
  onRouteUpdate(points: Array<RoutePoint>): void;
@@ -64,6 +67,8 @@ export declare class ActivityRideService extends IncyclistService {
64
67
  protected _save(): Promise<void>;
65
68
  protected getSaveInterval(): number;
66
69
  protected updateRepo(): Promise<void>;
70
+ protected convert(format: string): Promise<boolean>;
71
+ protected upload(format: string): Promise<boolean>;
67
72
  protected getRepo(): ActivitiesRepository;
68
73
  protected createLogRecord(): ActivityLogRecord;
69
74
  protected createActivity(requestedId?: string): ActivityDetails;
@@ -73,6 +78,7 @@ export declare class ActivityRideService extends IncyclistService {
73
78
  protected update(): void;
74
79
  protected createFreeRide(settings: FreeRideStartSettings): Route;
75
80
  protected getMode(routeType: ActivityRouteType): "video" | "free ride" | "follow route";
81
+ protected updateActivityTime(): void;
76
82
  getRideProps(): any;
77
83
  protected logActivityUpdateMessage(): void;
78
84
  getBikeInterface(): string;
@@ -83,5 +89,7 @@ export declare class ActivityRideService extends IncyclistService {
83
89
  protected getRouteList(): import("../../routes").RouteListService;
84
90
  protected getDeviceRide(): import("../../devices").DeviceRideService;
85
91
  protected getDeviceConfiguration(): import("../../devices").DeviceConfigurationService;
92
+ protected getActivityUploadFactory(): ActivityUploadFactory;
93
+ protected getActivityConverterfactory(): ActivityConverterFactory;
86
94
  }
87
95
  export declare const useActivityRide: () => ActivityRideService;
@@ -63,6 +63,7 @@ const route_1 = require("../../routes/base/utils/route");
63
63
  const route_2 = require("../../routes/base/model/route");
64
64
  const stats_1 = require("./stats");
65
65
  const duration_1 = require("./duration");
66
+ const upload_1 = require("../upload");
66
67
  const SAVE_INTERVAL = 5000;
67
68
  let ActivityRideService = (() => {
68
69
  let _classDecorators = [types_1.Singleton];
@@ -132,13 +133,6 @@ let ActivityRideService = (() => {
132
133
  delete this.tsStart;
133
134
  (0, utils_1.waitNextTick)().then(() => { delete this.observer; });
134
135
  }
135
- updateActivityTime() {
136
- var _a;
137
- if (!this.activity)
138
- return;
139
- this.activity.timeTotal = (Date.now() - this.tsStart) / 1000;
140
- this.activity.time = this.activity.timeTotal - ((_a = this.activity.timePause) !== null && _a !== void 0 ? _a : 0);
141
- }
142
136
  pause(autoResume = false) {
143
137
  if (this.state !== 'active')
144
138
  return;
@@ -233,8 +227,63 @@ let ActivityRideService = (() => {
233
227
  getActivity() {
234
228
  return this.activity;
235
229
  }
230
+ setTitle(title) {
231
+ this.activity.title = title;
232
+ this._save();
233
+ }
234
+ delete() {
235
+ return __awaiter(this, void 0, void 0, function* () {
236
+ if (this.state === 'idle' || !this.observer)
237
+ return;
238
+ if (this.state !== 'completed') {
239
+ this.stop();
240
+ yield new Promise(done => { this.observer.on('completed', done); });
241
+ }
242
+ this.getRepo().delete(this.activity.id);
243
+ this.state = 'idle';
244
+ });
245
+ }
236
246
  save() {
237
- return this._save();
247
+ if (this.saveObserver) {
248
+ return this.saveObserver;
249
+ }
250
+ const emit = (event, ...args) => {
251
+ if (this.saveObserver)
252
+ this.saveObserver.emit(event, ...args);
253
+ };
254
+ const run = () => __awaiter(this, void 0, void 0, function* () {
255
+ let success = false;
256
+ try {
257
+ emit('start', success);
258
+ yield this._save();
259
+ let format = undefined;
260
+ let uploadSuccess = false;
261
+ let convertSuccess = yield this.convert('TCX');
262
+ if (convertSuccess) {
263
+ format = 'TCX';
264
+ this.convert('FIT');
265
+ }
266
+ else {
267
+ convertSuccess == (yield this.convert('FIT'));
268
+ if (convertSuccess)
269
+ format = 'FIT';
270
+ }
271
+ if (convertSuccess) {
272
+ uploadSuccess = yield this.upload(format);
273
+ }
274
+ success = convertSuccess && uploadSuccess;
275
+ }
276
+ catch (err) {
277
+ success = false;
278
+ }
279
+ emit('done', success);
280
+ (0, utils_1.waitNextTick)().then(() => {
281
+ delete this.saveObserver;
282
+ });
283
+ return success;
284
+ });
285
+ this.saveObserver = new observer_1.PromiseObserver(run());
286
+ return this.saveObserver;
238
287
  }
239
288
  getObserver() {
240
289
  if (this.state === 'idle')
@@ -267,6 +316,8 @@ let ActivityRideService = (() => {
267
316
  onDeviceData(data) {
268
317
  if (!this.current)
269
318
  return;
319
+ if (!data)
320
+ return;
270
321
  try {
271
322
  this.current.tsDeviceData = Date.now();
272
323
  const update = Object.assign({}, data);
@@ -332,6 +383,40 @@ let ActivityRideService = (() => {
332
383
  }
333
384
  });
334
385
  }
386
+ convert(format) {
387
+ return __awaiter(this, void 0, void 0, function* () {
388
+ this.saveObserver.emit('convert.start', format);
389
+ try {
390
+ base_1.ActivityConverter.convert(this.activity, format);
391
+ this.saveObserver.emit('convert.done', format, true);
392
+ if (format.toLowerCase() === 'fit')
393
+ this.activity.fitFileName = this.activity.fileName.replace('json', 'fit');
394
+ if (format.toLowerCase() === 'tcx')
395
+ this.activity.tcxFileName = this.activity.fileName.replace('json', 'tcx');
396
+ yield this._save();
397
+ return true;
398
+ }
399
+ catch (err) {
400
+ this.saveObserver.emit('convert.error', format, err);
401
+ return false;
402
+ }
403
+ });
404
+ }
405
+ upload(format) {
406
+ return __awaiter(this, void 0, void 0, function* () {
407
+ const factory = this.getActivityUploadFactory();
408
+ this.saveObserver.emit('upload.start');
409
+ try {
410
+ yield factory.upload(this.activity, format);
411
+ this.saveObserver.emit('upload.done', format, true);
412
+ return true;
413
+ }
414
+ catch (err) {
415
+ this.saveObserver.emit('upload.error', format, err);
416
+ return false;
417
+ }
418
+ });
419
+ }
335
420
  getRepo() {
336
421
  if (this.repo)
337
422
  return this.repo;
@@ -451,7 +536,7 @@ let ActivityRideService = (() => {
451
536
  this.current.routeDistance += distance;
452
537
  if (distance !== 0) {
453
538
  const prev = this.current.position;
454
- const position = (_b = (0, route_1.getNextPosition)(this.current.route, { distance, prev: this.current.position })) !== null && _b !== void 0 ? _b : (0, route_1.getNextPosition)(this.current.route, { routeDistance: this.current.routeDistance });
539
+ const position = (_b = (0, route_1.getNextPosition)(this.current.route, { routeDistance: this.current.routeDistance, prev: this.current.position })) !== null && _b !== void 0 ? _b : (0, route_1.getNextPosition)(this.current.route, { distance, prev: this.current.position });
455
540
  this.current.position = position !== null && position !== void 0 ? position : prev;
456
541
  if (this.activity.realityFactor > 0) {
457
542
  const gain = (0, route_1.getElevationGainAt)(this.current.route, this.current.routeDistance);
@@ -555,6 +640,13 @@ let ActivityRideService = (() => {
555
640
  return 'follow route';
556
641
  return 'free ride';
557
642
  }
643
+ updateActivityTime() {
644
+ var _a;
645
+ if (!this.activity)
646
+ return;
647
+ this.activity.timeTotal = (Date.now() - this.tsStart) / 1000;
648
+ this.activity.time = this.activity.timeTotal - ((_a = this.activity.timePause) !== null && _a !== void 0 ? _a : 0);
649
+ }
558
650
  getRideProps() {
559
651
  var _a;
560
652
  const { startPos, realityFactor, routeType } = this.activity;
@@ -613,6 +705,12 @@ let ActivityRideService = (() => {
613
705
  getDeviceConfiguration() {
614
706
  return (0, devices_1.useDeviceConfiguration)();
615
707
  }
708
+ getActivityUploadFactory() {
709
+ return new upload_1.ActivityUploadFactory();
710
+ }
711
+ getActivityConverterfactory() {
712
+ return new base_1.ActivityConverterFactory();
713
+ }
616
714
  };
617
715
  __setFunctionName(_classThis, "ActivityRideService");
618
716
  (() => {
@@ -0,0 +1,8 @@
1
+ import { ActivityDetails } from "../base";
2
+ import { IActivityUpload, UploaderInfo } from "./types";
3
+ export declare class ActivityUploadFactory {
4
+ protected uploaders: Array<UploaderInfo>;
5
+ constructor();
6
+ add(service: string, uploader: IActivityUpload): void;
7
+ upload(activity: ActivityDetails, format?: string): Promise<any[]>;
8
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.ActivityUploadFactory = void 0;
51
+ const types_1 = require("../../base/types");
52
+ let ActivityUploadFactory = (() => {
53
+ let _classDecorators = [types_1.Singleton];
54
+ let _classDescriptor;
55
+ let _classExtraInitializers = [];
56
+ let _classThis;
57
+ var ActivityUploadFactory = _classThis = class {
58
+ constructor() {
59
+ this.uploaders = [];
60
+ }
61
+ add(service, uploader) {
62
+ const existing = this.uploaders.findIndex(ui => ui.service === service);
63
+ if (existing === -1)
64
+ this.uploaders.push({ service, uploader });
65
+ else
66
+ this.uploaders[existing] = { service, uploader };
67
+ }
68
+ upload(activity_1) {
69
+ return __awaiter(this, arguments, void 0, function* (activity, format = 'TCX') {
70
+ const uploads = [];
71
+ this.uploaders.forEach(ui => {
72
+ const { service, uploader } = ui;
73
+ if (uploader.isConnected()) {
74
+ const promise = uploader.upload(activity, format)
75
+ .then(success => ({ service, success }))
76
+ .catch(err => ({ service, success: false, error: err.message }));
77
+ uploads.push({ service, promise, status: undefined });
78
+ }
79
+ });
80
+ if (uploads.length > 0) {
81
+ const result = yield Promise.allSettled(uploads.map(us => us.promise));
82
+ }
83
+ else
84
+ return [];
85
+ });
86
+ }
87
+ };
88
+ __setFunctionName(_classThis, "ActivityUploadFactory");
89
+ (() => {
90
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
91
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
92
+ ActivityUploadFactory = _classThis = _classDescriptor.value;
93
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
94
+ __runInitializers(_classThis, _classExtraInitializers);
95
+ })();
96
+ return ActivityUploadFactory = _classThis;
97
+ })();
98
+ exports.ActivityUploadFactory = ActivityUploadFactory;
@@ -1,2 +1,4 @@
1
1
  export * from './velohero';
2
+ export * from './strava';
2
3
  export * from './types';
4
+ export * from './factory';
@@ -14,5 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ const factory_1 = require("./factory");
18
+ const strava_1 = require("./strava");
19
+ const velohero_1 = require("./velohero");
17
20
  __exportStar(require("./velohero"), exports);
21
+ __exportStar(require("./strava"), exports);
18
22
  __exportStar(require("./types"), exports);
23
+ __exportStar(require("./factory"), exports);
24
+ const factory = new factory_1.ActivityUploadFactory();
25
+ factory.add('strava', new strava_1.StravaUpload());
26
+ factory.add('velohero', new velohero_1.VeloHeroUpload());
@@ -0,0 +1,24 @@
1
+ import { IncyclistService } from "../../base/service";
2
+ import { ActivityDetails } from "../base";
3
+ import { StravaApi, StravaConfig, StravaFormat } from "../../apps/base/api/strava";
4
+ import { IActivityUpload } from "./types";
5
+ export declare class StravaUpload extends IncyclistService implements IActivityUpload {
6
+ protected isInitialized: any;
7
+ protected api: StravaApi;
8
+ protected config: StravaConfig;
9
+ protected _isConnecting: any;
10
+ constructor();
11
+ init(): boolean;
12
+ isConnected(): boolean;
13
+ isConnecting(): boolean;
14
+ connect(accessToken: string, refreshToken: string, expiration?: Date): Promise<boolean>;
15
+ disconnect(): void;
16
+ upload(activity: ActivityDetails, format?: string): Promise<boolean>;
17
+ protected getStravaFormat(format: string): StravaFormat;
18
+ protected getCredentials(): any;
19
+ protected saveCredentials(): void;
20
+ protected updateConfig(config: StravaConfig): void;
21
+ protected getSecret(key: string): string;
22
+ protected getUserSettings(): import("../../settings").UserSettingsService;
23
+ protected getApi(): StravaApi;
24
+ }
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.StravaUpload = void 0;
51
+ const service_1 = require("../../base/service");
52
+ const types_1 = require("../../base/types");
53
+ const settings_1 = require("../../settings");
54
+ const valid_1 = require("../../utils/valid");
55
+ const strava_1 = require("../../apps/base/api/strava");
56
+ const api_1 = require("../../api");
57
+ let StravaUpload = (() => {
58
+ let _classDecorators = [types_1.Singleton];
59
+ let _classDescriptor;
60
+ let _classExtraInitializers = [];
61
+ let _classThis;
62
+ let _classSuper = service_1.IncyclistService;
63
+ var StravaUpload = _classThis = class extends _classSuper {
64
+ constructor() {
65
+ super('StravaUpload');
66
+ this.isInitialized = false;
67
+ this.init();
68
+ }
69
+ init() {
70
+ if (this.isInitialized)
71
+ return true;
72
+ if (!this.getUserSettings().isInitialized)
73
+ return false;
74
+ try {
75
+ const clientId = this.getSecret('STRAVA_CLIENT_ID');
76
+ const clientSecret = this.getSecret('STRAVA_CLIENT_SECRET');
77
+ const auth = this.getCredentials();
78
+ if (clientId && clientSecret && auth) {
79
+ this.logger.logEvent({ message: 'Strava init done', hasCredentials: true });
80
+ this.config = {
81
+ clientId, clientSecret,
82
+ accessToken: auth.accesstoken,
83
+ refreshToken: auth.refreshtoken,
84
+ expiration: new Date(auth.expiration)
85
+ };
86
+ const observer = this.getApi().init(this.config);
87
+ observer.on('token.updated', this.updateConfig.bind(this));
88
+ }
89
+ else {
90
+ this.logger.logEvent({ message: 'Strava init done', hasCredentials: false });
91
+ }
92
+ this.isInitialized = true;
93
+ }
94
+ catch (err) {
95
+ this.logger.logEvent({ message: 'error', error: err.message, fn: 'init', stack: err.stack });
96
+ this.isInitialized = false;
97
+ }
98
+ return this.isInitialized;
99
+ }
100
+ isConnected() {
101
+ if (!this.isInitialized) {
102
+ this.init();
103
+ }
104
+ return ((0, valid_1.valid)(this.config));
105
+ }
106
+ isConnecting() {
107
+ return false;
108
+ }
109
+ connect(accessToken, refreshToken, expiration) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ if (!this.isInitialized) {
112
+ const ok = this.init();
113
+ }
114
+ this.logger.logEvent({ message: 'Connect with Strava' });
115
+ try {
116
+ const isConnected = this.isConnected();
117
+ const config = {
118
+ clientId: this.getSecret('STRAVA_CLIENT_ID'),
119
+ clientSecret: this.getSecret('STRAVA_CLIENT_SECRET'),
120
+ accessToken, refreshToken, expiration
121
+ };
122
+ if (isConnected) {
123
+ this.getApi().update(this.config);
124
+ }
125
+ else {
126
+ const observer = this.getApi().init(this.config);
127
+ observer.on('token.updated', this.updateConfig.bind(this));
128
+ }
129
+ yield this.saveCredentials();
130
+ this.logger.logEvent({ message: 'Connect with strava success' });
131
+ return true;
132
+ }
133
+ catch (err) {
134
+ this.logger.logEvent({ message: 'Connect with Strava failed', error: err.message });
135
+ throw err;
136
+ }
137
+ });
138
+ }
139
+ disconnect() {
140
+ if (!this.isInitialized) {
141
+ const ok = this.init();
142
+ }
143
+ try {
144
+ this.getUserSettings().set('user.auth.strava', null);
145
+ this.config = undefined;
146
+ this.getApi().init(undefined);
147
+ }
148
+ catch (err) {
149
+ this.logError(err, 'disconnect');
150
+ }
151
+ }
152
+ upload(activity_1) {
153
+ return __awaiter(this, arguments, void 0, function* (activity, format = 'TCX') {
154
+ try {
155
+ if (!this.isInitialized) {
156
+ const ok = this.init();
157
+ if (!ok)
158
+ return false;
159
+ }
160
+ if (!this.isConnected())
161
+ return false;
162
+ this.logger.logEvent({ message: 'Strava Upload', format });
163
+ const fileName = activity[`${format}FileName`];
164
+ const res = yield this.getApi().upload(fileName, {
165
+ name: activity.name,
166
+ description: '',
167
+ format: this.getStravaFormat(format)
168
+ });
169
+ this.logger.logEvent({ message: 'Strava Upload success', activityId: res.stravaId });
170
+ return true;
171
+ }
172
+ catch (err) {
173
+ if (err instanceof strava_1.DuplicateError) {
174
+ this.logger.logEvent({ message: 'Strava Upload failure', error: 'duplicate', activityId: err.stravaId });
175
+ }
176
+ else {
177
+ this.logger.logEvent({ message: 'Strava Upload failure', error: err.message });
178
+ }
179
+ return false;
180
+ }
181
+ });
182
+ }
183
+ getStravaFormat(format) {
184
+ switch (format.toLowerCase()) {
185
+ case 'tcx':
186
+ return 'tcx';
187
+ case 'fit':
188
+ return 'fit';
189
+ case 'gox':
190
+ return 'gpx';
191
+ default:
192
+ return null;
193
+ }
194
+ }
195
+ getCredentials() {
196
+ const userSettings = this.getUserSettings();
197
+ try {
198
+ return userSettings.get('user.auth.strava', null);
199
+ }
200
+ catch (_a) {
201
+ return null;
202
+ }
203
+ }
204
+ saveCredentials() {
205
+ this.logger.logEvent({ message: 'Strava Save Credentials' });
206
+ try {
207
+ if (!this.isConnected()) {
208
+ this.getUserSettings().set('user.auth.strava', null);
209
+ return;
210
+ }
211
+ this.getUserSettings().set('user.auth.strava', {
212
+ accesstoken: this.config.accessToken,
213
+ refreshToken: this.config.refreshToken,
214
+ expiration: this.config.expiration.toUTCString()
215
+ });
216
+ }
217
+ catch (err) {
218
+ this.logger.logEvent({ message: 'error', fn: 'saveCredentials', error: err.message, stack: err.stack });
219
+ }
220
+ this.logger.logEvent({ message: 'Strava Save Credentials done' });
221
+ return;
222
+ }
223
+ updateConfig(config) {
224
+ const { accessToken, refreshToken, expiration } = config;
225
+ this.config = Object.assign(Object.assign({}, this.config), { accessToken, refreshToken, expiration });
226
+ this.saveCredentials();
227
+ }
228
+ getSecret(key) {
229
+ var _a, _b;
230
+ return (_b = (_a = (0, api_1.getBindings)()) === null || _a === void 0 ? void 0 : _a.secret) === null || _b === void 0 ? void 0 : _b.getSecret(key);
231
+ }
232
+ getUserSettings() {
233
+ return (0, settings_1.useUserSettings)();
234
+ }
235
+ getApi() {
236
+ if (!this.api)
237
+ this.api = new strava_1.StravaApi();
238
+ return this.api;
239
+ }
240
+ };
241
+ __setFunctionName(_classThis, "StravaUpload");
242
+ (() => {
243
+ var _a;
244
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
245
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
246
+ StravaUpload = _classThis = _classDescriptor.value;
247
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
248
+ __runInitializers(_classThis, _classExtraInitializers);
249
+ })();
250
+ return StravaUpload = _classThis;
251
+ })();
252
+ exports.StravaUpload = StravaUpload;
@@ -1,3 +1,4 @@
1
+ import { ActivityDetails } from "../base";
1
2
  export interface Credentials {
2
3
  username?: string;
3
4
  password?: string;
@@ -6,3 +7,19 @@ export interface VeloHeroAuth extends Credentials {
6
7
  id?: string;
7
8
  authKey?: string;
8
9
  }
10
+ export type UploaderInfo = {
11
+ service: string;
12
+ uploader: IActivityUpload;
13
+ };
14
+ export type ActivityUploadResult = {
15
+ service: string;
16
+ success?: boolean;
17
+ error?: string;
18
+ };
19
+ export interface IActivityUpload {
20
+ init(): boolean;
21
+ isConnected(): boolean;
22
+ isConnecting(): boolean;
23
+ disconnect(): void;
24
+ upload(activity: ActivityDetails, format?: string): Promise<boolean>;
25
+ }