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.
This commit is contained in:
John Cowen 2020-07-29 10:16:09 +02:00 committed by GitHub
parent 34034b76f5
commit 77b4d8f42a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 36 additions and 41 deletions

View File

@ -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,

View File

@ -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}
${{

View File

@ -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) {

View File

@ -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'),

View File

@ -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':

View File

@ -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') {

View File

@ -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,

View File

@ -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

View File

@ -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])}`;