From 66c5007fc219615516361d1c69a55892fee5a503 Mon Sep 17 00:00:00 2001 From: Milos Brzakovic <78906108+mbrzakovic@users.noreply.github.com> Date: Wed, 25 May 2022 18:49:35 +0200 Subject: [PATCH] Update bing imagery key and api urls. Interval limiting for tiles vintage (#9133) update bing imagery key, template, api url BasicMetadata for vintage handled 429 in getMetadata --- CHANGELOG.md | 2 + modules/renderer/background_source.js | 60 +++++++++++++++------------ modules/util/IntervalTasksQueue.js | 35 ++++++++++++++++ 3 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 modules/util/IntervalTasksQueue.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d55cd53c..420907854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ _Breaking developer changes, which may affect downstream projects or sites that * Allow searching presets by their tag (`key=value`) ([#8869]) #### Other * Redact more API tokens from custom imagery sources in changeset metadata tags ([#8976], thanks [@k-yle]) +* New Bing imagery API key and limit tiles vintage API requests ([#9133], thanks [@mbrzakovic]) #### :hammer: Development * Switch build system to [esbuild](https://esbuild.github.io/) for much faster builds ([#8774], thanks [@mbrzakovic] and [@bhousel]) * Upgrade some dependencies: maki to `v7.1`, `fontawesome` to `v6.1`, `d3` to `v7.3`, `node-diff` to `v3.1`, `mocha` to `v9.2`, `svg-sprite` to `v1.5.4`, `marked` to `v4.0` @@ -86,6 +87,7 @@ _Breaking developer changes, which may affect downstream projects or sites that [#9102]: https://github.com/openstreetmap/iD/issues/9102 [#9118]: https://github.com/openstreetmap/iD/issues/9118 [#9124]: https://github.com/openstreetmap/iD/pull/9124 +[#9133]: https://github.com/openstreetmap/iD/pull/9133 [@wcedmisten]: https://github.com/wcedmisten diff --git a/modules/renderer/background_source.js b/modules/renderer/background_source.js index 770dcc60d..b8d070cdb 100644 --- a/modules/renderer/background_source.js +++ b/modules/renderer/background_source.js @@ -6,7 +6,7 @@ import { t, localizer } from '../core/localizer'; import { geoExtent, geoSphericalDistance } from '../geo'; import { utilQsString, utilStringQs } from '../util'; import { utilAesDecrypt } from '../util/aes'; - +import { IntervalTasksQueue } from '../util/IntervalTasksQueue'; var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2; @@ -265,12 +265,10 @@ rendererBackgroundSource.Bing = function(data, dispatch) { // https://docs.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles //fallback url template - data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&n=z'; + data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=1&pr=odbl&n=z'; var bing = rendererBackgroundSource(data); - //var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc - var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD - + var key = utilAesDecrypt('5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0'); /* missing tile image strictness param (n=) • n=f -> (Fail) returns a 404 @@ -279,10 +277,12 @@ rendererBackgroundSource.Bing = function(data, dispatch) { */ const strictParam = 'n'; - var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&uriScheme=https&key=' + key; + var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=' + key; var cache = {}; var inflight = {}; var providers = []; + var taskQueue = new IntervalTasksQueue(250); + var metadataLastZoom = -1; d3_json(url) .then(function(json) { @@ -337,7 +337,7 @@ rendererBackgroundSource.Bing = function(data, dispatch) { var tileID = tileCoord.slice(0, 3).join('/'); var zoom = Math.min(tileCoord[2], 21); var centerPoint = center[1] + ',' + center[0]; // lat,lng - var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + + var url = 'https://dev.virtualearth.net/REST/v1/Imagery/BasicMetadata/AerialOSM/' + centerPoint + '?zl=' + zoom + '&key=' + key; if (inflight[tileID]) return; @@ -350,26 +350,34 @@ rendererBackgroundSource.Bing = function(data, dispatch) { } inflight[tileID] = true; - d3_json(url) - .then(function(result) { - delete inflight[tileID]; - if (!result) { - throw new Error('Unknown Error'); - } - var vintage = { - start: localeDateString(result.resourceSets[0].resources[0].vintageStart), - end: localeDateString(result.resourceSets[0].resources[0].vintageEnd) - }; - vintage.range = vintageRange(vintage); - var metadata = { vintage: vintage }; - cache[tileID].metadata = metadata; - if (callback) callback(null, metadata); - }) - .catch(function(err) { - delete inflight[tileID]; - if (callback) callback(err.message); - }); + if (metadataLastZoom !== tileCoord[2]){ + metadataLastZoom = tileCoord[2]; + taskQueue.clear(); + } + + taskQueue.enqueue(() => { + d3_json(url) + .then(function (result) { + delete inflight[tileID]; + if (!result) { + throw new Error('Unknown Error'); + } + var vintage = { + start: localeDateString(result.resourceSets[0].resources[0].vintageStart), + end: localeDateString(result.resourceSets[0].resources[0].vintageEnd) + }; + vintage.range = vintageRange(vintage); + + var metadata = { vintage: vintage }; + cache[tileID].metadata = metadata; + if (callback) callback(null, metadata); + }) + .catch(function (err) { + delete inflight[tileID]; + if (callback) callback(err.message); + }); + }); }; diff --git a/modules/util/IntervalTasksQueue.js b/modules/util/IntervalTasksQueue.js new file mode 100644 index 000000000..e823409ea --- /dev/null +++ b/modules/util/IntervalTasksQueue.js @@ -0,0 +1,35 @@ +/** + * IntervalTasksQueue + * Enabled task execution under interval limit + */ +export class IntervalTasksQueue { + + /** + * Interval in milliseconds inside which only 1 task can execute. + * e.g. if interval is 200ms, and 5 async tasks are unqueued, + * they will complete in ~1s if not cleared + * @param {number} intervalInMs + */ + constructor(intervalInMs) { + this.intervalInMs = intervalInMs; + this.pendingHandles = []; + this.time = 0; + } + + enqueue(task) { + let taskTimeout = this.time; + this.time += this.intervalInMs; + this.pendingHandles.push(setTimeout(() => { + this.time -= this.intervalInMs; + task(); + }, taskTimeout)); + } + + clear() { + this.pendingHandles.forEach((timeoutHandle) => { + clearTimeout(timeoutHandle); + }); + this.pendingHandles = []; + this.time = 0; + } +}