incyclist-services 1.1.101 → 1.2.0
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.
- package/lib/activities/base/api/index.d.ts +0 -0
- package/lib/activities/base/api/index.js +0 -0
- package/lib/activities/base/loaders/db.d.ts +41 -0
- package/lib/activities/base/loaders/db.js +378 -0
- package/lib/activities/base/loaders/index.d.ts +2 -0
- package/lib/activities/base/loaders/index.js +18 -0
- package/lib/activities/base/loaders/types.d.ts +8 -0
- package/lib/activities/base/loaders/types.js +2 -0
- package/lib/activities/base/model/index.d.ts +116 -0
- package/lib/activities/base/model/index.js +2 -0
- package/lib/activities/index.d.ts +2 -0
- package/lib/activities/index.js +18 -0
- package/lib/api/repository/json/index.d.ts +1 -0
- package/lib/api/repository/json/index.js +19 -0
- package/lib/api/repository/types.d.ts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/routes/base/utils/route.js +2 -2
- package/lib/workouts/base/model/Workout.js +4 -3
- package/lib/workouts/list/cards/WorkoutCard.d.ts +1 -1
- package/lib/workouts/list/cards/WorkoutCard.js +3 -3
- package/lib/workouts/list/loaders/db.d.ts +1 -1
- package/lib/workouts/list/loaders/db.js +3 -3
- package/package.json +2 -3
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EventLogger } from "gd-eventlog";
|
|
2
|
+
import { JsonRepository } from "../../../api";
|
|
3
|
+
import { Observer, PromiseObserver } from "../../../base/types/observer";
|
|
4
|
+
import { ActivityDetails, ActivityInfo, ActivitySummary } from "../model";
|
|
5
|
+
import { ActivitySearchCriteria } from "./types";
|
|
6
|
+
export declare class ActivitiesDbLoader {
|
|
7
|
+
protected repo: JsonRepository;
|
|
8
|
+
protected loadObserver: Observer;
|
|
9
|
+
protected saveObserver: PromiseObserver<void>;
|
|
10
|
+
protected isDirty: boolean;
|
|
11
|
+
protected tsLastWrite: number;
|
|
12
|
+
protected logger: EventLogger;
|
|
13
|
+
protected activities: Array<ActivityInfo>;
|
|
14
|
+
protected isDBComplete: boolean;
|
|
15
|
+
constructor();
|
|
16
|
+
load(): Observer;
|
|
17
|
+
stopLoad(): void;
|
|
18
|
+
save(activity: ActivityInfo, writeDetails?: boolean): Promise<void>;
|
|
19
|
+
delete(activity: ActivityInfo | string): Promise<void>;
|
|
20
|
+
get(id: string): ActivityInfo;
|
|
21
|
+
getWithDetails(id: string): Promise<ActivityInfo>;
|
|
22
|
+
search(criteria: ActivitySearchCriteria): Array<ActivityInfo>;
|
|
23
|
+
protected writeRepo(): Promise<void>;
|
|
24
|
+
protected write(enforce?: boolean): void;
|
|
25
|
+
protected emitDone(): void;
|
|
26
|
+
protected emitUpdated(activity: ActivityInfo | Array<ActivityInfo>): void;
|
|
27
|
+
protected emitAdded(activity: ActivityInfo | Array<ActivityInfo>): void;
|
|
28
|
+
protected loadSummaries(): Promise<void>;
|
|
29
|
+
protected buildFromLegacy(): Promise<void>;
|
|
30
|
+
protected listActivities(): Promise<Array<string>>;
|
|
31
|
+
protected loadDetailsByName(name: string): Promise<ActivityDetails>;
|
|
32
|
+
protected loadDetails(name: string, id?: string): Promise<void>;
|
|
33
|
+
protected writeDetails(activity: ActivityInfo): Promise<void>;
|
|
34
|
+
protected buildSummary(activity: ActivityDetails, name: string): ActivitySummary;
|
|
35
|
+
protected scanForActivities(): Promise<Array<ActivitySummary> | null>;
|
|
36
|
+
protected scanForActivitiesAndMerge(activities: Array<ActivitySummary>): Promise<Array<ActivitySummary>>;
|
|
37
|
+
protected _load(): Promise<void>;
|
|
38
|
+
protected getActivity(id: string): ActivityInfo;
|
|
39
|
+
protected logError(error: Error, fn: string, logProps?: any): void;
|
|
40
|
+
protected getRepo(): JsonRepository;
|
|
41
|
+
}
|
|
@@ -0,0 +1,378 @@
|
|
|
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.ActivitiesDbLoader = void 0;
|
|
51
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
52
|
+
const api_1 = require("../../../api");
|
|
53
|
+
const types_1 = require("../../../base/types");
|
|
54
|
+
const observer_1 = require("../../../base/types/observer");
|
|
55
|
+
const utils_1 = require("../../../utils");
|
|
56
|
+
const DB_VERSION = '1';
|
|
57
|
+
let ActivitiesDbLoader = (() => {
|
|
58
|
+
let _classDecorators = [types_1.Singleton];
|
|
59
|
+
let _classDescriptor;
|
|
60
|
+
let _classExtraInitializers = [];
|
|
61
|
+
let _classThis;
|
|
62
|
+
var ActivitiesDbLoader = _classThis = class {
|
|
63
|
+
constructor() {
|
|
64
|
+
this.logger = new gd_eventlog_1.EventLogger('ActivitiesDB');
|
|
65
|
+
}
|
|
66
|
+
load() {
|
|
67
|
+
if (this.loadObserver)
|
|
68
|
+
return this.loadObserver;
|
|
69
|
+
this.loadObserver = new observer_1.Observer();
|
|
70
|
+
this._load();
|
|
71
|
+
return this.loadObserver;
|
|
72
|
+
}
|
|
73
|
+
stopLoad() {
|
|
74
|
+
this.emitDone();
|
|
75
|
+
}
|
|
76
|
+
save(activity, writeDetails = true) {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
const stringify = (json) => { try {
|
|
79
|
+
JSON.stringify(json);
|
|
80
|
+
}
|
|
81
|
+
catch (_a) { } };
|
|
82
|
+
let prev;
|
|
83
|
+
const idx = this.activities.findIndex(ai => ai.summary.id === activity.summary.id);
|
|
84
|
+
if (idx === -1) {
|
|
85
|
+
this.activities.push(activity);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
prev = stringify(this.activities[idx]);
|
|
89
|
+
this.activities[idx] = activity;
|
|
90
|
+
}
|
|
91
|
+
const changed = !prev || stringify(activity) !== prev;
|
|
92
|
+
if (changed) {
|
|
93
|
+
this.isDirty = true;
|
|
94
|
+
this.write();
|
|
95
|
+
if (writeDetails) {
|
|
96
|
+
this.writeDetails(activity);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
delete(activity) {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
let target = activity;
|
|
104
|
+
if (typeof (activity) === 'string') {
|
|
105
|
+
target = this.getActivity(activity);
|
|
106
|
+
}
|
|
107
|
+
if (!target)
|
|
108
|
+
return;
|
|
109
|
+
const id = target.summary.id;
|
|
110
|
+
const idx = this.activities.findIndex(ai => ai.summary.id === id);
|
|
111
|
+
if (idx) {
|
|
112
|
+
this.activities.splice(idx, 1);
|
|
113
|
+
this.write(true);
|
|
114
|
+
}
|
|
115
|
+
const name = target.summary.name;
|
|
116
|
+
yield this.getRepo().delete(name);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
get(id) {
|
|
120
|
+
const info = this.getActivity(id);
|
|
121
|
+
if (!info)
|
|
122
|
+
return;
|
|
123
|
+
return info;
|
|
124
|
+
}
|
|
125
|
+
getWithDetails(id) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
const info = this.getActivity(id);
|
|
128
|
+
if (!info)
|
|
129
|
+
return;
|
|
130
|
+
if (!info.details) {
|
|
131
|
+
yield this.loadDetails(info.summary.name, id);
|
|
132
|
+
}
|
|
133
|
+
return info;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
search(criteria) {
|
|
137
|
+
let result = this.activities;
|
|
138
|
+
if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.routeId)) {
|
|
139
|
+
result = result.filter(ai => ai.summary.routeId === criteria.routeId);
|
|
140
|
+
}
|
|
141
|
+
if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.startPos) !== undefined) {
|
|
142
|
+
result = result.filter(ai => ai.summary.startPos === criteria.startPos);
|
|
143
|
+
}
|
|
144
|
+
if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.realityFactor) !== undefined) {
|
|
145
|
+
result = result.filter(ai => { var _a; return ((_a = ai.summary.realityFactor) !== null && _a !== void 0 ? _a : 100) === criteria.realityFactor; });
|
|
146
|
+
}
|
|
147
|
+
if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.isSaved) !== undefined) {
|
|
148
|
+
result = result.filter(ai => ai.summary.isSaved === criteria.isSaved);
|
|
149
|
+
}
|
|
150
|
+
if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.uploadStatus) !== undefined) {
|
|
151
|
+
if (Array.isArray(criteria.uploadStatus)) {
|
|
152
|
+
result = result.filter(ai => {
|
|
153
|
+
const requested = criteria.uploadStatus;
|
|
154
|
+
const actual = ai.summary.uploadStatus;
|
|
155
|
+
const r = requested.sort().map(us => `${us.service}:${us.status}`).join(';');
|
|
156
|
+
const a = actual.sort().map(us => `${us.service}:${us.status}`).join(';');
|
|
157
|
+
return r === a;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const status = criteria.uploadStatus;
|
|
162
|
+
result = result.filter(ai => {
|
|
163
|
+
const serviceInfo = ai.summary.uploadStatus.find(asi => asi.service === status.service);
|
|
164
|
+
if (!serviceInfo)
|
|
165
|
+
return false;
|
|
166
|
+
return serviceInfo.status === status.status;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
writeRepo() {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
if (this.saveObserver)
|
|
175
|
+
yield this.saveObserver.wait();
|
|
176
|
+
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
const isComplete = this.isDBComplete;
|
|
178
|
+
try {
|
|
179
|
+
const dbData = {
|
|
180
|
+
version: DB_VERSION,
|
|
181
|
+
isComplete,
|
|
182
|
+
activties: this.activities.map(ai => ai.summary)
|
|
183
|
+
};
|
|
184
|
+
yield this.getRepo().write('db', dbData);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
this.logger.logEvent({ message: 'could not safe repo', error: err.message });
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
this.saveObserver = new observer_1.PromiseObserver(save());
|
|
191
|
+
yield this.saveObserver.start();
|
|
192
|
+
process.nextTick(() => { delete this.saveObserver; });
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
write(enforce = false) {
|
|
196
|
+
if (enforce)
|
|
197
|
+
this.isDirty = true;
|
|
198
|
+
if (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000)) {
|
|
199
|
+
this.isDirty = false;
|
|
200
|
+
this.tsLastWrite = Date.now();
|
|
201
|
+
this.writeRepo();
|
|
202
|
+
}
|
|
203
|
+
if (this.isDirty && Date.now() - this.tsLastWrite < 1000) {
|
|
204
|
+
setTimeout(() => { this.write(); }, this.tsLastWrite + 1000 - Date.now());
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
emitDone() {
|
|
208
|
+
if (this.loadObserver)
|
|
209
|
+
this.loadObserver.emit('done');
|
|
210
|
+
(0, utils_1.waitNextTick)().then(() => {
|
|
211
|
+
this.loadObserver.reset();
|
|
212
|
+
delete this.loadObserver;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
emitUpdated(activity) {
|
|
216
|
+
if (this.loadObserver)
|
|
217
|
+
this.loadObserver.emit('updated', activity);
|
|
218
|
+
}
|
|
219
|
+
emitAdded(activity) {
|
|
220
|
+
if (this.loadObserver)
|
|
221
|
+
this.loadObserver.emit('added', activity);
|
|
222
|
+
}
|
|
223
|
+
loadSummaries() {
|
|
224
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
225
|
+
const dbData = yield this.getRepo().read('db');
|
|
226
|
+
if (dbData) {
|
|
227
|
+
const { activities, isComplete } = dbData;
|
|
228
|
+
this.activities = activities.map(summary => ({ summary }));
|
|
229
|
+
this.emitAdded(this.activities);
|
|
230
|
+
this.isDBComplete = isComplete;
|
|
231
|
+
if (!isComplete) {
|
|
232
|
+
const cnt = activities.length;
|
|
233
|
+
const update = yield this.scanForActivitiesAndMerge(activities);
|
|
234
|
+
if (cnt !== update.length) {
|
|
235
|
+
yield this.write(true);
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
yield this.buildFromLegacy();
|
|
241
|
+
return;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
buildFromLegacy() {
|
|
245
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
246
|
+
const activities = yield this.scanForActivities();
|
|
247
|
+
if (activities !== null) {
|
|
248
|
+
this.activities = activities.map(summary => ({ summary }));
|
|
249
|
+
}
|
|
250
|
+
yield this.write(true);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
listActivities() {
|
|
254
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
255
|
+
return this.getRepo().list();
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
loadDetailsByName(name) {
|
|
259
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
260
|
+
let details;
|
|
261
|
+
try {
|
|
262
|
+
details = yield this.getRepo().read(name);
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
this.logger.logEvent({ message: 'could not load activity details', name, reason: err.message, stack: err.stack });
|
|
266
|
+
}
|
|
267
|
+
return details;
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
loadDetails(name, id) {
|
|
271
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
272
|
+
const details = yield this.loadDetailsByName(name);
|
|
273
|
+
const aid = id !== null && id !== void 0 ? id : details.id;
|
|
274
|
+
const activity = this.getActivity(aid);
|
|
275
|
+
if (activity) {
|
|
276
|
+
activity.details = details;
|
|
277
|
+
this.emitUpdated(activity);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
writeDetails(activity) {
|
|
282
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
283
|
+
const name = activity.summary.name;
|
|
284
|
+
this.getRepo().write(name, activity.details);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
buildSummary(activity, name) {
|
|
288
|
+
var _a;
|
|
289
|
+
const { id, title, route, screenshots, startTime: startTimeUTC, time: rideTime, distance, startPos, realityFactor = 100, links, laps } = activity;
|
|
290
|
+
const routeId = route === null || route === void 0 ? void 0 : route.id;
|
|
291
|
+
const shots = screenshots !== null && screenshots !== void 0 ? screenshots : [];
|
|
292
|
+
const preview = (_a = shots.find(s => s.isHighlight)) !== null && _a !== void 0 ? _a : shots[0];
|
|
293
|
+
const previewImage = preview === null || preview === void 0 ? void 0 : preview.fileName;
|
|
294
|
+
let startTime;
|
|
295
|
+
if (startTimeUTC)
|
|
296
|
+
startTime = (new Date(startTimeUTC)).getTime();
|
|
297
|
+
const uploadStatus = [];
|
|
298
|
+
if (links === null || links === void 0 ? void 0 : links.strava) {
|
|
299
|
+
uploadStatus.push({ service: 'strava', status: 'success' });
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
id, title, name, routeId, previewImage, startTime, rideTime, distance, startPos, realityFactor, uploadStatus, laps
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
scanForActivities() {
|
|
306
|
+
var _a, _b;
|
|
307
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
308
|
+
try {
|
|
309
|
+
this.isDBComplete = (_a = this.isDBComplete) !== null && _a !== void 0 ? _a : false;
|
|
310
|
+
const names = yield this.listActivities();
|
|
311
|
+
if (!names)
|
|
312
|
+
return null;
|
|
313
|
+
const promises = [];
|
|
314
|
+
names.forEach(name => promises.push(this.loadDetailsByName(name).then((details) => ({ name, details }))));
|
|
315
|
+
const result = yield Promise.allSettled(promises);
|
|
316
|
+
const activities = [];
|
|
317
|
+
let isComplete = true;
|
|
318
|
+
result.forEach(result => {
|
|
319
|
+
var _a;
|
|
320
|
+
if (result.status === "rejected")
|
|
321
|
+
isComplete = false;
|
|
322
|
+
else {
|
|
323
|
+
const details = (_a = result.value) === null || _a === void 0 ? void 0 : _a.details;
|
|
324
|
+
const name = result.value.name;
|
|
325
|
+
const summary = this.buildSummary(details, name);
|
|
326
|
+
activities.push(summary);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
this.isDBComplete = (_b = this.isDBComplete) !== null && _b !== void 0 ? _b : isComplete;
|
|
330
|
+
return activities;
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
scanForActivitiesAndMerge(activities) {
|
|
338
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
const total = yield this.scanForActivities();
|
|
340
|
+
if (total === null)
|
|
341
|
+
return activities;
|
|
342
|
+
total.forEach(activity => {
|
|
343
|
+
if (!activities.map(a => a.id).includes(activity.id))
|
|
344
|
+
activities.push(activity);
|
|
345
|
+
});
|
|
346
|
+
return activities;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
_load() {
|
|
350
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
351
|
+
yield this.loadSummaries();
|
|
352
|
+
this.emitDone();
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
getActivity(id) {
|
|
356
|
+
return this.activities.find(ai => ai.summary.id === id);
|
|
357
|
+
}
|
|
358
|
+
logError(error, fn, logProps) {
|
|
359
|
+
const props = logProps !== null && logProps !== void 0 ? logProps : {};
|
|
360
|
+
this.logger.logEvent(Object.assign({ message: 'error', error, fn }, props));
|
|
361
|
+
}
|
|
362
|
+
getRepo() {
|
|
363
|
+
if (!this.repo)
|
|
364
|
+
this.repo = api_1.JsonRepository.create('activities');
|
|
365
|
+
return this.repo;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
__setFunctionName(_classThis, "ActivitiesDbLoader");
|
|
369
|
+
(() => {
|
|
370
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
371
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
372
|
+
ActivitiesDbLoader = _classThis = _classDescriptor.value;
|
|
373
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
374
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
375
|
+
})();
|
|
376
|
+
return ActivitiesDbLoader = _classThis;
|
|
377
|
+
})();
|
|
378
|
+
exports.ActivitiesDbLoader = ActivitiesDbLoader;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./db"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RoutePoint } from "../../../routes/base/types";
|
|
2
|
+
export type ActivityUser = {
|
|
3
|
+
uuid?: string;
|
|
4
|
+
weight: number;
|
|
5
|
+
ftp: number;
|
|
6
|
+
};
|
|
7
|
+
export type ActivityRoute = {
|
|
8
|
+
id?: string;
|
|
9
|
+
hash: string;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
export type ActivityStatsRecord = {
|
|
13
|
+
min: number;
|
|
14
|
+
max: number;
|
|
15
|
+
avg: number;
|
|
16
|
+
cntVal: number;
|
|
17
|
+
sum: number;
|
|
18
|
+
minAllowed: number;
|
|
19
|
+
};
|
|
20
|
+
export type ActivityLogRecord = {
|
|
21
|
+
time: number;
|
|
22
|
+
timeDelta: number;
|
|
23
|
+
speed: number;
|
|
24
|
+
slope: number;
|
|
25
|
+
cadence: number;
|
|
26
|
+
heartrate: number;
|
|
27
|
+
distance: number;
|
|
28
|
+
power: number;
|
|
29
|
+
lat?: number;
|
|
30
|
+
lon?: number;
|
|
31
|
+
elevation?: number;
|
|
32
|
+
};
|
|
33
|
+
export type ActivityStats = {
|
|
34
|
+
hrm?: ActivityStatsRecord;
|
|
35
|
+
cadence?: ActivityStatsRecord;
|
|
36
|
+
speed: ActivityStatsRecord;
|
|
37
|
+
slope?: ActivityStatsRecord;
|
|
38
|
+
power: ActivityStatsRecord;
|
|
39
|
+
};
|
|
40
|
+
export type StravaAppLink = {
|
|
41
|
+
upload_id: number;
|
|
42
|
+
activity_id: number;
|
|
43
|
+
};
|
|
44
|
+
export type ActivityAppLinks = {
|
|
45
|
+
strava?: StravaAppLink;
|
|
46
|
+
};
|
|
47
|
+
export type ScreenShotInfo = {
|
|
48
|
+
fileName: string;
|
|
49
|
+
position: RoutePoint;
|
|
50
|
+
isHighlight?: boolean;
|
|
51
|
+
};
|
|
52
|
+
export type ActivityType = 'IncyclistActivity';
|
|
53
|
+
export type UploadStatus = 'success' | 'failure';
|
|
54
|
+
export type UploadInfo = {
|
|
55
|
+
service: string;
|
|
56
|
+
status: UploadStatus;
|
|
57
|
+
};
|
|
58
|
+
export type ActivityDB = {
|
|
59
|
+
version: string;
|
|
60
|
+
activities: Array<ActivitySummary>;
|
|
61
|
+
isComplete: boolean;
|
|
62
|
+
};
|
|
63
|
+
export type ActivitySummary = {
|
|
64
|
+
id: string;
|
|
65
|
+
title: string;
|
|
66
|
+
name: string;
|
|
67
|
+
routeId: string;
|
|
68
|
+
previewImage?: string;
|
|
69
|
+
startTime: number;
|
|
70
|
+
rideTime: number;
|
|
71
|
+
distance: number;
|
|
72
|
+
startPos: number;
|
|
73
|
+
realityFactor: number;
|
|
74
|
+
uploadStatus: Array<UploadInfo>;
|
|
75
|
+
isCompleted?: boolean;
|
|
76
|
+
isSaved?: boolean;
|
|
77
|
+
saveRideTime?: number;
|
|
78
|
+
laps?: Array<LapSummary>;
|
|
79
|
+
};
|
|
80
|
+
export type LapSummary = {
|
|
81
|
+
num: number;
|
|
82
|
+
startPos: number;
|
|
83
|
+
distance: number;
|
|
84
|
+
startTime: number;
|
|
85
|
+
rideTime: number;
|
|
86
|
+
};
|
|
87
|
+
export type ActivityDetails = {
|
|
88
|
+
type?: ActivityType;
|
|
89
|
+
version?: string;
|
|
90
|
+
title: string;
|
|
91
|
+
id: string;
|
|
92
|
+
user: ActivityUser;
|
|
93
|
+
route: ActivityRoute;
|
|
94
|
+
startTime: string;
|
|
95
|
+
time: number;
|
|
96
|
+
timeTotal: number;
|
|
97
|
+
timePause: number;
|
|
98
|
+
distance: number;
|
|
99
|
+
startPos: number;
|
|
100
|
+
startpos: number;
|
|
101
|
+
endpos: number;
|
|
102
|
+
totalElevation: number;
|
|
103
|
+
stats: ActivityStats;
|
|
104
|
+
logs: Array<ActivityLogRecord>;
|
|
105
|
+
screenshots: Array<ScreenShotInfo>;
|
|
106
|
+
fileName?: string;
|
|
107
|
+
tcxFileName?: string;
|
|
108
|
+
fitFileName?: string;
|
|
109
|
+
links?: ActivityAppLinks;
|
|
110
|
+
realityFactor: number;
|
|
111
|
+
laps?: Array<LapSummary>;
|
|
112
|
+
};
|
|
113
|
+
export type ActivityInfo = {
|
|
114
|
+
summary: ActivitySummary;
|
|
115
|
+
details?: ActivityDetails;
|
|
116
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./base/model"), exports);
|
|
18
|
+
__exportStar(require("./base/loaders"), exports);
|
|
@@ -15,5 +15,6 @@ export declare class JsonRepository {
|
|
|
15
15
|
read(objectName: string): Promise<JSONObject>;
|
|
16
16
|
delete(objectName: string): Promise<boolean>;
|
|
17
17
|
protected open(): Promise<boolean>;
|
|
18
|
+
list(exclude?: string | Array<string>): Promise<Array<string>>;
|
|
18
19
|
protected close(): Promise<boolean>;
|
|
19
20
|
}
|
|
@@ -75,6 +75,25 @@ class JsonRepository {
|
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
+
list(exclude) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
try {
|
|
81
|
+
let names = yield this.access.list();
|
|
82
|
+
if (!names)
|
|
83
|
+
return null;
|
|
84
|
+
names = names.filter(name => name.toLowerCase().endsWith('.json'));
|
|
85
|
+
names = names.map(name => name.substring(0, name.length - 5));
|
|
86
|
+
if (exclude) {
|
|
87
|
+
const excludes = (typeof (exclude) === 'string') ? [exclude] : exclude;
|
|
88
|
+
names = names.filter(name => !excludes.includes(name));
|
|
89
|
+
}
|
|
90
|
+
return names;
|
|
91
|
+
}
|
|
92
|
+
catch (_a) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
78
97
|
close() {
|
|
79
98
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
99
|
const db = (0, bindings_1.getBindings)().db;
|
|
@@ -5,6 +5,7 @@ export type JsonAccess = {
|
|
|
5
5
|
read(resourceName: string): Promise<JSONObject>;
|
|
6
6
|
write(resourceName: string, data: JSONObject): Promise<boolean>;
|
|
7
7
|
delete(resourceName: string): Promise<boolean>;
|
|
8
|
+
list(): Promise<Array<string>>;
|
|
8
9
|
};
|
|
9
10
|
export interface IJsonRepositoryBinding {
|
|
10
11
|
create(name: string): Promise<JsonAccess | null>;
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -21,6 +21,7 @@ __exportStar(require("./api"), exports);
|
|
|
21
21
|
__exportStar(require("./routes"), exports);
|
|
22
22
|
__exportStar(require("./workouts"), exports);
|
|
23
23
|
__exportStar(require("./coaches"), exports);
|
|
24
|
+
__exportStar(require("./activities"), exports);
|
|
24
25
|
var settings_1 = require("./settings");
|
|
25
26
|
Object.defineProperty(exports, "useUserSettings", { enumerable: true, get: function () { return settings_1.useUserSettings; } });
|
|
26
27
|
Object.defineProperty(exports, "initUserSettings", { enumerable: true, get: function () { return settings_1.initUserSettings; } });
|
|
@@ -7,7 +7,7 @@ exports.getPosition = exports.getNextPosition = exports.getRouteHash = exports.g
|
|
|
7
7
|
const utils_1 = require("../../../utils");
|
|
8
8
|
const geo_1 = require("../../../utils/geo");
|
|
9
9
|
const valid_1 = require("../../../utils/valid");
|
|
10
|
-
const
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
11
|
const MAX_LAPMODE_DISTANCE = 50;
|
|
12
12
|
const checkIsLoop = (_route) => {
|
|
13
13
|
var _a;
|
|
@@ -155,7 +155,7 @@ const getRouteHash = (route) => {
|
|
|
155
155
|
else {
|
|
156
156
|
json = { decoded: route.points.map(p => ({ lat: p.lat, lng: p.lng })) };
|
|
157
157
|
}
|
|
158
|
-
const routeHash =
|
|
158
|
+
const routeHash = crypto_1.default.createHash('md5').update(JSON.stringify(json)).digest('hex');
|
|
159
159
|
return routeHash;
|
|
160
160
|
};
|
|
161
161
|
exports.getRouteHash = getRouteHash;
|
|
@@ -7,7 +7,7 @@ exports.Plan = exports.Workout = void 0;
|
|
|
7
7
|
const Step_1 = require("./Step");
|
|
8
8
|
const Segment_1 = require("./Segment");
|
|
9
9
|
const valid_1 = require("../../../utils/valid");
|
|
10
|
-
const
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
11
|
class Workout extends Segment_1.Segment {
|
|
12
12
|
constructor(opts) {
|
|
13
13
|
var _a;
|
|
@@ -36,7 +36,7 @@ class Workout extends Segment_1.Segment {
|
|
|
36
36
|
if (this._hash)
|
|
37
37
|
return this.hash;
|
|
38
38
|
const { name, description, steps, repeat } = this;
|
|
39
|
-
this._hash =
|
|
39
|
+
this._hash = crypto_1.default.createHash('md5').update(JSON.stringify({ name, description, steps, repeat })).digest('hex');
|
|
40
40
|
return this._hash;
|
|
41
41
|
}
|
|
42
42
|
getSegment(time) {
|
|
@@ -85,7 +85,8 @@ class Plan {
|
|
|
85
85
|
if (this._hash)
|
|
86
86
|
return this.hash;
|
|
87
87
|
const { name, description, workouts } = this;
|
|
88
|
-
|
|
88
|
+
const data = JSON.stringify({ name, description, workouts });
|
|
89
|
+
this._hash = crypto_1.default.createHash('md5').update(data).digest('hex');
|
|
89
90
|
return this._hash;
|
|
90
91
|
}
|
|
91
92
|
addWorkoutSchedule(week, day, workoutId) {
|
|
@@ -19,7 +19,7 @@ export declare class WorkoutCard extends BaseCard implements Card<Workout> {
|
|
|
19
19
|
select(settings?: WorkoutSettings): void;
|
|
20
20
|
unselect(): void;
|
|
21
21
|
move(targetListName: string): void;
|
|
22
|
-
save(): Promise<void>;
|
|
22
|
+
save(enforce?: boolean): Promise<void>;
|
|
23
23
|
delete(): PromiseObserver<boolean>;
|
|
24
24
|
getId(): string;
|
|
25
25
|
getTitle(): string;
|
|
@@ -71,12 +71,12 @@ class WorkoutCard extends base_1.BaseCard {
|
|
|
71
71
|
this.list = newList;
|
|
72
72
|
}
|
|
73
73
|
this.workout.category = { name: targetListName, index: newList === null || newList === void 0 ? void 0 : newList.length };
|
|
74
|
-
this.save();
|
|
74
|
+
this.save(true);
|
|
75
75
|
}
|
|
76
|
-
save() {
|
|
76
|
+
save(enforce = false) {
|
|
77
77
|
return __awaiter(this, void 0, void 0, function* () {
|
|
78
78
|
try {
|
|
79
|
-
return yield this.getRepo().save(this.workout);
|
|
79
|
+
return yield this.getRepo().save(this.workout, enforce);
|
|
80
80
|
}
|
|
81
81
|
catch (err) {
|
|
82
82
|
this.logError(err, 'save');
|
|
@@ -16,7 +16,7 @@ export declare class WorkoutsDbLoader extends Loader {
|
|
|
16
16
|
constructor();
|
|
17
17
|
load(): Observer;
|
|
18
18
|
stopLoad(): void;
|
|
19
|
-
save(workout: Workout | Plan): Promise<void>;
|
|
19
|
+
save(workout: Workout | Plan, enforceWrite?: boolean): Promise<void>;
|
|
20
20
|
delete(workout: Workout | Plan): Promise<void>;
|
|
21
21
|
protected getRepo(): JsonRepository;
|
|
22
22
|
protected _load(): Promise<void>;
|
|
@@ -85,7 +85,7 @@ let WorkoutsDbLoader = (() => {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
save(workout) {
|
|
88
|
+
save(workout, enforceWrite = false) {
|
|
89
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
90
90
|
if (!(0, valid_1.valid)(workout))
|
|
91
91
|
return;
|
|
@@ -106,9 +106,9 @@ let WorkoutsDbLoader = (() => {
|
|
|
106
106
|
else {
|
|
107
107
|
prev = stringify(Object.assign({}, this.workouts[idx]));
|
|
108
108
|
this.workouts[idx] = workout;
|
|
109
|
-
changed = stringify(Object.assign({},
|
|
109
|
+
changed = stringify(Object.assign({}, workout)) !== prev;
|
|
110
110
|
}
|
|
111
|
-
if (changed) {
|
|
111
|
+
if (changed || enforceWrite) {
|
|
112
112
|
this.isDirty = true;
|
|
113
113
|
this.write();
|
|
114
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-services",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"gd-eventlog": "^0.1.26"
|
|
6
6
|
},
|
|
@@ -39,8 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"axios": "^1.6.1",
|
|
42
|
-
"incyclist-devices": "^2.
|
|
43
|
-
"md5": "^2.3.0",
|
|
42
|
+
"incyclist-devices": "^2.2.0",
|
|
44
43
|
"promise.any": "^2.0.6",
|
|
45
44
|
"uuid": "^9.0.0",
|
|
46
45
|
"xml2js": "^0.6.2"
|