incyclist-services 1.6.4 → 1.6.5

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,4 +1,4 @@
1
- import { DeviceData, UpdateRequest } from "incyclist-devices";
1
+ import { CyclingMode, DeviceData, UpdateRequest } from "incyclist-devices";
2
2
  import { Observer } from "../../base/types";
3
3
  import { ActiveWorkoutLimit } from "../../workouts";
4
4
  import { CurrentRideDisplayProps, ICurrentRideService, IRideModeService, IRideModeServiceDisplayProps } from "./types";
@@ -39,8 +39,11 @@ export declare class RideModeService extends IncyclistService implements IRideMo
39
39
  }): UpdateRequest;
40
40
  sendUpdate(request?: UpdateRequest): Promise<void>;
41
41
  protected processPowerDeltaRequest(request: UpdateRequest): void;
42
+ protected isForcedERG(): boolean;
43
+ protected updatePropsForForcedERG(mode: CyclingMode, logProps: any): void;
42
44
  protected getBikeLogProps(): object;
43
45
  protected getDashboardColumns(): number;
44
46
  protected getDeviceRide(): import("../../devices").DeviceRideService;
45
47
  protected getWorkoutRide(): import("../../workouts").WorkoutRide;
48
+ protected getWorkoutList(): import("../../workouts").WorkoutListService;
46
49
  }
@@ -54,6 +54,7 @@ let RideModeService = (() => {
54
54
  let _classSuper = service_1.IncyclistService;
55
55
  let _instanceExtraInitializers = [];
56
56
  let _getDeviceRide_decorators;
57
+ let _getWorkoutList_decorators;
57
58
  return _a = class RideModeService extends _classSuper {
58
59
  constructor() {
59
60
  super('Ride');
@@ -169,6 +170,31 @@ let RideModeService = (() => {
169
170
  }
170
171
  send(request);
171
172
  }
173
+ isForcedERG() {
174
+ var _b;
175
+ let forceErgMode = false;
176
+ if (this.getWorkoutList().getSelected()) {
177
+ forceErgMode = (_b = this.getWorkoutList().getStartSettings()) === null || _b === void 0 ? void 0 : _b.useErgMode;
178
+ }
179
+ return forceErgMode;
180
+ }
181
+ updatePropsForForcedERG(mode, logProps) {
182
+ try {
183
+ const isSIM = typeof (mode === null || mode === void 0 ? void 0 : mode.isSIM) === 'function' ? mode.isSIM() : false;
184
+ if (this.isForcedERG()) {
185
+ if (isSIM) {
186
+ logProps.bikeMode = 'ERG (Workout)';
187
+ }
188
+ delete logProps['virtshift'];
189
+ delete logProps['startGear'];
190
+ delete logProps['slopeAdj'];
191
+ delete logProps['slopeAsjDown'];
192
+ }
193
+ }
194
+ catch (err) {
195
+ this.logError(err, 'updatePropsForForcedERG');
196
+ }
197
+ }
172
198
  getBikeLogProps() {
173
199
  var _b, _c, _d;
174
200
  const device = this.getDeviceRide().getControlAdapter();
@@ -176,10 +202,13 @@ let RideModeService = (() => {
176
202
  return {};
177
203
  const mode = this.getDeviceRide().getCyclingMode();
178
204
  if ((mode === null || mode === void 0 ? void 0 : mode.getName()) === 'Simulator') {
179
- return { bike: 'Simulator', interface: 'Simulator', mode: 'Simulator' };
205
+ return { bike: 'Simulator', interface: 'Simulator', bikeMode: 'Simulator' };
180
206
  }
207
+ let bikeMode = mode === null || mode === void 0 ? void 0 : mode.getName();
181
208
  const settings = (_b = mode === null || mode === void 0 ? void 0 : mode.getSettings()) !== null && _b !== void 0 ? _b : {};
182
- return Object.assign({ bike: (_c = device.adapter) === null || _c === void 0 ? void 0 : _c.getDisplayName(), interface: (_d = device.adapter) === null || _d === void 0 ? void 0 : _d.getInterface(), bikeMode: mode === null || mode === void 0 ? void 0 : mode.getName() }, settings);
209
+ const logProps = Object.assign({ bikeMode }, settings);
210
+ this.updatePropsForForcedERG(mode, logProps);
211
+ return Object.assign({ bike: (_c = device.adapter) === null || _c === void 0 ? void 0 : _c.getDisplayName(), interface: (_d = device.adapter) === null || _d === void 0 ? void 0 : _d.getInterface() }, logProps);
183
212
  }
184
213
  getDashboardColumns() {
185
214
  const mode = this.getDeviceRide().getCyclingMode();
@@ -193,12 +222,17 @@ let RideModeService = (() => {
193
222
  getWorkoutRide() {
194
223
  return (0, workouts_1.useWorkoutRide)();
195
224
  }
225
+ getWorkoutList() {
226
+ return (0, workouts_1.useWorkoutList)();
227
+ }
196
228
  },
197
229
  (() => {
198
230
  var _b;
199
231
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
200
232
  _getDeviceRide_decorators = [decorators_1.Injectable];
233
+ _getWorkoutList_decorators = [decorators_1.Injectable];
201
234
  __esDecorate(_a, null, _getDeviceRide_decorators, { kind: "method", name: "getDeviceRide", static: false, private: false, access: { has: obj => "getDeviceRide" in obj, get: obj => obj.getDeviceRide }, metadata: _metadata }, null, _instanceExtraInitializers);
235
+ __esDecorate(_a, null, _getWorkoutList_decorators, { kind: "method", name: "getWorkoutList", static: false, private: false, access: { has: obj => "getWorkoutList" in obj, get: obj => obj.getWorkoutList }, metadata: _metadata }, null, _instanceExtraInitializers);
202
236
  if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
203
237
  })(),
204
238
  _a;
@@ -387,7 +387,6 @@ let RLVDisplayService = (() => {
387
387
  this.emit('state-update');
388
388
  }
389
389
  onVideoStalled(time, bufferedTime, buffers, video = this.currentVideo) {
390
- this.logEvent({ message: 'video stalled', bufferedTime, buffers });
391
390
  video.syncHelper.onVideoStalled(time, bufferedTime);
392
391
  }
393
392
  onVideoWaiting(time, rate, bufferedTime, buffers, video = this.currentVideo) {
@@ -33,6 +33,7 @@ export declare class VideoSyncHelper extends IncyclistService {
33
33
  loopMode?: boolean;
34
34
  observer?: Observer;
35
35
  });
36
+ logEvent(event: any): void;
36
37
  pause(): void;
37
38
  resume(): void;
38
39
  reset(): void;
@@ -45,7 +46,7 @@ export declare class VideoSyncHelper extends IncyclistService {
45
46
  networkState?: number;
46
47
  bufferedTime?: number;
47
48
  }): void;
48
- onVideoStalled(time: number, bufferedTime: number): void;
49
+ onVideoStalled(time: number, _bufferedTime: number): void;
49
50
  onVideoWaiting(time: number, rate: number, bufferedTime: number, buffers: Array<{
50
51
  start: number;
51
52
  end: number;
@@ -70,4 +71,6 @@ export declare class VideoSyncHelper extends IncyclistService {
70
71
  protected validateMappings(route: Route): void;
71
72
  protected initCorrectedMapping(routeData: RouteApiDetail): import("../routes/base/types").VideoMapping[];
72
73
  protected logPlaybackSummary(): void;
74
+ protected checkIfStalled(): void;
75
+ protected checkIfStalledEnded(time: number): void;
73
76
  }
@@ -19,8 +19,17 @@ class VideoSyncHelper extends service_1.IncyclistService {
19
19
  this.initCorrectedMapping((_a = this.route) === null || _a === void 0 ? void 0 : _a.details);
20
20
  this.init(startPos, props);
21
21
  }
22
+ logEvent(event) {
23
+ var _a, _b;
24
+ if (!event)
25
+ return;
26
+ const route = (_b = (_a = this.route) === null || _a === void 0 ? void 0 : _a.details) === null || _b === void 0 ? void 0 : _b.title;
27
+ const syncId = this.id;
28
+ const logEvent = Object.assign({ message: event.message, route, syncId }, event);
29
+ super.logEvent(logEvent);
30
+ }
22
31
  pause() {
23
- this.logEvent({ message: 'video paused', route: this.route.details.title });
32
+ this.logEvent({ message: 'video paused' });
24
33
  this.logPlaybackSummary();
25
34
  this.isPaused = true;
26
35
  this.send('rate-update', 0);
@@ -30,18 +39,18 @@ class VideoSyncHelper extends service_1.IncyclistService {
30
39
  resume() {
31
40
  if (this.isStopped)
32
41
  return;
33
- this.logEvent({ message: 'video resumed', route: this.route.details.title });
42
+ this.logEvent({ message: 'video resumed' });
34
43
  this.isPaused = false;
35
44
  this.activityStatus.ts = Date.now();
36
45
  this.rlvStatus.ts = Date.now();
37
46
  }
38
47
  reset() {
39
- this.logEvent({ message: 'video reset', route: this.route.details.title });
48
+ this.logEvent({ message: 'video reset' });
40
49
  this.init(0, { loopMode: this.loopMode, observer: this.observer });
41
50
  delete this.endTime;
42
51
  }
43
52
  stop() {
44
- this.logEvent({ message: 'video stopped', route: this.route.details.title });
53
+ this.logEvent({ message: 'video stopped' });
45
54
  this.send('rate-update', 0);
46
55
  this.isPaused = true;
47
56
  this.isStopped = true;
@@ -64,7 +73,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
64
73
  this.isStopped = true;
65
74
  }
66
75
  onVideoPlaybackUpdate(time, rate, e) {
67
- var _a, _b, _c, _d, _e;
76
+ var _a, _b, _c, _d, _e, _f;
68
77
  try {
69
78
  this.endTime = (_a = this.endTime) !== null && _a !== void 0 ? _a : this.getVideoTimeByPosition((_b = this.route.description) === null || _b === void 0 ? void 0 : _b.distance);
70
79
  const endTime = this.endTime;
@@ -92,6 +101,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
92
101
  }
93
102
  else if (this.rlvStatus.rateRequested !== undefined && rate >= this.rlvStatus.rateRequested) {
94
103
  delete this.rlvStatus.rateRequested;
104
+ delete this.rlvStatus.tsLastRateRequest;
95
105
  if (this.tsLastIssue !== undefined) {
96
106
  const timeSinceLastIssue = (Date.now() - this.tsLastIssue) / 1000;
97
107
  const timeSinceLastRateIncrease = (Date.now() - ((_d = this.tsLastRateIncrease) !== null && _d !== void 0 ? _d : 0)) / 1000;
@@ -113,15 +123,19 @@ class VideoSyncHelper extends service_1.IncyclistService {
113
123
  this.maxSuccessRate = Math.max(this.maxSuccessRate, rate);
114
124
  }
115
125
  }
116
- else {
126
+ else if (this.rlvStatus.rateRequested !== undefined && (Date.now() - ((_e = this.rlvStatus.rateRequested) !== null && _e !== void 0 ? _e : 0) > 2000)) {
127
+ delete this.rlvStatus.rateRequested;
128
+ delete this.rlvStatus.rateRequested;
129
+ this.logEvent({ message: 'video rate update timeout' });
117
130
  }
131
+ this.checkIfStalledEnded(time);
132
+ this.rlvPrev = Object.assign({}, this.rlvStatus);
118
133
  if (this.isPaused) {
119
134
  this.rlvStatus.ts = Date.now();
120
135
  this.rlvStatus.time = time;
121
136
  this.rlvStatus.rate = 0;
122
137
  return;
123
138
  }
124
- this.rlvPrev = Object.assign({}, this.rlvStatus);
125
139
  this.rlvStatus.ts = Date.now();
126
140
  this.rlvStatus.time = time;
127
141
  this.rlvStatus.rate = rate;
@@ -153,14 +167,16 @@ class VideoSyncHelper extends service_1.IncyclistService {
153
167
  if (this.rlvStatus.speed !== this.rlvPrev.speed) {
154
168
  updates.push('rlv:speed');
155
169
  }
156
- this.cpuTime = ((_e = this.cpuTime) !== null && _e !== void 0 ? _e : 0) + (Date.now() - tsStart);
170
+ this.cpuTime = ((_f = this.cpuTime) !== null && _f !== void 0 ? _f : 0) + (Date.now() - tsStart);
157
171
  this.onUpdate(updates);
158
172
  }
159
173
  catch (err) {
160
174
  this.logError(err, 'onVideoPlaybackUpdate');
161
175
  }
162
176
  }
163
- onVideoStalled(time, bufferedTime) {
177
+ onVideoStalled(time, _bufferedTime) {
178
+ this.logEvent({ message: 'video stalled', time, source: 'event' });
179
+ this.rlvStatus.isStalled = true;
164
180
  }
165
181
  onVideoWaiting(time, rate, bufferedTime, buffers) {
166
182
  this.logEvent({ message: 'video waiting', time, bufferedTime, buffers });
@@ -204,6 +220,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
204
220
  this.activityStatus.ts = Date.now();
205
221
  this.activityStatus.routeDistance = distance;
206
222
  this.activityStatus.speed = speed;
223
+ this.checkIfStalled();
207
224
  this.onUpdate(updates);
208
225
  }
209
226
  onUpdate(updates = []) {
@@ -267,8 +284,18 @@ class VideoSyncHelper extends service_1.IncyclistService {
267
284
  if (newTime - this.rlvStatus.time > 1) {
268
285
  this.logEvent({ message: 'video forwarded', newTime });
269
286
  this.updateTime(newTime);
287
+ this.prevDelta = delta;
288
+ }
289
+ else {
290
+ const time = this.rlvStatus.time;
291
+ const vt = this.loopMode ? this.getLapTime(time) : (time > this.getTotalTime() ? this.getTotalTime() : time);
292
+ const mapping = this.getMappingByTime(vt);
293
+ this.logEvent({ message: 'video forwarded skipped',
294
+ newTime, rlvTime: this.rlvStatus.time, rlvSpeed: this.rlvStatus.speed, rate: this.rlvStatus.rate,
295
+ routeDistance: this.rlvStatus.routeDistance, tDelta: Date.now() - this.rlvStatus.ts,
296
+ mapping
297
+ });
270
298
  }
271
- this.prevDelta = delta;
272
299
  }
273
300
  else {
274
301
  this.prevDelta = delta;
@@ -294,8 +321,12 @@ class VideoSyncHelper extends service_1.IncyclistService {
294
321
  }
295
322
  }
296
323
  updateRate(requested) {
297
- if (requested === undefined || isNaN(requested))
324
+ if (requested === undefined)
325
+ return;
326
+ if (isNaN(requested)) {
327
+ delete this.rlvStatus.rateRequested;
298
328
  return;
329
+ }
299
330
  if (!this.isPaused && !this.isStopped && this.rlvStatus.rate !== undefined && Math.abs(requested - this.rlvStatus.rate) < 0.01) {
300
331
  delete this.rlvStatus.rateRequested;
301
332
  return;
@@ -317,6 +348,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
317
348
  return;
318
349
  }
319
350
  this.rlvStatus.rateRequested = rate;
351
+ this.rlvStatus.tsLastRateRequest = Date.now();
320
352
  this.send('rate-update', rate);
321
353
  }
322
354
  updateTime(time) {
@@ -324,6 +356,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
324
356
  return;
325
357
  this.rlvStatus.timeRequested = time;
326
358
  delete this.rlvStatus.rateRequested;
359
+ delete this.rlvStatus.tsLastRateRequest;
327
360
  delete this.tsLastIssue;
328
361
  delete this.tsLastRateIncrease;
329
362
  this.send('time-update', time);
@@ -541,8 +574,25 @@ class VideoSyncHelper extends service_1.IncyclistService {
541
574
  if (Date.now() - ((_a = this.tsLastSummeryLog) !== null && _a !== void 0 ? _a : 0) < 60000)
542
575
  return;
543
576
  const totalTime = Date.now() - this.tsStart;
544
- this.logEvent({ message: 'video playback summary', syncId: this.id, route: this.route.details.title, routeId: this.route.description.id, maxDelta: n(this.maxDelta, 1), cntWaiting: this.cntWaitingEvents, totalTime: f(totalTime !== null && totalTime !== void 0 ? totalTime : 0), cpuTime: f((_b = this.cpuTime) !== null && _b !== void 0 ? _b : 0), pct: n(this.cpuTime / totalTime * 100, 1) });
577
+ this.logEvent({ message: 'video playback summary', routeId: this.route.description.id, maxDelta: n(this.maxDelta, 1), cntWaiting: this.cntWaitingEvents, totalTime: f(totalTime !== null && totalTime !== void 0 ? totalTime : 0), cpuTime: f((_b = this.cpuTime) !== null && _b !== void 0 ? _b : 0), pct: n(this.cpuTime / totalTime * 100, 1) });
545
578
  this.tsLastSummeryLog = Date.now();
546
579
  }
580
+ checkIfStalled() {
581
+ if (this.rlvStatus.tsVideoUpdate === undefined)
582
+ return;
583
+ const timeSinceLastUpdate = Date.now() - this.rlvStatus.tsVideoUpdate;
584
+ if (timeSinceLastUpdate > 2000 && !this.rlvStatus.isStalled) {
585
+ this.rlvStatus.isStalled = true;
586
+ this.logEvent({ message: 'video stalled', time: this.rlvStatus.time, source: 'timeout' });
587
+ }
588
+ }
589
+ checkIfStalledEnded(time) {
590
+ if (!this.rlvStatus.isStalled)
591
+ return;
592
+ if (time > this.rlvPrev.time) {
593
+ this.rlvStatus.isStalled = false;
594
+ this.logEvent({ message: 'video playback unstalled' });
595
+ }
596
+ }
547
597
  }
548
598
  exports.VideoSyncHelper = VideoSyncHelper;
@@ -1,6 +1,7 @@
1
1
  export type RLVPlaybackStatus = {
2
2
  rate: number;
3
3
  rateRequested?: number;
4
+ tsLastRateRequest?: number;
4
5
  time: number;
5
6
  timeRequested?: number;
6
7
  tsLastTimeRequest?: number;
@@ -10,6 +11,7 @@ export type RLVPlaybackStatus = {
10
11
  tsVideoUpdate?: number;
11
12
  lap: number;
12
13
  lapRequested?: boolean;
14
+ isStalled?: boolean;
13
15
  };
14
16
  export type RLVActivityStatus = {
15
17
  routeDistance: number;
@@ -196,6 +196,9 @@ let WorkoutRide = (() => {
196
196
  const ts = this.trainingTime;
197
197
  const wo = this.workout;
198
198
  const limits = wo.getLimits(ts);
199
+ if (!limits) {
200
+ return;
201
+ }
199
202
  this.manualTimeOffset += limits.remaining;
200
203
  this.update();
201
204
  this.observer.emit('forward', ts, limits.remaining);
@@ -205,10 +208,14 @@ let WorkoutRide = (() => {
205
208
  }
206
209
  }
207
210
  backward() {
211
+ var _a;
208
212
  try {
209
213
  const ts = this.trainingTime;
210
214
  const wo = this.workout;
211
215
  const limits = wo.getLimits(ts, true);
216
+ if (!limits) {
217
+ return;
218
+ }
212
219
  const completed = limits.duration - limits.remaining;
213
220
  const stepBusyLmit = Math.min(15, limits.duration / 2);
214
221
  let diff = completed;
@@ -237,7 +244,14 @@ let WorkoutRide = (() => {
237
244
  this.observer.emit('backward', ts, diff, jumpType, limits === null || limits === void 0 ? void 0 : limits.step, target);
238
245
  }
239
246
  catch (err) {
240
- this.logError(err, 'backward');
247
+ let limits;
248
+ let ts;
249
+ try {
250
+ ts = this.trainingTime;
251
+ limits = (_a = this.workout) === null || _a === void 0 ? void 0 : _a.getLimits(ts, true);
252
+ }
253
+ catch (_b) { }
254
+ this.logError(err, 'backward', { ts, limits });
241
255
  }
242
256
  }
243
257
  powerUp(delta) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.26"
6
6
  },