incyclist-services 1.3.27 → 1.3.29
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/ride/service.d.ts +1 -1
- package/lib/routes/base/api/index.d.ts +1 -0
- package/lib/routes/base/api/index.js +3 -0
- package/lib/routes/list/loaders/api.e2e.test copy.d.ts +1 -0
- package/lib/routes/list/loaders/api.e2e.test copy.js +69 -0
- package/lib/routes/list/loaders/api.js +1 -0
- package/lib/routes/list/loaders/db.d.ts +1 -2
- package/lib/routes/list/loaders/db.js +35 -25
- package/lib/routes/list/loaders/db_new.d.ts +44 -0
- package/lib/routes/list/loaders/db_new.js +349 -0
- package/lib/routes/list/loaders/db_old.d.ts +44 -0
- package/lib/routes/list/loaders/db_old.js +340 -0
- package/package.json +1 -1
|
@@ -157,7 +157,7 @@ export declare class ActivityRideService extends IncyclistService {
|
|
|
157
157
|
protected getTotalElevation(): number;
|
|
158
158
|
protected update(): void;
|
|
159
159
|
protected createFreeRide(settings: FreeRideStartSettings): Route;
|
|
160
|
-
protected getMode(routeType: ActivityRouteType): "video" | "
|
|
160
|
+
protected getMode(routeType: ActivityRouteType): "video" | "free ride" | "follow route";
|
|
161
161
|
protected updateActivityTime(): void;
|
|
162
162
|
getRideProps(): any;
|
|
163
163
|
protected logActivityUpdateMessage(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const api_1 = __importDefault(require("../../base/api"));
|
|
16
|
+
const consts_1 = require("../../base/api/consts");
|
|
17
|
+
const api_2 = require("./api");
|
|
18
|
+
const service_1 = require("../service");
|
|
19
|
+
const utils_1 = require("../../../utils");
|
|
20
|
+
describe('RouteApiLoader', () => {
|
|
21
|
+
describe('load', () => {
|
|
22
|
+
test('e2e test - should only be executed manually', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
var _a;
|
|
24
|
+
const api = api_1.default.getInstance();
|
|
25
|
+
api['getBaseUrl'] = jest.fn().mockReturnValue(consts_1.DEFAULT_ROUTE_API);
|
|
26
|
+
const list = new service_1.RouteListService();
|
|
27
|
+
list.createPreview = jest.fn().mockResolvedValue(true);
|
|
28
|
+
const loader = new api_2.RoutesApiLoader();
|
|
29
|
+
const routes = [];
|
|
30
|
+
const run = () => new Promise(done => {
|
|
31
|
+
let added = 0;
|
|
32
|
+
let updated = 0;
|
|
33
|
+
const observer = loader.load();
|
|
34
|
+
observer.on('route.added', route => {
|
|
35
|
+
routes.push(route);
|
|
36
|
+
added++;
|
|
37
|
+
});
|
|
38
|
+
observer.on('route.updated', route => {
|
|
39
|
+
updated++;
|
|
40
|
+
});
|
|
41
|
+
observer.on('done', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
console.log('added:', added);
|
|
43
|
+
console.log('updated:', updated);
|
|
44
|
+
yield (0, utils_1.waitNextTick)();
|
|
45
|
+
done({ added, updated });
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
const run1 = yield run();
|
|
49
|
+
console.log(run1);
|
|
50
|
+
expect(routes.length).toBe(14);
|
|
51
|
+
expect(run1.updated).toBe(6);
|
|
52
|
+
const existing = Array.from(routes);
|
|
53
|
+
api['getRouteDescriptionFromDB'] = jest.fn((id) => existing.find(r => r.description.id === id));
|
|
54
|
+
const run2 = yield run();
|
|
55
|
+
expect(routes.length).toBe(14);
|
|
56
|
+
expect(run2.updated).toBe(0);
|
|
57
|
+
expect(run2.added).toBe(0);
|
|
58
|
+
const updateTarget = existing.find(r => { var _a; return (_a = r.description.version) !== null && _a !== void 0 ? _a : 0 > 1; });
|
|
59
|
+
if (updateTarget) {
|
|
60
|
+
const prevVersion = (_a = updateTarget.description.version) !== null && _a !== void 0 ? _a : 1;
|
|
61
|
+
updateTarget.description.version = prevVersion - 1;
|
|
62
|
+
const run3 = yield run();
|
|
63
|
+
expect(routes.length).toBe(14);
|
|
64
|
+
expect(run3.updated).toBe(1);
|
|
65
|
+
expect(run3.added).toBe(0);
|
|
66
|
+
}
|
|
67
|
+
}), 20000);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -39,6 +39,5 @@ export declare class RoutesDbLoader extends DBLoader<RouteInfoDBEntry> {
|
|
|
39
39
|
protected getRoutesRepo(): JsonRepository;
|
|
40
40
|
protected getDetailsRepo(route: Route): JsonRepository;
|
|
41
41
|
protected writeDetails(route: Route): Promise<void>;
|
|
42
|
-
protected
|
|
43
|
-
protected _deleteRoute(id: any): Promise<void>;
|
|
42
|
+
protected deleteRouteDetails(route: Route): Promise<void>;
|
|
44
43
|
}
|
|
@@ -46,6 +46,9 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
46
46
|
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
47
47
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
48
48
|
};
|
|
49
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
49
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
53
|
exports.RoutesDbLoader = void 0;
|
|
51
54
|
const api_1 = require("../../../api");
|
|
@@ -55,6 +58,7 @@ const LegacyDB_1 = require("./LegacyDB");
|
|
|
55
58
|
const DBLoader_1 = require("./DBLoader");
|
|
56
59
|
const utils_1 = require("../../../utils");
|
|
57
60
|
const route_1 = require("../../base/utils/route");
|
|
61
|
+
const clone_1 = __importDefault(require("../../../utils/clone"));
|
|
58
62
|
let RoutesDbLoader = (() => {
|
|
59
63
|
let _classDecorators = [types_1.Singleton];
|
|
60
64
|
let _classDescriptor;
|
|
@@ -74,15 +78,20 @@ let RoutesDbLoader = (() => {
|
|
|
74
78
|
return JSON.stringify(json);
|
|
75
79
|
}
|
|
76
80
|
catch (_a) { } };
|
|
77
|
-
|
|
81
|
+
const updatedDescr = this.buildRouteDBInfo(route.description);
|
|
78
82
|
const idx = this.routeDescriptions.findIndex(d => d.id === route.description.id);
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
let changed = false;
|
|
84
|
+
if (idx === -1) {
|
|
85
|
+
this.routeDescriptions.push((0, clone_1.default)(updatedDescr));
|
|
86
|
+
changed = true;
|
|
87
|
+
}
|
|
81
88
|
else {
|
|
82
|
-
prev = stringify(this.
|
|
83
|
-
|
|
89
|
+
const prev = stringify(this.routeDescriptions[idx]);
|
|
90
|
+
const updated = stringify(updatedDescr);
|
|
91
|
+
changed = (prev !== updated);
|
|
92
|
+
if (changed)
|
|
93
|
+
this.routeDescriptions[idx] = (0, clone_1.default)(updatedDescr);
|
|
84
94
|
}
|
|
85
|
-
const changed = !prev || stringify(this.buildRouteDBInfo(this.routeDescriptions[idx])) !== prev;
|
|
86
95
|
if (changed) {
|
|
87
96
|
this.isDirty = true;
|
|
88
97
|
this.write();
|
|
@@ -103,8 +112,8 @@ let RoutesDbLoader = (() => {
|
|
|
103
112
|
throw new Error('route not found');
|
|
104
113
|
this.routeDescriptions.splice(idx, 1);
|
|
105
114
|
this.isDirty = true;
|
|
106
|
-
this.
|
|
107
|
-
yield this.
|
|
115
|
+
yield this.writeRepo();
|
|
116
|
+
yield this.deleteRouteDetails(route);
|
|
108
117
|
});
|
|
109
118
|
}
|
|
110
119
|
getDescription(id) {
|
|
@@ -127,6 +136,7 @@ let RoutesDbLoader = (() => {
|
|
|
127
136
|
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
128
137
|
try {
|
|
129
138
|
yield this.routesRepo.write('db', this.routeDescriptions.map(this.buildRouteDBInfo.bind(this)));
|
|
139
|
+
this.isDirty = false;
|
|
130
140
|
}
|
|
131
141
|
catch (err) {
|
|
132
142
|
this.logger.logEvent({ message: 'could not safe repo', error: err.message });
|
|
@@ -302,29 +312,29 @@ let RoutesDbLoader = (() => {
|
|
|
302
312
|
process.nextTick(() => { delete this.routesSaveObserver[id]; });
|
|
303
313
|
});
|
|
304
314
|
}
|
|
305
|
-
|
|
315
|
+
deleteRouteDetails(route) {
|
|
306
316
|
return __awaiter(this, void 0, void 0, function* () {
|
|
307
|
-
|
|
317
|
+
const repo = this.getDetailsRepo(route);
|
|
318
|
+
if (!repo)
|
|
308
319
|
return;
|
|
320
|
+
const id = route.description.id;
|
|
309
321
|
if (this.routesSaveObserver[id])
|
|
310
|
-
|
|
311
|
-
|
|
322
|
+
yield this.routesSaveObserver[id].wait();
|
|
323
|
+
const _deleteRoute = (id) => __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
yield (0, utils_1.waitNextTick)();
|
|
325
|
+
try {
|
|
326
|
+
yield repo.delete(id);
|
|
327
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
328
|
+
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
this.routesSaveObserver[id] = new observer_1.PromiseObserver(_deleteRoute(id));
|
|
312
335
|
yield this.routesSaveObserver[id].start();
|
|
313
336
|
});
|
|
314
337
|
}
|
|
315
|
-
_deleteRoute(id) {
|
|
316
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
317
|
-
yield (0, utils_1.waitNextTick)();
|
|
318
|
-
try {
|
|
319
|
-
yield this.routesRepo.delete(id);
|
|
320
|
-
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
321
|
-
}
|
|
322
|
-
catch (err) {
|
|
323
|
-
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
324
|
-
throw err;
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
338
|
};
|
|
329
339
|
__setFunctionName(_classThis, "RoutesDbLoader");
|
|
330
340
|
(() => {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { JsonRepository } from "../../../api";
|
|
2
|
+
import { Observer, PromiseObserver } from "../../../base/types/observer";
|
|
3
|
+
import { Route } from "../../base/model/route";
|
|
4
|
+
import { RouteInfo } from "../../base/types";
|
|
5
|
+
import { RoutesLegacyDbLoader } from "./LegacyDB";
|
|
6
|
+
import { RouteInfoDBEntry } from "./types";
|
|
7
|
+
import { DBLoader } from "./DBLoader";
|
|
8
|
+
import { RouteApiDetail } from "../../base/api/types";
|
|
9
|
+
export declare class RoutesDbLoader extends DBLoader<RouteInfoDBEntry> {
|
|
10
|
+
protected loadObserver: Observer;
|
|
11
|
+
protected saveObserver: PromiseObserver<void>;
|
|
12
|
+
protected videosRepo: JsonRepository;
|
|
13
|
+
protected routesRepo: JsonRepository;
|
|
14
|
+
protected routeDescriptions: Array<RouteInfoDBEntry>;
|
|
15
|
+
protected tsLastWrite: number;
|
|
16
|
+
protected isDirty: boolean;
|
|
17
|
+
protected routesSaveObserver: {
|
|
18
|
+
[index: string]: PromiseObserver<void>;
|
|
19
|
+
};
|
|
20
|
+
constructor();
|
|
21
|
+
save(route: Route, enforcedWriteDetails?: boolean): Promise<void>;
|
|
22
|
+
delete(route: Route): Promise<void>;
|
|
23
|
+
getDescription(id: string): RouteInfo;
|
|
24
|
+
getDetails(id: string): Promise<RouteApiDetail>;
|
|
25
|
+
protected writeRepo(): Promise<void>;
|
|
26
|
+
protected write(): void;
|
|
27
|
+
protected getLegacyLoader(): RoutesLegacyDbLoader;
|
|
28
|
+
protected buildRouteInfo(descr: RouteInfoDBEntry): RouteInfo;
|
|
29
|
+
protected buildRouteDBInfo(descr: RouteInfo): RouteInfoDBEntry;
|
|
30
|
+
protected loadFromLegacy(): Promise<Array<RouteInfoDBEntry>>;
|
|
31
|
+
protected loadDescriptions(): Promise<Array<RouteInfoDBEntry>>;
|
|
32
|
+
protected removeDuplicates(routes: Array<RouteInfoDBEntry>): any[];
|
|
33
|
+
protected verifyImportDate(routes: Array<RouteInfoDBEntry>): void;
|
|
34
|
+
protected loadDetailRecord(target: Route | RouteInfo): Promise<RouteApiDetail>;
|
|
35
|
+
private validateDetails;
|
|
36
|
+
private validateDescription;
|
|
37
|
+
protected loadDetails(route: Route, alreadyAdded?: boolean): Promise<void>;
|
|
38
|
+
protected getVideoRepo(): JsonRepository;
|
|
39
|
+
protected getRoutesRepo(): JsonRepository;
|
|
40
|
+
protected getDetailsRepo(route: Route): JsonRepository;
|
|
41
|
+
protected writeDetails(route: Route): Promise<void>;
|
|
42
|
+
protected deleteRoute(id: string): Promise<PromiseObserver<void>>;
|
|
43
|
+
protected _deleteRoute(id: any): Promise<void>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.RoutesDbLoader = void 0;
|
|
54
|
+
const api_1 = require("../../../api");
|
|
55
|
+
const types_1 = require("../../../base/types");
|
|
56
|
+
const observer_1 = require("../../../base/types/observer");
|
|
57
|
+
const LegacyDB_1 = require("./LegacyDB");
|
|
58
|
+
const DBLoader_1 = require("./DBLoader");
|
|
59
|
+
const utils_1 = require("../../../utils");
|
|
60
|
+
const route_1 = require("../../base/utils/route");
|
|
61
|
+
const clone_1 = __importDefault(require("../../../utils/clone"));
|
|
62
|
+
let RoutesDbLoader = (() => {
|
|
63
|
+
let _classDecorators = [types_1.Singleton];
|
|
64
|
+
let _classDescriptor;
|
|
65
|
+
let _classExtraInitializers = [];
|
|
66
|
+
let _classThis;
|
|
67
|
+
let _classSuper = DBLoader_1.DBLoader;
|
|
68
|
+
var RoutesDbLoader = _classThis = class extends _classSuper {
|
|
69
|
+
constructor() {
|
|
70
|
+
super();
|
|
71
|
+
this.routesSaveObserver = {};
|
|
72
|
+
this.routeDescriptions = [];
|
|
73
|
+
this.isDirty = true;
|
|
74
|
+
}
|
|
75
|
+
save(route_2) {
|
|
76
|
+
return __awaiter(this, arguments, void 0, function* (route, enforcedWriteDetails = false) {
|
|
77
|
+
const stringify = (json) => { try {
|
|
78
|
+
return JSON.stringify(json);
|
|
79
|
+
}
|
|
80
|
+
catch (_a) { } };
|
|
81
|
+
const updatedDescr = this.buildRouteDBInfo(route.description);
|
|
82
|
+
const idx = this.routeDescriptions.findIndex(d => d.id === route.description.id);
|
|
83
|
+
let changed = false;
|
|
84
|
+
if (idx === -1) {
|
|
85
|
+
this.routeDescriptions.push((0, clone_1.default)(updatedDescr));
|
|
86
|
+
changed = true;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const prev = stringify(this.routeDescriptions[idx]);
|
|
90
|
+
const updated = stringify(updatedDescr);
|
|
91
|
+
changed = (prev !== updated);
|
|
92
|
+
if (changed)
|
|
93
|
+
this.routeDescriptions[idx] = (0, clone_1.default)(updatedDescr);
|
|
94
|
+
}
|
|
95
|
+
if (changed) {
|
|
96
|
+
this.isDirty = true;
|
|
97
|
+
this.write();
|
|
98
|
+
this.writeDetails(route);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const details = yield this.loadDetailRecord(route);
|
|
102
|
+
if (!details || enforcedWriteDetails)
|
|
103
|
+
this.writeDetails(route);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
delete(route) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
const id = route.description.id;
|
|
110
|
+
const idx = this.routeDescriptions.findIndex(d => d.id === id);
|
|
111
|
+
if (idx == -1)
|
|
112
|
+
throw new Error('route not found');
|
|
113
|
+
this.routeDescriptions.splice(idx, 1);
|
|
114
|
+
this.isDirty = true;
|
|
115
|
+
this.write();
|
|
116
|
+
yield this.deleteRoute(id);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
getDescription(id) {
|
|
120
|
+
const descr = this.routeDescriptions.find(d => d.id === id);
|
|
121
|
+
return descr;
|
|
122
|
+
}
|
|
123
|
+
getDetails(id) {
|
|
124
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
+
const descr = this.routeDescriptions.find(d => d.id === id);
|
|
126
|
+
if (!descr)
|
|
127
|
+
return;
|
|
128
|
+
const details = yield this.loadDetailRecord(descr);
|
|
129
|
+
return details;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
writeRepo() {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
if (this.saveObserver)
|
|
135
|
+
yield this.saveObserver.wait();
|
|
136
|
+
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
try {
|
|
138
|
+
yield this.routesRepo.write('db', this.routeDescriptions.map(this.buildRouteDBInfo.bind(this)));
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
this.logger.logEvent({ message: 'could not safe repo', error: err.message });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
this.saveObserver = new observer_1.PromiseObserver(save());
|
|
145
|
+
yield this.saveObserver.start();
|
|
146
|
+
process.nextTick(() => { delete this.saveObserver; });
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
write() {
|
|
150
|
+
if (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000)) {
|
|
151
|
+
this.isDirty = false;
|
|
152
|
+
this.tsLastWrite = Date.now();
|
|
153
|
+
this.writeRepo();
|
|
154
|
+
}
|
|
155
|
+
if (this.isDirty && Date.now() - this.tsLastWrite < 1000) {
|
|
156
|
+
setTimeout(() => { this.write(); }, this.tsLastWrite + 1000 - Date.now());
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
getLegacyLoader() {
|
|
160
|
+
return new LegacyDB_1.RoutesLegacyDbLoader();
|
|
161
|
+
}
|
|
162
|
+
buildRouteInfo(descr) {
|
|
163
|
+
return descr;
|
|
164
|
+
}
|
|
165
|
+
buildRouteDBInfo(descr) {
|
|
166
|
+
const data = Object.assign({}, descr);
|
|
167
|
+
delete data.points;
|
|
168
|
+
return data;
|
|
169
|
+
}
|
|
170
|
+
loadFromLegacy() {
|
|
171
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
return new Promise(done => {
|
|
173
|
+
const observer = this.getLegacyLoader().load();
|
|
174
|
+
const descriptions = [];
|
|
175
|
+
observer.on('route.added', (r) => { descriptions.push(r.description); });
|
|
176
|
+
observer.on('done', () => done(descriptions));
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
loadDescriptions() {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
const descriptions = yield this.getRoutesRepo().read('db');
|
|
183
|
+
if (descriptions) {
|
|
184
|
+
const routes = descriptions;
|
|
185
|
+
const cleaned = this.removeDuplicates(routes);
|
|
186
|
+
return cleaned;
|
|
187
|
+
}
|
|
188
|
+
const legacy = yield this.loadFromLegacy();
|
|
189
|
+
return legacy;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
removeDuplicates(routes) {
|
|
193
|
+
const ids = routes.map(r => r.legacyId || r.id);
|
|
194
|
+
const uniqueIds = ids.filter((d, pos) => ids.indexOf(d) === pos);
|
|
195
|
+
const cleaned = [];
|
|
196
|
+
uniqueIds.forEach(id => {
|
|
197
|
+
const routeWithLegacy = routes.find(r => r.legacyId === id);
|
|
198
|
+
const route = routeWithLegacy || routes.find(r => r.id === id);
|
|
199
|
+
if (route)
|
|
200
|
+
cleaned.push(route);
|
|
201
|
+
});
|
|
202
|
+
return cleaned;
|
|
203
|
+
}
|
|
204
|
+
verifyImportDate(routes) {
|
|
205
|
+
let changed = false;
|
|
206
|
+
routes.forEach(r => {
|
|
207
|
+
if (!r.tsImported) {
|
|
208
|
+
r.tsImported = Date.now();
|
|
209
|
+
changed = true;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
if (changed) {
|
|
213
|
+
this.isDirty = true;
|
|
214
|
+
this.write();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
loadDetailRecord(target) {
|
|
218
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
219
|
+
var _a;
|
|
220
|
+
const description = (target.description || target);
|
|
221
|
+
const repo = (description === null || description === void 0 ? void 0 : description.hasVideo) ? this.getVideosRepo() : this.getRoutesRepo();
|
|
222
|
+
let details;
|
|
223
|
+
try {
|
|
224
|
+
const id = description.legacyId || description.id;
|
|
225
|
+
details = (yield repo.read(id));
|
|
226
|
+
description.originalName = details.title;
|
|
227
|
+
if (description.hasVideo) {
|
|
228
|
+
description.segments = ((_a = details.video) === null || _a === void 0 ? void 0 : _a.selectableSegments) || (details === null || details === void 0 ? void 0 : details.selectableSegments);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
this.logger.logEvent({ message: 'could not load route details', id: (description === null || description === void 0 ? void 0 : description.legacyId) || (description === null || description === void 0 ? void 0 : description.id), title: description === null || description === void 0 ? void 0 : description.title, reason: err.message, stack: err.stack });
|
|
233
|
+
if (description.id && description.legacyId !== description.id) {
|
|
234
|
+
try {
|
|
235
|
+
details = (yield repo.read(description.id));
|
|
236
|
+
description.originalName = details.title;
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
this.logger.logEvent({ message: 'could not load route details', id: (description === null || description === void 0 ? void 0 : description.legacyId) || (description === null || description === void 0 ? void 0 : description.id), title: description === null || description === void 0 ? void 0 : description.title, reason: err.message, stack: err.stack });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (!details) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.validateDetails(details);
|
|
247
|
+
this.validateDescription(description, details);
|
|
248
|
+
return details;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
validateDetails(details) {
|
|
252
|
+
if (!details.points || !Array.isArray(details.points)) {
|
|
253
|
+
details.points = details.decoded;
|
|
254
|
+
delete details.decoded;
|
|
255
|
+
}
|
|
256
|
+
if (details.localizedTitle && typeof (details.localizedTitle) === 'string') {
|
|
257
|
+
details.localizedTitle = { en: details.localizedTitle };
|
|
258
|
+
}
|
|
259
|
+
(0, route_1.validateDistance)(details.points);
|
|
260
|
+
(0, route_1.updateSlopes)(details.points);
|
|
261
|
+
}
|
|
262
|
+
validateDescription(description, details) {
|
|
263
|
+
if (!description.elevation) {
|
|
264
|
+
description.elevation = (0, route_1.getTotalElevation)(details);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
loadDetails(route, alreadyAdded) {
|
|
268
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
const details = yield this.loadDetailRecord(route);
|
|
270
|
+
(0, route_1.addDetails)(route, details);
|
|
271
|
+
this.verifyRouteHash(route);
|
|
272
|
+
if (alreadyAdded)
|
|
273
|
+
this.emitRouteUpdate(route);
|
|
274
|
+
this.emitRouteAdded(route);
|
|
275
|
+
this.verifyCountry(route);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
getVideoRepo() {
|
|
279
|
+
if (!this.videosRepo)
|
|
280
|
+
this.videosRepo = api_1.JsonRepository.create('videos');
|
|
281
|
+
return this.videosRepo;
|
|
282
|
+
}
|
|
283
|
+
getRoutesRepo() {
|
|
284
|
+
if (!this.routesRepo)
|
|
285
|
+
this.routesRepo = api_1.JsonRepository.create('routes');
|
|
286
|
+
return this.routesRepo;
|
|
287
|
+
}
|
|
288
|
+
getDetailsRepo(route) {
|
|
289
|
+
var _a;
|
|
290
|
+
return ((_a = route === null || route === void 0 ? void 0 : route.description) === null || _a === void 0 ? void 0 : _a.hasVideo) ? this.getVideoRepo() : this.getRoutesRepo();
|
|
291
|
+
}
|
|
292
|
+
writeDetails(route) {
|
|
293
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
+
const repo = this.getDetailsRepo(route);
|
|
295
|
+
if (!repo) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const id = route.description.legacyId || route.description.id;
|
|
299
|
+
if (this.routesSaveObserver[id]) {
|
|
300
|
+
yield this.routesSaveObserver[id].wait();
|
|
301
|
+
}
|
|
302
|
+
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
303
|
+
try {
|
|
304
|
+
yield repo.write(id, route.details);
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
this.routesSaveObserver[id] = new observer_1.PromiseObserver(save());
|
|
310
|
+
yield this.routesSaveObserver[id].start();
|
|
311
|
+
process.nextTick(() => { delete this.routesSaveObserver[id]; });
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
deleteRoute(id) {
|
|
315
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
316
|
+
if (!this.routesRepo)
|
|
317
|
+
return;
|
|
318
|
+
if (this.routesSaveObserver[id])
|
|
319
|
+
return this.routesSaveObserver[id];
|
|
320
|
+
this.routesSaveObserver[id] = new observer_1.PromiseObserver(this._deleteRoute(id));
|
|
321
|
+
yield this.routesSaveObserver[id].start();
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
_deleteRoute(id) {
|
|
325
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
326
|
+
yield (0, utils_1.waitNextTick)();
|
|
327
|
+
try {
|
|
328
|
+
yield this.routesRepo.delete(id);
|
|
329
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
333
|
+
throw err;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
__setFunctionName(_classThis, "RoutesDbLoader");
|
|
339
|
+
(() => {
|
|
340
|
+
var _a;
|
|
341
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
|
|
342
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
343
|
+
RoutesDbLoader = _classThis = _classDescriptor.value;
|
|
344
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
345
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
346
|
+
})();
|
|
347
|
+
return RoutesDbLoader = _classThis;
|
|
348
|
+
})();
|
|
349
|
+
exports.RoutesDbLoader = RoutesDbLoader;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { JsonRepository } from "../../../api";
|
|
2
|
+
import { Observer, PromiseObserver } from "../../../base/types/observer";
|
|
3
|
+
import { Route } from "../../base/model/route";
|
|
4
|
+
import { RouteInfo } from "../../base/types";
|
|
5
|
+
import { RoutesLegacyDbLoader } from "./LegacyDB";
|
|
6
|
+
import { RouteInfoDBEntry } from "./types";
|
|
7
|
+
import { DBLoader } from "./DBLoader";
|
|
8
|
+
import { RouteApiDetail } from "../../base/api/types";
|
|
9
|
+
export declare class RoutesDbLoader extends DBLoader<RouteInfoDBEntry> {
|
|
10
|
+
protected loadObserver: Observer;
|
|
11
|
+
protected saveObserver: PromiseObserver<void>;
|
|
12
|
+
protected videosRepo: JsonRepository;
|
|
13
|
+
protected routesRepo: JsonRepository;
|
|
14
|
+
protected routeDescriptions: Array<RouteInfoDBEntry>;
|
|
15
|
+
protected tsLastWrite: number;
|
|
16
|
+
protected isDirty: boolean;
|
|
17
|
+
protected routesSaveObserver: {
|
|
18
|
+
[index: string]: PromiseObserver<void>;
|
|
19
|
+
};
|
|
20
|
+
constructor();
|
|
21
|
+
save(route: Route, enforcedWriteDetails?: boolean): Promise<void>;
|
|
22
|
+
delete(route: Route): Promise<void>;
|
|
23
|
+
getDescription(id: string): RouteInfo;
|
|
24
|
+
getDetails(id: string): Promise<RouteApiDetail>;
|
|
25
|
+
protected writeRepo(): Promise<void>;
|
|
26
|
+
protected write(): void;
|
|
27
|
+
protected getLegacyLoader(): RoutesLegacyDbLoader;
|
|
28
|
+
protected buildRouteInfo(descr: RouteInfoDBEntry): RouteInfo;
|
|
29
|
+
protected buildRouteDBInfo(descr: RouteInfo): RouteInfoDBEntry;
|
|
30
|
+
protected loadFromLegacy(): Promise<Array<RouteInfoDBEntry>>;
|
|
31
|
+
protected loadDescriptions(): Promise<Array<RouteInfoDBEntry>>;
|
|
32
|
+
protected removeDuplicates(routes: Array<RouteInfoDBEntry>): any[];
|
|
33
|
+
protected verifyImportDate(routes: Array<RouteInfoDBEntry>): void;
|
|
34
|
+
protected loadDetailRecord(target: Route | RouteInfo): Promise<RouteApiDetail>;
|
|
35
|
+
private validateDetails;
|
|
36
|
+
private validateDescription;
|
|
37
|
+
protected loadDetails(route: Route, alreadyAdded?: boolean): Promise<void>;
|
|
38
|
+
protected getVideoRepo(): JsonRepository;
|
|
39
|
+
protected getRoutesRepo(): JsonRepository;
|
|
40
|
+
protected getDetailsRepo(route: Route): JsonRepository;
|
|
41
|
+
protected writeDetails(route: Route): Promise<void>;
|
|
42
|
+
protected deleteRoute(id: string): Promise<PromiseObserver<void>>;
|
|
43
|
+
protected _deleteRoute(id: any): Promise<void>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
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.RoutesDbLoader = void 0;
|
|
51
|
+
const api_1 = require("../../../api");
|
|
52
|
+
const types_1 = require("../../../base/types");
|
|
53
|
+
const observer_1 = require("../../../base/types/observer");
|
|
54
|
+
const LegacyDB_1 = require("./LegacyDB");
|
|
55
|
+
const DBLoader_1 = require("./DBLoader");
|
|
56
|
+
const utils_1 = require("../../../utils");
|
|
57
|
+
const route_1 = require("../../base/utils/route");
|
|
58
|
+
let RoutesDbLoader = (() => {
|
|
59
|
+
let _classDecorators = [types_1.Singleton];
|
|
60
|
+
let _classDescriptor;
|
|
61
|
+
let _classExtraInitializers = [];
|
|
62
|
+
let _classThis;
|
|
63
|
+
let _classSuper = DBLoader_1.DBLoader;
|
|
64
|
+
var RoutesDbLoader = _classThis = class extends _classSuper {
|
|
65
|
+
constructor() {
|
|
66
|
+
super();
|
|
67
|
+
this.routesSaveObserver = {};
|
|
68
|
+
this.routeDescriptions = [];
|
|
69
|
+
this.isDirty = true;
|
|
70
|
+
}
|
|
71
|
+
save(route_2) {
|
|
72
|
+
return __awaiter(this, arguments, void 0, function* (route, enforcedWriteDetails = false) {
|
|
73
|
+
const stringify = (json) => { try {
|
|
74
|
+
return JSON.stringify(json);
|
|
75
|
+
}
|
|
76
|
+
catch (_a) { } };
|
|
77
|
+
let prev;
|
|
78
|
+
const idx = this.routeDescriptions.findIndex(d => d.id === route.description.id);
|
|
79
|
+
if (idx === -1)
|
|
80
|
+
this.routeDescriptions.push(route.description);
|
|
81
|
+
else {
|
|
82
|
+
prev = stringify(this.buildRouteDBInfo(this.routeDescriptions[idx]));
|
|
83
|
+
this.routeDescriptions[idx] = route.description;
|
|
84
|
+
}
|
|
85
|
+
const changed = !prev || stringify(this.buildRouteDBInfo(this.routeDescriptions[idx])) !== prev;
|
|
86
|
+
if (changed) {
|
|
87
|
+
this.isDirty = true;
|
|
88
|
+
this.write();
|
|
89
|
+
this.writeDetails(route);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const details = yield this.loadDetailRecord(route);
|
|
93
|
+
if (!details || enforcedWriteDetails)
|
|
94
|
+
this.writeDetails(route);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
delete(route) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
const id = route.description.id;
|
|
101
|
+
const idx = this.routeDescriptions.findIndex(d => d.id === id);
|
|
102
|
+
if (idx == -1)
|
|
103
|
+
throw new Error('route not found');
|
|
104
|
+
this.routeDescriptions.splice(idx, 1);
|
|
105
|
+
this.isDirty = true;
|
|
106
|
+
this.write();
|
|
107
|
+
yield this.deleteRoute(id);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
getDescription(id) {
|
|
111
|
+
const descr = this.routeDescriptions.find(d => d.id === id);
|
|
112
|
+
return descr;
|
|
113
|
+
}
|
|
114
|
+
getDetails(id) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
const descr = this.routeDescriptions.find(d => d.id === id);
|
|
117
|
+
if (!descr)
|
|
118
|
+
return;
|
|
119
|
+
const details = yield this.loadDetailRecord(descr);
|
|
120
|
+
return details;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
writeRepo() {
|
|
124
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
+
if (this.saveObserver)
|
|
126
|
+
yield this.saveObserver.wait();
|
|
127
|
+
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
try {
|
|
129
|
+
yield this.routesRepo.write('db', this.routeDescriptions.map(this.buildRouteDBInfo.bind(this)));
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
this.logger.logEvent({ message: 'could not safe repo', error: err.message });
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
this.saveObserver = new observer_1.PromiseObserver(save());
|
|
136
|
+
yield this.saveObserver.start();
|
|
137
|
+
process.nextTick(() => { delete this.saveObserver; });
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
write() {
|
|
141
|
+
if (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000)) {
|
|
142
|
+
this.isDirty = false;
|
|
143
|
+
this.tsLastWrite = Date.now();
|
|
144
|
+
this.writeRepo();
|
|
145
|
+
}
|
|
146
|
+
if (this.isDirty && Date.now() - this.tsLastWrite < 1000) {
|
|
147
|
+
setTimeout(() => { this.write(); }, this.tsLastWrite + 1000 - Date.now());
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
getLegacyLoader() {
|
|
151
|
+
return new LegacyDB_1.RoutesLegacyDbLoader();
|
|
152
|
+
}
|
|
153
|
+
buildRouteInfo(descr) {
|
|
154
|
+
return descr;
|
|
155
|
+
}
|
|
156
|
+
buildRouteDBInfo(descr) {
|
|
157
|
+
const data = Object.assign({}, descr);
|
|
158
|
+
delete data.points;
|
|
159
|
+
return data;
|
|
160
|
+
}
|
|
161
|
+
loadFromLegacy() {
|
|
162
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
163
|
+
return new Promise(done => {
|
|
164
|
+
const observer = this.getLegacyLoader().load();
|
|
165
|
+
const descriptions = [];
|
|
166
|
+
observer.on('route.added', (r) => { descriptions.push(r.description); });
|
|
167
|
+
observer.on('done', () => done(descriptions));
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
loadDescriptions() {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
const descriptions = yield this.getRoutesRepo().read('db');
|
|
174
|
+
if (descriptions) {
|
|
175
|
+
const routes = descriptions;
|
|
176
|
+
const cleaned = this.removeDuplicates(routes);
|
|
177
|
+
return cleaned;
|
|
178
|
+
}
|
|
179
|
+
const legacy = yield this.loadFromLegacy();
|
|
180
|
+
return legacy;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
removeDuplicates(routes) {
|
|
184
|
+
const ids = routes.map(r => r.legacyId || r.id);
|
|
185
|
+
const uniqueIds = ids.filter((d, pos) => ids.indexOf(d) === pos);
|
|
186
|
+
const cleaned = [];
|
|
187
|
+
uniqueIds.forEach(id => {
|
|
188
|
+
const routeWithLegacy = routes.find(r => r.legacyId === id);
|
|
189
|
+
const route = routeWithLegacy || routes.find(r => r.id === id);
|
|
190
|
+
if (route)
|
|
191
|
+
cleaned.push(route);
|
|
192
|
+
});
|
|
193
|
+
return cleaned;
|
|
194
|
+
}
|
|
195
|
+
verifyImportDate(routes) {
|
|
196
|
+
let changed = false;
|
|
197
|
+
routes.forEach(r => {
|
|
198
|
+
if (!r.tsImported) {
|
|
199
|
+
r.tsImported = Date.now();
|
|
200
|
+
changed = true;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
if (changed) {
|
|
204
|
+
this.isDirty = true;
|
|
205
|
+
this.write();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
loadDetailRecord(target) {
|
|
209
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
210
|
+
var _a;
|
|
211
|
+
const description = (target.description || target);
|
|
212
|
+
const repo = (description === null || description === void 0 ? void 0 : description.hasVideo) ? this.getVideosRepo() : this.getRoutesRepo();
|
|
213
|
+
let details;
|
|
214
|
+
try {
|
|
215
|
+
const id = description.legacyId || description.id;
|
|
216
|
+
details = (yield repo.read(id));
|
|
217
|
+
description.originalName = details.title;
|
|
218
|
+
if (description.hasVideo) {
|
|
219
|
+
description.segments = ((_a = details.video) === null || _a === void 0 ? void 0 : _a.selectableSegments) || (details === null || details === void 0 ? void 0 : details.selectableSegments);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
this.logger.logEvent({ message: 'could not load route details', id: (description === null || description === void 0 ? void 0 : description.legacyId) || (description === null || description === void 0 ? void 0 : description.id), title: description === null || description === void 0 ? void 0 : description.title, reason: err.message, stack: err.stack });
|
|
224
|
+
if (description.id && description.legacyId !== description.id) {
|
|
225
|
+
try {
|
|
226
|
+
details = (yield repo.read(description.id));
|
|
227
|
+
description.originalName = details.title;
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
this.logger.logEvent({ message: 'could not load route details', id: (description === null || description === void 0 ? void 0 : description.legacyId) || (description === null || description === void 0 ? void 0 : description.id), title: description === null || description === void 0 ? void 0 : description.title, reason: err.message, stack: err.stack });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!details) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.validateDetails(details);
|
|
238
|
+
this.validateDescription(description, details);
|
|
239
|
+
return details;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
validateDetails(details) {
|
|
243
|
+
if (!details.points || !Array.isArray(details.points)) {
|
|
244
|
+
details.points = details.decoded;
|
|
245
|
+
delete details.decoded;
|
|
246
|
+
}
|
|
247
|
+
if (details.localizedTitle && typeof (details.localizedTitle) === 'string') {
|
|
248
|
+
details.localizedTitle = { en: details.localizedTitle };
|
|
249
|
+
}
|
|
250
|
+
(0, route_1.validateDistance)(details.points);
|
|
251
|
+
(0, route_1.updateSlopes)(details.points);
|
|
252
|
+
}
|
|
253
|
+
validateDescription(description, details) {
|
|
254
|
+
if (!description.elevation) {
|
|
255
|
+
description.elevation = (0, route_1.getTotalElevation)(details);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
loadDetails(route, alreadyAdded) {
|
|
259
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
260
|
+
const details = yield this.loadDetailRecord(route);
|
|
261
|
+
(0, route_1.addDetails)(route, details);
|
|
262
|
+
this.verifyRouteHash(route);
|
|
263
|
+
if (alreadyAdded)
|
|
264
|
+
this.emitRouteUpdate(route);
|
|
265
|
+
this.emitRouteAdded(route);
|
|
266
|
+
this.verifyCountry(route);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
getVideoRepo() {
|
|
270
|
+
if (!this.videosRepo)
|
|
271
|
+
this.videosRepo = api_1.JsonRepository.create('videos');
|
|
272
|
+
return this.videosRepo;
|
|
273
|
+
}
|
|
274
|
+
getRoutesRepo() {
|
|
275
|
+
if (!this.routesRepo)
|
|
276
|
+
this.routesRepo = api_1.JsonRepository.create('routes');
|
|
277
|
+
return this.routesRepo;
|
|
278
|
+
}
|
|
279
|
+
getDetailsRepo(route) {
|
|
280
|
+
var _a;
|
|
281
|
+
return ((_a = route === null || route === void 0 ? void 0 : route.description) === null || _a === void 0 ? void 0 : _a.hasVideo) ? this.getVideoRepo() : this.getRoutesRepo();
|
|
282
|
+
}
|
|
283
|
+
writeDetails(route) {
|
|
284
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
285
|
+
const repo = this.getDetailsRepo(route);
|
|
286
|
+
if (!repo) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const id = route.description.legacyId || route.description.id;
|
|
290
|
+
if (this.routesSaveObserver[id]) {
|
|
291
|
+
yield this.routesSaveObserver[id].wait();
|
|
292
|
+
}
|
|
293
|
+
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
294
|
+
try {
|
|
295
|
+
yield repo.write(id, route.details);
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
this.routesSaveObserver[id] = new observer_1.PromiseObserver(save());
|
|
301
|
+
yield this.routesSaveObserver[id].start();
|
|
302
|
+
process.nextTick(() => { delete this.routesSaveObserver[id]; });
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
deleteRoute(id) {
|
|
306
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
307
|
+
if (!this.routesRepo)
|
|
308
|
+
return;
|
|
309
|
+
if (this.routesSaveObserver[id])
|
|
310
|
+
return this.routesSaveObserver[id];
|
|
311
|
+
this.routesSaveObserver[id] = new observer_1.PromiseObserver(this._deleteRoute(id));
|
|
312
|
+
yield this.routesSaveObserver[id].start();
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
_deleteRoute(id) {
|
|
316
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
317
|
+
yield (0, utils_1.waitNextTick)();
|
|
318
|
+
try {
|
|
319
|
+
yield this.routesRepo.delete(id);
|
|
320
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
(0, utils_1.waitNextTick)().then(() => { delete this.routesSaveObserver[id]; });
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
__setFunctionName(_classThis, "RoutesDbLoader");
|
|
330
|
+
(() => {
|
|
331
|
+
var _a;
|
|
332
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
|
|
333
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
334
|
+
RoutesDbLoader = _classThis = _classDescriptor.value;
|
|
335
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
336
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
337
|
+
})();
|
|
338
|
+
return RoutesDbLoader = _classThis;
|
|
339
|
+
})();
|
|
340
|
+
exports.RoutesDbLoader = RoutesDbLoader;
|