From 77b4d8f42a467cef78248cc1ef36f4c33306af3a Mon Sep 17 00:00:00 2001 From: John Cowen Date: Wed, 29 Jul 2020 10:16:09 +0200 Subject: [PATCH] ui: Use X-Range header as a signal as to whether to reconcile the ember-data store (#8384) * ui: Use `X-Range` header/meta to decide whether to reconcile or not Previously we used a `shouldReconcile` method in order to decide whether a response should trigger a reconciliation of the frontend ember-data 'source of truth' or not. It's a lot nicer/clearer if this 'flag' can be set alongside the HTTP request information, moreover we almost have the same functionality in `If-Range`/`Partial Content` HTTP functionality. Here we partly follow this HTTP semantics but use a custom `X-Range` header instead. --- ui-v2/app/adapters/intention.js | 7 ++++++- ui-v2/app/adapters/service.js | 1 + ui-v2/app/serializers/application.js | 9 ++++++++- ui-v2/app/services/client/http.js | 2 +- .../services/data-source/protocols/http.js | 19 +++++++++--------- ui-v2/app/services/repository.js | 3 --- ui-v2/app/services/repository/intention.js | 9 --------- ui-v2/app/services/repository/service.js | 7 ------- .../services/repository/type/event-source.js | 20 +++++++++---------- 9 files changed, 36 insertions(+), 41 deletions(-) diff --git a/ui-v2/app/adapters/intention.js b/ui-v2/app/adapters/intention.js index 73fe3d25f4..5cef02a3f7 100644 --- a/ui-v2/app/adapters/intention.js +++ b/ui-v2/app/adapters/intention.js @@ -9,7 +9,12 @@ export default Adapter.extend({ requestForQuery: function(request, { dc, filter, index, uri }) { return request` GET /v1/connect/intentions?${{ dc }} - X-Request-ID: ${uri} + X-Request-ID: ${uri}${ + typeof filter !== 'undefined' + ? ` + X-Range: ${filter}` + : `` + } ${{ index, diff --git a/ui-v2/app/adapters/service.js b/ui-v2/app/adapters/service.js index b9cced90ba..dd09327020 100644 --- a/ui-v2/app/adapters/service.js +++ b/ui-v2/app/adapters/service.js @@ -5,6 +5,7 @@ export default Adapter.extend({ if (typeof gateway !== 'undefined') { return request` GET /v1/internal/ui/gateway-services-nodes/${gateway}?${{ dc }} + X-Range: ${gateway} X-Request-ID: ${uri} ${{ diff --git a/ui-v2/app/serializers/application.js b/ui-v2/app/serializers/application.js index af5f1c3d5c..fb7397df8a 100644 --- a/ui-v2/app/serializers/application.js +++ b/ui-v2/app/serializers/application.js @@ -92,7 +92,11 @@ export default Serializer.extend({ // and they need the slug key AND potential namespace in order to // create the correct uid/fingerprint return { - [primaryKey]: this.fingerprint(primaryKey, slugKey, data[DATACENTER_KEY])({ + [primaryKey]: this.fingerprint( + primaryKey, + slugKey, + data[DATACENTER_KEY] + )({ [slugKey]: data[slugKey], [NSPACE_KEY]: data[NSPACE_KEY], })[primaryKey], @@ -151,6 +155,9 @@ export default Serializer.extend({ dc: headers[HTTP_HEADERS_DATACENTER.toLowerCase()], nspace: headers[HTTP_HEADERS_NAMESPACE.toLowerCase()], }; + if (typeof headers['x-range'] !== 'undefined') { + meta.range = headers['x-range']; + } if (requestType === 'query') { meta.date = this.timestamp(); payload.forEach(function(item) { diff --git a/ui-v2/app/services/client/http.js b/ui-v2/app/services/client/http.js index e98ba07c57..a9525afb3c 100644 --- a/ui-v2/app/services/client/http.js +++ b/ui-v2/app/services/client/http.js @@ -68,7 +68,7 @@ const parseBody = function(strs, ...values) { return [body, ...values]; }; -const CLIENT_HEADERS = [CACHE_CONTROL, 'X-Request-ID']; +const CLIENT_HEADERS = [CACHE_CONTROL, 'X-Request-ID', 'X-Range']; export default Service.extend({ dom: service('dom'), connections: service('client/connections'), diff --git a/ui-v2/app/services/data-source/protocols/http.js b/ui-v2/app/services/data-source/protocols/http.js index 5a51a08f8f..4dc7070a98 100644 --- a/ui-v2/app/services/data-source/protocols/http.js +++ b/ui-v2/app/services/data-source/protocols/http.js @@ -33,16 +33,17 @@ export default Service.extend({ // so we might get urls like //dc/services let find; const repo = this[model]; - if (repo.shouldReconcile(src)) { - configuration.createEvent = function(result = {}, configuration) { - const event = { - type: 'message', - data: result, - }; - repo.reconcile(get(event, 'data.meta')); - return event; + configuration.createEvent = function(result = {}, configuration) { + const event = { + type: 'message', + data: result, }; - } + const meta = get(event, 'data.meta') || {}; + if (typeof meta.range === 'undefined') { + repo.reconcile(meta); + } + return event; + }; let method, slug; switch (model) { case 'datacenters': diff --git a/ui-v2/app/services/repository.js b/ui-v2/app/services/repository.js index 9e3e13971c..a48b4f13e4 100644 --- a/ui-v2/app/services/repository.js +++ b/ui-v2/app/services/repository.js @@ -15,9 +15,6 @@ export default Service.extend({ }, // store: service('store'), - shouldReconcile: function(method) { - return true; - }, reconcile: function(meta = {}) { // unload anything older than our current sync date/time if (typeof meta.date !== 'undefined') { diff --git a/ui-v2/app/services/repository/intention.js b/ui-v2/app/services/repository/intention.js index 193ed93730..72b8a62275 100644 --- a/ui-v2/app/services/repository/intention.js +++ b/ui-v2/app/services/repository/intention.js @@ -12,15 +12,6 @@ export default RepositoryService.extend({ delete obj.Namespace; return this._super(obj); }, - shouldReconcile: function(method) { - // TODO: This is to be switched out for something at an adapter level - // so it works for both methods of interacting with data-sources - switch (true) { - case method === 'findByService' || method.indexOf('for-service') !== -1: - return false; - } - return this._super(...arguments); - }, findByService: function(slug, dc, nspace, configuration = {}) { const query = { dc: dc, diff --git a/ui-v2/app/services/repository/service.js b/ui-v2/app/services/repository/service.js index a62a70a534..82c6f4f2d7 100644 --- a/ui-v2/app/services/repository/service.js +++ b/ui-v2/app/services/repository/service.js @@ -5,13 +5,6 @@ export default RepositoryService.extend({ getModelName: function() { return modelName; }, - shouldReconcile: function(method) { - switch (method) { - case 'findGatewayBySlug': - return false; - } - return this._super(...arguments); - }, findBySlug: function(slug, dc) { return this._super(...arguments).then(function(item) { // TODO: Move this to the Serializer diff --git a/ui-v2/app/services/repository/type/event-source.js b/ui-v2/app/services/repository/type/event-source.js index 79683aa391..6fffd39ad1 100644 --- a/ui-v2/app/services/repository/type/event-source.js +++ b/ui-v2/app/services/repository/type/event-source.js @@ -9,17 +9,17 @@ import { cache as createCache, BlockingEventSource } from 'consul-ui/utils/dom/e const createProxy = function(repo, find, settings, cache, serialize = JSON.stringify) { const client = this.client; // custom createEvent, here used to reconcile the ember-data store for each tick - let createEvent; - if (repo.shouldReconcile(find)) { - createEvent = function(result = {}, configuration) { - const event = { - type: 'message', - data: result, - }; - repo.reconcile(get(event, 'data.meta')); - return event; + const createEvent = function(result = {}, configuration) { + const event = { + type: 'message', + data: result, }; - } + const meta = get(event, 'data.meta') || {}; + if (typeof meta.range === 'undefined') { + repo.reconcile(meta); + } + return event; + }; // proxied find*..(id, dc) return function() { const key = `${repo.getModelName()}.${find}.${serialize([...arguments])}`;