2016-06-16 03:48:26 -05:00
|
|
|
///<reference path="../../headers/common.d.ts" />
|
|
|
|
|
|
|
|
import angular from 'angular';
|
|
|
|
import _ from 'lodash';
|
|
|
|
import config from 'app/core/config';
|
|
|
|
import coreModule from 'app/core/core_module';
|
|
|
|
|
|
|
|
export class BackendSrv {
|
|
|
|
inFlightRequests = {};
|
|
|
|
HTTP_REQUEST_CANCELLED = -1;
|
|
|
|
|
2017-04-14 08:47:39 -05:00
|
|
|
/** @ngInject */
|
|
|
|
constructor(private $http, private alertSrv, private $rootScope, private $q, private $timeout, private contextSrv) {
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
get(url, params?) {
|
|
|
|
return this.request({ method: 'GET', url: url, params: params });
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(url) {
|
|
|
|
return this.request({ method: 'DELETE', url: url });
|
|
|
|
}
|
|
|
|
|
|
|
|
post(url, data) {
|
|
|
|
return this.request({ method: 'POST', url: url, data: data });
|
2017-04-20 04:16:37 -05:00
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
|
|
|
|
patch(url, data) {
|
|
|
|
return this.request({ method: 'PATCH', url: url, data: data });
|
|
|
|
}
|
|
|
|
|
|
|
|
put(url, data) {
|
|
|
|
return this.request({ method: 'PUT', url: url, data: data });
|
|
|
|
}
|
|
|
|
|
|
|
|
requestErrorHandler(err) {
|
|
|
|
if (err.isHandled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var data = err.data || { message: 'Unexpected error' };
|
|
|
|
if (_.isString(data)) {
|
|
|
|
data = { message: data };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err.status === 422) {
|
|
|
|
this.alertSrv.set("Validation failed", data.message, "warning", 4000);
|
|
|
|
throw data;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.severity = 'error';
|
|
|
|
|
|
|
|
if (err.status < 500) {
|
|
|
|
data.severity = "warning";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.message) {
|
|
|
|
this.alertSrv.set("Problem!", data.message, data.severity, 10000);
|
|
|
|
}
|
|
|
|
|
|
|
|
throw data;
|
|
|
|
}
|
|
|
|
|
|
|
|
request(options) {
|
|
|
|
options.retry = options.retry || 0;
|
2017-04-14 09:00:52 -05:00
|
|
|
var requestIsLocal = !options.url.match(/^http/);
|
2016-06-16 03:48:26 -05:00
|
|
|
var firstAttempt = options.retry === 0;
|
|
|
|
|
2017-04-14 09:00:52 -05:00
|
|
|
if (requestIsLocal) {
|
|
|
|
if (this.contextSrv.user && this.contextSrv.user.orgId) {
|
|
|
|
options.headers = options.headers || {};
|
|
|
|
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
|
|
|
|
}
|
|
|
|
|
2017-04-14 12:01:08 -05:00
|
|
|
if (options.url.indexOf("/") === 0) {
|
|
|
|
options.url = options.url.substring(1);
|
2017-04-14 09:00:52 -05:00
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.$http(options).then(results => {
|
|
|
|
if (options.method !== 'GET') {
|
|
|
|
if (results && results.data.message) {
|
2016-11-09 03:41:39 -06:00
|
|
|
if (options.showSuccessAlert !== false) {
|
|
|
|
this.alertSrv.set(results.data.message, '', 'success', 3000);
|
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return results.data;
|
|
|
|
}, err => {
|
|
|
|
// handle unauthorized
|
|
|
|
if (err.status === 401 && firstAttempt) {
|
|
|
|
return this.loginPing().then(() => {
|
|
|
|
options.retry = 1;
|
|
|
|
return this.request(options);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-25 10:42:08 -05:00
|
|
|
this.$timeout(this.requestErrorHandler.bind(this, err), 50);
|
2016-06-16 03:48:26 -05:00
|
|
|
throw err;
|
|
|
|
});
|
2017-04-20 04:16:37 -05:00
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
|
2017-02-05 23:42:26 -06:00
|
|
|
addCanceler(requestId, canceler) {
|
|
|
|
if (requestId in this.inFlightRequests) {
|
|
|
|
this.inFlightRequests[requestId].push(canceler);
|
|
|
|
} else {
|
|
|
|
this.inFlightRequests[requestId] = [canceler];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resolveCancelerIfExists(requestId) {
|
|
|
|
var cancelers = this.inFlightRequests[requestId];
|
|
|
|
if (!_.isUndefined(cancelers) && cancelers.length) {
|
|
|
|
cancelers[0].resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-16 03:48:26 -05:00
|
|
|
datasourceRequest(options) {
|
|
|
|
options.retry = options.retry || 0;
|
|
|
|
|
|
|
|
// A requestID is provided by the datasource as a unique identifier for a
|
|
|
|
// particular query. If the requestID exists, the promise it is keyed to
|
|
|
|
// is canceled, canceling the previous datasource request if it is still
|
|
|
|
// in-flight.
|
2017-02-05 23:42:26 -06:00
|
|
|
var requestId = options.requestId;
|
|
|
|
if (requestId) {
|
|
|
|
this.resolveCancelerIfExists(requestId);
|
2016-06-16 03:48:26 -05:00
|
|
|
// create new canceler
|
2017-02-05 23:42:26 -06:00
|
|
|
var canceler = this.$q.defer();
|
2016-06-16 03:48:26 -05:00
|
|
|
options.timeout = canceler.promise;
|
2017-02-05 23:42:26 -06:00
|
|
|
this.addCanceler(requestId, canceler);
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
|
2017-04-14 09:00:52 -05:00
|
|
|
var requestIsLocal = !options.url.match(/^http/);
|
2016-06-16 03:48:26 -05:00
|
|
|
var firstAttempt = options.retry === 0;
|
|
|
|
|
2017-04-14 09:00:52 -05:00
|
|
|
if (requestIsLocal) {
|
|
|
|
if (this.contextSrv.user && this.contextSrv.user.orgId) {
|
|
|
|
options.headers = options.headers || {};
|
|
|
|
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
|
|
|
|
}
|
2017-04-14 08:47:39 -05:00
|
|
|
|
2017-04-14 12:01:08 -05:00
|
|
|
if (options.url.indexOf("/") === 0) {
|
|
|
|
options.url = options.url.substring(1);
|
2017-04-14 09:00:52 -05:00
|
|
|
}
|
2016-09-23 05:29:53 -05:00
|
|
|
|
2017-04-14 09:00:52 -05:00
|
|
|
if (options.headers && options.headers.Authorization) {
|
|
|
|
options.headers['X-DS-Authorization'] = options.headers.Authorization;
|
|
|
|
delete options.headers.Authorization;
|
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.$http(options).catch(err => {
|
|
|
|
if (err.status === this.HTTP_REQUEST_CANCELLED) {
|
|
|
|
throw {err, cancelled: true};
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle unauthorized for backend requests
|
|
|
|
if (requestIsLocal && firstAttempt && err.status === 401) {
|
|
|
|
return this.loginPing().then(() => {
|
|
|
|
options.retry = 1;
|
|
|
|
if (canceler) {
|
|
|
|
canceler.resolve();
|
|
|
|
}
|
|
|
|
return this.datasourceRequest(options);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//populate error obj on Internal Error
|
|
|
|
if (_.isString(err.data) && err.status === 500) {
|
|
|
|
err.data = {
|
2016-08-16 15:31:26 -05:00
|
|
|
error: err.statusText,
|
|
|
|
response: err.data,
|
2016-06-16 03:48:26 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// for Prometheus
|
|
|
|
if (!err.data.message && _.isString(err.data.error)) {
|
|
|
|
err.data.message = err.data.error;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
}).finally(() => {
|
|
|
|
// clean up
|
|
|
|
if (options.requestId) {
|
2017-02-05 23:42:26 -06:00
|
|
|
this.inFlightRequests[options.requestId].shift();
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
});
|
2017-04-20 04:16:37 -05:00
|
|
|
}
|
2016-06-16 03:48:26 -05:00
|
|
|
|
|
|
|
loginPing() {
|
|
|
|
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 });
|
|
|
|
}
|
|
|
|
|
|
|
|
search(query) {
|
|
|
|
return this.get('/api/search', query);
|
|
|
|
}
|
|
|
|
|
|
|
|
getDashboard(type, slug) {
|
|
|
|
return this.get('/api/dashboards/' + type + '/' + slug);
|
|
|
|
}
|
|
|
|
|
|
|
|
saveDashboard(dash, options) {
|
|
|
|
options = (options || {});
|
2017-06-05 07:56:11 -05:00
|
|
|
|
|
|
|
return this.post('/api/dashboards/db/', {
|
|
|
|
dashboard: dash,
|
2017-05-24 11:52:06 -05:00
|
|
|
parentId: dash.parentId,
|
2017-06-05 07:56:11 -05:00
|
|
|
overwrite: options.overwrite === true,
|
|
|
|
message: options.message || '',
|
|
|
|
});
|
2016-06-16 03:48:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
coreModule.service('backendSrv', BackendSrv);
|