bruce-models 2.1.0 → 2.1.2

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.
@@ -3140,259 +3140,125 @@
3140
3140
  });
3141
3141
  });
3142
3142
 
3143
- (function (ObjectUtils) {
3144
- /**
3145
- * Generates a Bruce compatible UID.
3146
- * @returns
3147
- */
3148
- function UId() {
3149
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
3150
- const r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
3151
- return v.toString(16);
3152
- });
3153
- }
3154
- ObjectUtils.UId = UId;
3155
- })(exports.ObjectUtils || (exports.ObjectUtils = {}));
3156
-
3157
- class CacheDictionary {
3143
+ const CACHE_VERSION_PREFIX = "v2_";
3144
+ class CacheUtil {
3158
3145
  constructor(id) {
3159
- this.memory = Object.create(null);
3160
- if (!id) {
3161
- id = "BRUCE_UI_MODELS_CACHE_DICT_" + exports.ObjectUtils.UId();
3162
- }
3163
- this.id = id;
3164
3146
  this.store = localforage.createInstance({
3165
- name: id
3166
- });
3167
- }
3168
- get Id() {
3169
- return this.id;
3170
- }
3171
- GetItems() {
3172
- return __awaiter(this, void 0, void 0, function* () {
3173
- if (this.items == null) {
3174
- const raw = yield this.store.getItem(this.id);
3175
- if (raw == null) {
3176
- this.items = [];
3177
- }
3178
- else {
3179
- // Check if any are expired.
3180
- // We can clean this every first time we load.
3181
- const now = new Date().getTime();
3182
- for (const item of raw) {
3183
- if (item.duration > -1 && (now - item.created) / 1000 > item.duration) {
3184
- if (item.inMemory) {
3185
- this.memory[item.key] = null;
3186
- delete this.memory[item.key];
3187
- }
3188
- else {
3189
- yield this.store.removeItem(item.key);
3190
- }
3191
- }
3192
- }
3193
- this.items = raw;
3194
- }
3195
- }
3196
- return this.items;
3197
- });
3198
- }
3199
- GetKeys() {
3200
- return __awaiter(this, void 0, void 0, function* () {
3201
- return (yield this.GetItems()).map(x => "" + x.key);
3147
+ name: CACHE_VERSION_PREFIX + id,
3202
3148
  });
3149
+ this.inMemoryPromises = {};
3150
+ this.keyVersions = {};
3203
3151
  }
3204
- Set(key, value, duration) {
3152
+ Set(key, value, duration = 300000) {
3205
3153
  return __awaiter(this, void 0, void 0, function* () {
3206
- key = "" + key;
3207
- const items = yield this.GetItems();
3208
- const itemIndex = items.findIndex(x => x.key == key);
3209
- if (itemIndex > -1) {
3210
- const item = items[itemIndex];
3211
- if (item.inMemory) {
3212
- this.memory[item.key] = null;
3213
- delete this.memory[item.key];
3214
- }
3215
- else {
3216
- yield this.store.removeItem(item.key);
3217
- }
3218
- items.splice(itemIndex, 1);
3219
- }
3220
- const item = {
3221
- key: key,
3222
- duration: duration,
3223
- created: new Date().getTime(),
3224
- inMemory: false
3225
- };
3226
- // Short duration, keep in memory.
3227
- if (duration < 60) {
3228
- item.inMemory = true;
3229
- this.memory[item.key] = value;
3230
- }
3231
- // Let's resolve and store the value in local-storage.
3232
- // If resolution crashes then we'll keep retaining that in memory.
3233
- else if (value instanceof Promise) {
3234
- value.then((x) => __awaiter(this, void 0, void 0, function* () {
3235
- try {
3236
- const items = yield this.GetItems();
3237
- const item = items.find(x => x.key == key);
3238
- if (!item) {
3239
- console.log("Item was removed from cache before promise resolved.", key, items);
3240
- return;
3241
- }
3242
- try {
3243
- yield this.store.setItem(item.key, x);
3244
- item.inMemory = false;
3245
- this.memory[item.key] = null;
3246
- delete this.memory[item.key];
3247
- yield this.store.setItem(this.id, items);
3248
- }
3249
- catch (e) {
3250
- console.warn(e);
3251
- }
3154
+ if (value instanceof Promise) {
3155
+ this.inMemoryPromises[key] = value;
3156
+ const currentVersion = (this.keyVersions[key] = (this.keyVersions[key] || 0) + 1);
3157
+ value
3158
+ .then((resolvedValue) => {
3159
+ if (this.keyVersions[key] === currentVersion) {
3160
+ this.Set(key, resolvedValue, duration);
3252
3161
  }
3253
- catch (e) {
3254
- console.warn(e);
3162
+ })
3163
+ .catch((error) => {
3164
+ if (this.keyVersions[key] === currentVersion) {
3165
+ this.Set(key, error, duration);
3255
3166
  }
3256
- }));
3257
- item.inMemory = true;
3258
- this.memory[item.key] = value;
3167
+ })
3168
+ .finally(() => {
3169
+ delete this.inMemoryPromises[key];
3170
+ });
3259
3171
  }
3260
- if (!item.inMemory) {
3261
- try {
3262
- yield this.store.setItem(item.key, value);
3263
- }
3264
- catch (e) {
3265
- item.inMemory = true;
3266
- this.memory[item.key] = value;
3267
- console.warn(e);
3268
- }
3172
+ else {
3173
+ const item = {
3174
+ value,
3175
+ expiry: Date.now() + duration,
3176
+ };
3177
+ yield this.store.setItem(key, item);
3269
3178
  }
3270
- items.push(item);
3271
- yield this.store.setItem(this.id, items);
3272
- this.items = items;
3273
3179
  });
3274
3180
  }
3275
- Remove(key) {
3181
+ Get(key) {
3276
3182
  return __awaiter(this, void 0, void 0, function* () {
3277
- key = "" + key;
3278
- const items = yield this.GetItems();
3279
- const index = items.findIndex(x => x.key == key);
3280
- if (index >= 0) {
3281
- const item = items[index];
3282
- if (item.inMemory) {
3283
- this.memory[item.key] = null;
3284
- delete this.memory[item.key];
3285
- }
3286
- else {
3287
- this.store.removeItem(item.key);
3288
- }
3289
- items.splice(index, 1);
3290
- this.store.setItem(this.id, items);
3183
+ if (this.inMemoryPromises[key]) {
3184
+ return this.inMemoryPromises[key];
3291
3185
  }
3292
- this.items = items;
3293
- });
3294
- }
3295
- Clear() {
3296
- return __awaiter(this, void 0, void 0, function* () {
3297
- const items = yield this.GetItems();
3298
- for (const item of items) {
3299
- if (item.inMemory) {
3300
- this.store.removeItem(item.key);
3301
- }
3186
+ const item = (yield this.store.getItem(key));
3187
+ if (!item) {
3188
+ return null;
3302
3189
  }
3303
- this.store.setItem(this.id, []);
3304
- this.items = [];
3305
- this.memory = Object.create(null);
3190
+ if (Date.now() > item.expiry) {
3191
+ yield this.store.removeItem(key);
3192
+ return null;
3193
+ }
3194
+ return item.value;
3306
3195
  });
3307
3196
  }
3308
- GetData(key) {
3197
+ ClearCache(pattern, mode = "equals") {
3309
3198
  return __awaiter(this, void 0, void 0, function* () {
3310
- key = "" + key;
3311
- const item = (yield this.GetItems()).find(x => x.key == key);
3312
- const isExpired = item == null || item.duration > -1 && (new Date().getTime() - item.created) / 1000 > item.duration;
3313
- if (isExpired) {
3314
- this.Remove(key);
3315
- return null;
3199
+ const keys = yield this.store.keys();
3200
+ const checkFuncs = {
3201
+ equals: (key) => key === pattern,
3202
+ contains: (key) => key.includes(pattern),
3203
+ startswith: (key) => key.startsWith(pattern),
3204
+ };
3205
+ const check = checkFuncs[mode];
3206
+ if (!check) {
3207
+ throw new Error("Invalid mode");
3316
3208
  }
3317
- if (item.inMemory) {
3318
- return this.memory[item.key];
3209
+ for (const key of keys) {
3210
+ if (check(key)) {
3211
+ yield this.store.removeItem(key);
3212
+ }
3319
3213
  }
3320
- const raw = yield this.store.getItem(item.key);
3321
- if (raw == null) {
3322
- return null;
3214
+ for (const key in this.inMemoryPromises) {
3215
+ if (check(key)) {
3216
+ delete this.inMemoryPromises[key];
3217
+ this.keyVersions[key]++;
3218
+ }
3323
3219
  }
3324
- return raw;
3325
3220
  });
3326
3221
  }
3327
3222
  }
3328
3223
  class CacheControl {
3329
3224
  constructor(id) {
3330
3225
  this.Disabled = false;
3331
- this.data = new CacheDictionary(id);
3226
+ this.data = new CacheUtil(id);
3332
3227
  }
3333
3228
  /**
3334
3229
  * @param id
3335
3230
  * @param data
3336
3231
  * @param duration seconds to keep the data in cache. -1 for infinite.
3337
3232
  */
3338
- Set(id, data, duration = -1) {
3233
+ Set(id, data, duration = 300) {
3339
3234
  return __awaiter(this, void 0, void 0, function* () {
3340
- return this.data.Set(id, data, duration);
3235
+ const durationMs = duration === -1 ? undefined : duration * 1000;
3236
+ return this.data.Set(String(id), data, durationMs);
3341
3237
  });
3342
3238
  }
3343
3239
  Get(id) {
3344
3240
  return __awaiter(this, void 0, void 0, function* () {
3345
- return this.data.GetData(id);
3241
+ return (yield this.data.Get(String(id)));
3346
3242
  });
3347
3243
  }
3348
3244
  Clear() {
3349
3245
  return __awaiter(this, void 0, void 0, function* () {
3350
- return this.data.Clear();
3246
+ return this.data.ClearCache("");
3351
3247
  });
3352
3248
  }
3353
3249
  Remove(id) {
3354
3250
  return __awaiter(this, void 0, void 0, function* () {
3355
- return this.data.Remove(id);
3251
+ return this.data.ClearCache(String(id), "equals");
3356
3252
  });
3357
3253
  }
3358
3254
  RemoveByStartsWith(text) {
3359
3255
  return __awaiter(this, void 0, void 0, function* () {
3360
- const items = [...(yield this.data.GetItems())];
3361
- for (const item of items) {
3362
- if (item.key.startsWith(text)) {
3363
- yield this.data.Remove(item.key);
3364
- }
3365
- }
3256
+ return this.data.ClearCache(text, "startswith");
3366
3257
  });
3367
3258
  }
3368
3259
  RemoveByContains(text) {
3369
3260
  return __awaiter(this, void 0, void 0, function* () {
3370
- const items = [...(yield this.data.GetItems())];
3371
- for (const item of items) {
3372
- if (item.key.includes(text)) {
3373
- yield this.data.Remove(item.key);
3374
- }
3375
- }
3376
- });
3377
- }
3378
- GetKeys() {
3379
- return __awaiter(this, void 0, void 0, function* () {
3380
- if (this.Disabled) {
3381
- return [];
3382
- }
3383
- const items = yield this.data.GetItems();
3384
- return items.map(x => x.key);
3385
- });
3386
- }
3387
- GetValues() {
3388
- return __awaiter(this, void 0, void 0, function* () {
3389
- if (this.Disabled) {
3390
- return [];
3391
- }
3392
- const items = yield this.data.GetItems();
3393
- const keys = items.map(x => x.key);
3394
- const values = yield Promise.all(keys.map(key => this.data.GetData(key)));
3395
- return values.filter(x => x != null);
3261
+ return this.data.ClearCache(text, "contains");
3396
3262
  });
3397
3263
  }
3398
3264
  }
@@ -4636,6 +4502,20 @@
4636
4502
  Color.ColorFromStr = ColorFromStr;
4637
4503
  })(exports.Color || (exports.Color = {}));
4638
4504
 
4505
+ (function (ObjectUtils) {
4506
+ /**
4507
+ * Generates a Bruce compatible UID.
4508
+ * @returns
4509
+ */
4510
+ function UId() {
4511
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
4512
+ const r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
4513
+ return v.toString(16);
4514
+ });
4515
+ }
4516
+ ObjectUtils.UId = UId;
4517
+ })(exports.ObjectUtils || (exports.ObjectUtils = {}));
4518
+
4639
4519
  /**
4640
4520
  * Utility to help with parsing and wrapping Bruce paths.
4641
4521
  */
@@ -7106,6 +6986,7 @@
7106
6986
  this.IsFetched = null;
7107
6987
  this.FetchPageIndex = 0;
7108
6988
  this.Boundaries = null;
6989
+ this.Fetching = false;
7109
6990
  }
7110
6991
  GetBounds() {
7111
6992
  // Entity data works in -180 to 180 range.
@@ -7132,93 +7013,47 @@
7132
7013
  class Grid {
7133
7014
  constructor() {
7134
7015
  this.cells = {};
7135
- this.patches = [];
7136
7016
  }
7137
7017
  GetCellsForView(viewRect) {
7018
+ const cells = [];
7019
+ const minLat = viewRect.south;
7020
+ const minLon = viewRect.west;
7021
+ const maxLat = viewRect.north;
7022
+ const maxLon = viewRect.east;
7138
7023
  const MAX_CELLS = 150;
7139
- const { south: minLat, west: minLon, north: maxLat, east: maxLon } = viewRect;
7140
7024
  const cellDegreeSize = getCellSizeFromHeight(viewRect.alt);
7141
- const [curMinLon, curMinLat] = [minLon, minLat].map((v) => floorValueToCellSize(cellDegreeSize, v));
7142
- const [width, height] = [maxLon - curMinLon, maxLat - curMinLat].map((v) => v / cellDegreeSize);
7143
- const ids = [];
7144
- const cells = [];
7145
- let max = [curMinLon, curMinLat];
7146
- const intersections = this.intersections(viewRect);
7147
- const addCell = (x, y) => {
7148
- const lon1 = x * cellDegreeSize + curMinLon;
7149
- const lat1 = y * cellDegreeSize + curMinLat;
7150
- const lon2 = lon1 + cellDegreeSize;
7151
- const lat2 = lat1 + cellDegreeSize;
7152
- const [id, cell] = getOrCreateCell(this.cells, cellDegreeSize, lon1, lon2, lat1, lat2);
7153
- /*
7154
- {
7155
- const cell_bounds = { south: lat1, west: lon1, north: lat2, east: lon2 };
7156
- const subcells = [];
7157
- for (const id of intersections) {
7158
- const c = this.cells[id].GetBounds();
7159
- if (contains(c, cell_bounds)) {
7160
- cell.Fetched = true;
7161
- return;
7162
- }
7163
- if (intersects(c, cell_bounds)) {
7164
- const cropped = crop(c, cell.GetBounds());
7165
- subcells.push(cropped);
7166
- }
7167
- }
7168
- let filled = 0;
7169
- while (subcells.length > 0) {
7170
- const c = subcells.pop();
7171
- filled += area(c);
7172
- for (const s of subcells) {
7173
- filled -= intersection(s, c);
7174
- }
7175
- }
7176
- if (filled + Number.EPSILON * 2 > area(cell.GetBounds())) {
7177
- cell.Fetched = true;
7178
- return;
7179
- }
7180
-
7181
- let [x2, y2] = max;
7182
- x2 = Math.max(x2, lon2);
7183
- y2 = Math.max(y2, lat2);
7184
- max = [x2, y2];
7185
- }
7186
- */
7187
- ids.push(id);
7188
- cells.push(cell);
7189
- cells[id] = cell;
7190
- };
7025
+ const curMinLon = floorValueToCellSize(cellDegreeSize, minLon);
7026
+ const curMinLat = floorValueToCellSize(cellDegreeSize, minLat);
7027
+ const width = (maxLon - curMinLon) / cellDegreeSize;
7028
+ const height = (maxLat - curMinLat) / cellDegreeSize;
7029
+ const centerX = (minLon + maxLon) / 2;
7030
+ const centerY = (minLat + maxLat) / 2;
7191
7031
  for (let x = 0; x < width; x++) {
7192
7032
  for (let y = 0; y < height; y++) {
7193
- addCell(x, y);
7194
- if (cells.length >= MAX_CELLS) {
7033
+ const lon = x * cellDegreeSize + curMinLon;
7034
+ const lat = y * cellDegreeSize + curMinLat;
7035
+ const [id, cell] = getOrCreateCell(this.cells, cellDegreeSize, lon, lon + cellDegreeSize, lat, lat + cellDegreeSize);
7036
+ cells.push(cell);
7037
+ if (cells.length > MAX_CELLS) {
7195
7038
  break;
7196
7039
  }
7197
7040
  }
7198
7041
  }
7199
- const [x2, y2] = max;
7200
- if (x2 != curMinLon && y2 != curMinLat) {
7201
- this.patches.push([{ west: curMinLon, east: x2, south: curMinLat, north: y2 }, ids]);
7202
- }
7042
+ // Sort cells so that the ones closest to the center are first
7043
+ cells.sort((a, b) => {
7044
+ const aCenterX = (a.Boundaries.minLongitude + a.Boundaries.maxLongitude) / 2;
7045
+ const aCenterY = (a.Boundaries.minLatitude + a.Boundaries.maxLatitude) / 2;
7046
+ const bCenterX = (b.Boundaries.minLongitude + b.Boundaries.maxLongitude) / 2;
7047
+ const bCenterY = (b.Boundaries.minLatitude + b.Boundaries.maxLatitude) / 2;
7048
+ const aDist = Math.sqrt(Math.pow(aCenterX - centerX, 2) + Math.pow(aCenterY - centerY, 2));
7049
+ const bDist = Math.sqrt(Math.pow(bCenterX - centerX, 2) + Math.pow(bCenterY - centerY, 2));
7050
+ return aDist - bDist;
7051
+ });
7203
7052
  return cells;
7204
7053
  }
7205
- intersections(withRect) {
7206
- return this.patches
7207
- .filter(([rect, _]) => intersects(rect, withRect))
7208
- .map(([_, ids]) => ids)
7209
- .reduce((all, ids) => {
7210
- all.push(...ids);
7211
- return all;
7212
- }, []);
7213
- }
7214
7054
  }
7215
7055
  EntityGlobe.Grid = Grid;
7216
7056
  })(exports.EntityGlobe || (exports.EntityGlobe = {}));
7217
- function intersects(l, r) {
7218
- const { west: w, south: s, north: n, east: e } = l;
7219
- const { west: wr, south: sr, north: nr, east: er } = r;
7220
- return !(e <= wr || w >= er || n <= sr || s >= nr);
7221
- }
7222
7057
  function floorValueToCellSize(size, value) {
7223
7058
  return Math.floor(value / size) * size;
7224
7059
  }
@@ -7452,6 +7287,7 @@
7452
7287
  let retryDelay = 0;
7453
7288
  let prevFirstId = "";
7454
7289
  let prevLastId = "";
7290
+ let prevTicks = 0;
7455
7291
  while ((!this.viewCenter || !this.viewRect) && this.getterLoopId == loopId) {
7456
7292
  yield delay(RETRY_DELAY_INCREMENT);
7457
7293
  }
@@ -7481,8 +7317,12 @@
7481
7317
  }
7482
7318
  const curCell = cells[curCellIndex];
7483
7319
  if (curCell.IsFetched()) {
7320
+ curCell.Fetching = false;
7484
7321
  curCellIndex += 1;
7485
- if (!cells[curCellIndex]) {
7322
+ if (cells[curCellIndex]) {
7323
+ cells[curCellIndex].Fetching = true;
7324
+ }
7325
+ else {
7486
7326
  curCellIndex = null;
7487
7327
  }
7488
7328
  (_b = this.onScanUpdate) === null || _b === void 0 ? void 0 : _b.Trigger(cells);
@@ -7522,6 +7362,7 @@
7522
7362
  // Only mark as fetched when ALL pages are done.
7523
7363
  if (entities.length <= 0) {
7524
7364
  curCell.Fetched = true;
7365
+ curCell.Fetching = false;
7525
7366
  (_d = this.onScanUpdate) === null || _d === void 0 ? void 0 : _d.Trigger(cells);
7526
7367
  continue;
7527
7368
  }
@@ -7530,11 +7371,15 @@
7530
7371
  const first = (_f = (_e = entities[0]) === null || _e === void 0 ? void 0 : _e.Bruce) === null || _f === void 0 ? void 0 : _f.ID;
7531
7372
  const last = (_h = (_g = entities[entities.length - 1]) === null || _g === void 0 ? void 0 : _g.Bruce) === null || _h === void 0 ? void 0 : _h.ID;
7532
7373
  if (prevFirstId == first && prevLastId == last) {
7533
- break;
7374
+ prevTicks += 1;
7375
+ if (prevTicks > 3) {
7376
+ break;
7377
+ }
7534
7378
  }
7535
7379
  else {
7536
7380
  prevFirstId = first;
7537
7381
  prevLastId = last;
7382
+ prevTicks = 0;
7538
7383
  }
7539
7384
  }
7540
7385
  curCell.FetchPageIndex++;
@@ -7543,7 +7388,7 @@
7543
7388
  retryDelay = 0;
7544
7389
  }
7545
7390
  catch (e) {
7546
- console.log(e);
7391
+ console.error(e);
7547
7392
  // Request failed so let's add a delay and try again soon.
7548
7393
  retryDelay += RETRY_DELAY_INCREMENT;
7549
7394
  retryAttempts -= 1;