
warm.topology-webapp.2017.10.0.source-code.topology.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of topology-webapp Show documentation
Show all versions of topology-webapp Show documentation
Server-Sent Events of instances being added/removed from cluster
var topology = (function() {
var defaults = {
headers: {},
method: 'GET',
keycloak: false,
keycloakUpdateInterval: 30,
context: '/topology'
}, topology = {}, scheduler;
function factory( options ) {
options = merge(defaults, options);
function ajax( serviceName, path, settings ) {
var nextServer = scheduler.next(serviceName),
deferredResult = deferred(),
keycloak = options.keycloak;
if (!nextServer) {
return deferredResult.reject('No servers available').promise;
}
// ensure some default settings exist
settings = merge({
method: options.method,
headers: options.headers,
data: undefined
}, settings);
path = path || '/';
settings.url = nextServer.endpoint + path;
// Set relevant headers
if (settings.method === 'POST') {
settings.headers['Content-Type'] = 'application/json';
}
if (!keycloak || !keycloak.authenticated) {
// If we're not authenticating, go ahead and make the request
return doRequest( settings );
} else {
// TODO: Make token update interval configurable
keycloak.updateToken(30).success( function() {
console.log( "topology.js: keycloak token refreshed" );
// Using keycloak, update token, and make the request
settings.headers.Authorization = 'Bearer ' + keycloak.token;
// make the request
doRequest( settings ).then( function(result) {
deferredResult.resolve(result);
});
}).error( function(e) {
console.log( "topology.js: Failed to update keycloak token. " + e );
deferredResult.reject('Failed to update keycloak token. ' + e);
});
}
return deferredResult.promise;
}
function doRequest(settings) {
var request = new XMLHttpRequest(),
deferredResponse = deferred();
// set the state change handler and open the http request
request.onreadystatechange = changeState(request, deferredResponse);
request.open(settings.method, settings.url);
getHeaders(settings.headers).forEach(function(header) {
request.setRequestHeader(header.field, header.value);
});
if (settings.data) request.send(settings.data);
else request.send();
// return a deferred promise
return deferredResponse;
function changeState(request, deferredResponse) {
return function() {
switch(request.readyState) {
case 0:
case 1:
case 2:
case 3:
break;
case 4:
processResponse(request, deferredResponse);
break;
default:
console.log('topology.js: Unexpected XMLHttpRequest state');
deferred.reject('Unexpected XMLHttpRequst state');
}
};
}
function processResponse(request, response) {
if (request.status === 200) {
response.resolve(JSON.parse(request.responseText));
} else {
response.reject('topology.js: Bad request: ' + request.statusText);
}
}
function getHeaders(headers) {
var headerList = [];
for (var key in headers) {
if (headers.hasOwnProperty(key)) {
headerList.push({
field: key,
value: headers[key]
});
}
}
return headerList;
}
}
function getJSON(serviceName, path, data) {
//var _data = (typeof data === 'string') ? data : JSON.stringify(data);
var qs = '?';
for (var k in data) {
if (data.hasOwnProperty(k)) {
qs += k + '=' + data[k];
}
}
if ( typeof(path) == 'undefined' ) {
path = '/';
}
path = path + qs;
return ajax( serviceName, path );
}
function postJSON(serviceName, path, data) {
if (typeof path === 'object') {
data = path;
path = '/';
}
var _data = (typeof data === 'string') ? data : JSON.stringify(data);
return ajax( serviceName, path, {
method: 'POST',
data: _data
});
}
function schedule(initialState) {
var o = {
next: next
}, topology = parseInitialState(initialState);
function next(serviceName) {
var service = topology[serviceName];
if (!service || service.length < 1) return null;
return service.next();
}
function parseInitialState(initialState) {
var o = {};
for(var key in initialState) {
if (initialState[key] && initialState.hasOwnProperty(key)) {
o[key] = {
instances: initialState[key],
currentIndex: 0,
length: initialState[key].length
};
o[key].next = increment(o[key]);
}
}
function increment(o) {
return function() {
var index = o.currentIndex,
_next = o.instances[index];
o.currentIndex = ++index % o.length;
return _next;
};
}
return o;
}
return o;
}
var initialTopologyObtained = false;
var result = deferred();
var sse = new EventSource( options.context + "/system/stream" );
sse.addEventListener('topologyChange', function(message) {
console.log('topology.js: topology changed: ', message.data);
topology = JSON.parse(message.data);
scheduler = schedule(topology);
if (!initialTopologyObtained) {
initialTopologyObtained = true;
result.resolve(_topology);
}
});
sse.onerror = function(e) {
console.log( "topology.js: topology SSE error", e );
if (!initialTopologyObtained) {
initialTopologyObtained = true;
result.reject(_topology);
}
};
function onTopologyChange(f) {
sse.addEventListener('topologyChange', function(message) {
f(JSON.parse(message.data));
});
f(topology);
}
var _topology = {
ajax: ajax,
postJSON: postJSON,
getJSON: getJSON,
onTopologyChange: onTopologyChange
};
Object.defineProperty(_topology, 'topology', {
get: function() { return topology; },
enumerable: true
});
Object.freeze(_topology);
return result.promise;
}
function merge(defaults, provided) {
var obj = {};
if (!provided) provided = {};
for (var key in defaults) {
if (defaults.hasOwnProperty(key))
obj[key] = provided[key] || defaults[key];
}
return obj;
}
function promises() {
var PENDING = 0,
FULFILLED = 1,
REJECTED = 2;
function promise(fn) {
var p = {
state: PENDING,
identify: 'fidelity',
value: null,
queue: [],
handlers: {
fulfill: null,
reject: null
}
};
p.then = then(p);
if (isA('function', fn)) {
fn(
function(v) { resolve(p, v); },
function(r) { reject(p, r); }
);
}
return p;
}
function then(p) {
return function(onFulfilled, onRejected) {
var q = promise();
if (isA('function', onFulfilled)) {
q.handlers.fulfill = onFulfilled;
}
if (isA('function', onRejected)) {
q.handlers.reject = onRejected;
}
p.queue.push(q);
process(p);
return q;
};
}
function resolve(p, x) {
if (x === p)
reject(p, new TypeError('The promise and its value are the same.'));
if (isPromise(x)) {
if (x.state === PENDING) {
x.then(function(value) {
resolve(p, value);
}, function(cause) {
reject(p, cause);
});
} else {
transition(p, x.state, x.value);
}
} else if (isA('function', x) || isA('object', x)) {
var called = false, thenFunction;
try {
thenFunction = x.then;
if (isA('function', thenFunction)) {
thenFunction.call(x, function(y) {
if (!called) {
resolve(p, y);
called = true;
}
}, function (r) {
if (!called) {
reject(p, r);
called = true;
}
});
} else {
fulfill(p, x);
called = true;
}
} catch (e) {
if (!called) {
reject(p, e);
called = true;
}
}
}
else fulfill(p, x);
}
function fulfill(p, result) {
transition(p, FULFILLED, result);
}
function reject(p, cause) {
transition(p, REJECTED, cause);
}
function defaultFulfill(v) { return v; }
function defaultReject(r) { throw r; }
function process(p) {
if (p.state === PENDING) return;
setTimeout(function() {
while(p.queue.length) {
var qp = p.queue.shift(),
handler, value;
if (p.state === FULFILLED) {
handler = qp.handlers.fulfill || defaultFulfill;
} else if (p.state === REJECTED) {
handler = qp.handlers.reject || defaultReject;
}
try {
value = handler(p.value);
} catch(e) {
transition(qp, REJECTED, e);
continue;
}
resolve(qp, value);
}
}, 0);
}
function transition(p, state, value) {
if (p.state === state ||
p.state !== PENDING ||
arguments.length !== 3) return;
p.state = state;
p.value = value;
process(p);
}
function isA(type, x) {
return x && typeof x === type;
}
function isPromise(x) {
return x && x.identify === 'fidelity';
}
promise.PENDING = PENDING;
promise.FULFILLED = FULFILLED;
promise.REJECTED = REJECTED;
return promise;
}
var promise = promises(),
deferred = function() {
var resolver, rejecter,
p = promise(function(resolve, reject) {
resolver = resolve;
rejecter = reject;
});
function resolve(value) {
resolver(value);
return this;
}
function reject(cause) {
rejecter(cause);
return this;
}
return {
promise: p,
resolve: resolve,
reject: reject,
then: p.then
};
};
return factory;
})();
© 2015 - 2025 Weber Informatics LLC | Privacy Policy