2016-10-27 13:13:51 +02:00
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
const logger = require('../logger');
|
|
|
|
|
const ClientMetrics = require('../client-metrics');
|
2016-11-09 11:16:44 +01:00
|
|
|
|
const joi = require('joi');
|
2016-11-11 15:46:59 +01:00
|
|
|
|
const { clientMetricsSchema, clientRegisterSchema } = require('./metrics-schema');
|
2016-12-01 17:15:55 +01:00
|
|
|
|
const { catchLogAndSendErrorResponse } = require('./route-utils');
|
|
|
|
|
|
2016-10-27 16:55:38 +02:00
|
|
|
|
module.exports = function (app, config) {
|
2016-11-04 23:02:55 +01:00
|
|
|
|
const {
|
2016-11-05 13:36:44 +01:00
|
|
|
|
clientMetricsStore,
|
2016-11-05 14:08:47 +01:00
|
|
|
|
clientStrategyStore,
|
|
|
|
|
clientInstanceStore,
|
2016-12-06 09:19:15 +01:00
|
|
|
|
clientApplicationsStore,
|
2016-11-05 14:08:47 +01:00
|
|
|
|
} = config.stores;
|
2016-11-30 23:41:57 +01:00
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
|
const metrics = new ClientMetrics(clientMetricsStore);
|
2016-12-04 14:09:37 +01:00
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
|
app.get('/client/seen-toggles', (req, res) => {
|
2016-12-05 13:26:53 +01:00
|
|
|
|
const seenAppToggles = metrics.getAppsWithToggles();
|
2016-11-28 17:11:11 +01:00
|
|
|
|
res.json(seenAppToggles);
|
2016-11-02 12:49:25 +01:00
|
|
|
|
});
|
2016-10-27 16:55:38 +02:00
|
|
|
|
|
2016-12-05 13:53:53 +01:00
|
|
|
|
app.get('/client/seen-apps', (req, res) => {
|
|
|
|
|
const seenApps = metrics.getSeenAppsPerToggle();
|
2016-12-06 09:19:15 +01:00
|
|
|
|
clientApplicationsStore.getApplicationMetaData()
|
|
|
|
|
.then(toLookup)
|
|
|
|
|
.then(metaData => {
|
|
|
|
|
Object.keys(seenApps).forEach(key => {
|
|
|
|
|
seenApps[key] = seenApps[key].map(entry => {
|
|
|
|
|
if (metaData[entry.appName]) {
|
|
|
|
|
entry.data = metaData[entry.appName];
|
|
|
|
|
}
|
|
|
|
|
return entry;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
res.json(seenApps);
|
|
|
|
|
});
|
2016-12-05 13:27:08 +01:00
|
|
|
|
});
|
|
|
|
|
|
2016-12-01 17:15:55 +01:00
|
|
|
|
app.get('/client/metrics/feature-toggles', (req, res) => {
|
2016-11-04 16:16:55 +01:00
|
|
|
|
res.json(metrics.getTogglesMetrics());
|
2016-10-27 13:13:51 +02:00
|
|
|
|
});
|
|
|
|
|
|
2016-12-04 18:08:19 +01:00
|
|
|
|
app.get('/client/metrics/feature-toggles/:name', (req, res) => {
|
|
|
|
|
const name = req.params.name;
|
|
|
|
|
const data = metrics.getTogglesMetrics();
|
|
|
|
|
const lastHour = data.lastHour[name] || {};
|
|
|
|
|
const lastMinute = data.lastMinute[name] || {};
|
|
|
|
|
res.json({
|
|
|
|
|
lastHour,
|
|
|
|
|
lastMinute,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2016-11-02 12:49:25 +01:00
|
|
|
|
app.post('/client/metrics', (req, res) => {
|
2016-11-11 15:46:59 +01:00
|
|
|
|
const data = req.body;
|
2016-11-28 17:11:11 +01:00
|
|
|
|
const clientIp = req.ip;
|
|
|
|
|
|
2016-11-11 15:46:59 +01:00
|
|
|
|
joi.validate(data, clientMetricsSchema, (err, cleaned) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
return res.status(400).json(err);
|
2016-11-09 11:16:44 +01:00
|
|
|
|
}
|
2016-11-28 17:11:11 +01:00
|
|
|
|
|
|
|
|
|
clientMetricsStore
|
|
|
|
|
.insert(cleaned)
|
|
|
|
|
.then(() => clientInstanceStore.insert({
|
|
|
|
|
appName: cleaned.appName,
|
|
|
|
|
instanceId: cleaned.instanceId,
|
|
|
|
|
clientIp,
|
|
|
|
|
}))
|
2016-12-02 17:19:59 +01:00
|
|
|
|
.catch(err => logger.error('failed to store metrics', err));
|
2016-12-04 14:09:37 +01:00
|
|
|
|
|
2016-11-11 15:46:59 +01:00
|
|
|
|
res.status(202).end();
|
|
|
|
|
});
|
2016-11-09 11:16:44 +01:00
|
|
|
|
});
|
|
|
|
|
|
2016-11-02 12:49:25 +01:00
|
|
|
|
app.post('/client/register', (req, res) => {
|
2016-11-04 23:02:55 +01:00
|
|
|
|
const data = req.body;
|
2016-11-05 12:42:58 +01:00
|
|
|
|
const clientIp = req.ip;
|
2016-11-02 12:49:25 +01:00
|
|
|
|
|
2016-11-09 11:16:44 +01:00
|
|
|
|
joi.validate(data, clientRegisterSchema, (err, cleaned) => {
|
|
|
|
|
if (err) {
|
2016-11-10 22:05:50 +01:00
|
|
|
|
return res.status(400).json(err);
|
2016-11-09 11:16:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
|
clientStrategyStore
|
|
|
|
|
.insert(cleaned.appName, cleaned.strategies)
|
2016-11-09 11:16:44 +01:00
|
|
|
|
.then(() => clientInstanceStore.insert({
|
|
|
|
|
appName: cleaned.appName,
|
|
|
|
|
instanceId: cleaned.instanceId,
|
|
|
|
|
clientIp,
|
|
|
|
|
}))
|
2016-12-04 18:08:19 +01:00
|
|
|
|
.then(() => logger.info(`New client registered with
|
2016-12-01 17:15:55 +01:00
|
|
|
|
appName=${cleaned.appName} and instanceId=${cleaned.instanceId}`))
|
2016-12-02 17:19:59 +01:00
|
|
|
|
.catch(err => logger.error('failed to register client', err));
|
2016-11-09 11:16:44 +01:00
|
|
|
|
|
2016-11-11 15:46:59 +01:00
|
|
|
|
res.status(202).end();
|
2016-11-09 11:16:44 +01:00
|
|
|
|
});
|
2016-10-27 16:55:38 +02:00
|
|
|
|
});
|
2016-11-02 23:17:28 +01:00
|
|
|
|
|
|
|
|
|
app.get('/client/strategies', (req, res) => {
|
2016-11-28 17:11:11 +01:00
|
|
|
|
const appName = req.query.appName;
|
2016-12-04 14:09:37 +01:00
|
|
|
|
if (appName) {
|
2016-11-28 17:11:11 +01:00
|
|
|
|
clientStrategyStore.getByAppName(appName)
|
|
|
|
|
.then(data => res.json(data))
|
2016-12-01 17:15:55 +01:00
|
|
|
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
2016-11-28 17:11:11 +01:00
|
|
|
|
} else {
|
|
|
|
|
clientStrategyStore.getAll()
|
|
|
|
|
.then(data => res.json(data))
|
2016-12-01 17:15:55 +01:00
|
|
|
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
2016-11-28 17:11:11 +01:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-12-06 09:19:15 +01:00
|
|
|
|
app.post('/client/applications/:appName', (req, res) => {
|
|
|
|
|
const input = Object.assign({}, req.body, {
|
|
|
|
|
appName: req.params.appName,
|
|
|
|
|
});
|
|
|
|
|
clientApplicationsStore
|
|
|
|
|
.upsert(input)
|
|
|
|
|
.then(() => res.status(202).end())
|
|
|
|
|
.catch((e) => {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
res.status(500).end();
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-12-05 22:17:40 +01:00
|
|
|
|
|
2016-12-06 09:19:15 +01:00
|
|
|
|
function toLookup (metaData) {
|
|
|
|
|
return metaData.reduce((result, entry) => {
|
|
|
|
|
result[entry.appName] = entry;
|
|
|
|
|
return result;
|
|
|
|
|
}, {});
|
|
|
|
|
}
|
2016-12-05 22:17:40 +01:00
|
|
|
|
|
2016-12-06 09:19:15 +01:00
|
|
|
|
app.get('/client/applications/', (req, res) => {
|
|
|
|
|
const strategyName = req.query.strategyName;
|
|
|
|
|
Promise.all([
|
|
|
|
|
strategyName ? clientStrategyStore.getAppsForStrategy(strategyName) : clientStrategyStore.getApplications(),
|
|
|
|
|
clientApplicationsStore.getApplicationMetaData().then(toLookup),
|
|
|
|
|
])
|
|
|
|
|
.then(([apps, metaData]) => {
|
|
|
|
|
const applications = apps.map(({ appName }) => ({
|
|
|
|
|
appName,
|
|
|
|
|
data: metaData[appName],
|
|
|
|
|
links: {
|
|
|
|
|
appDetails: `/api/client/applications/${appName}`,
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
res.json({ applications });
|
|
|
|
|
})
|
|
|
|
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
2016-11-02 23:17:28 +01:00
|
|
|
|
});
|
2016-11-04 23:02:55 +01:00
|
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
|
app.get('/client/applications/:appName', (req, res) => {
|
|
|
|
|
const appName = req.params.appName;
|
|
|
|
|
const seenToggles = metrics.getSeenTogglesByAppName(appName);
|
|
|
|
|
Promise.all([
|
2016-12-04 14:09:37 +01:00
|
|
|
|
clientInstanceStore.getByAppName(appName),
|
|
|
|
|
clientStrategyStore.getByAppName(appName),
|
2016-12-06 09:19:15 +01:00
|
|
|
|
clientApplicationsStore.getApplicationMetaData(appName),
|
2016-12-04 14:09:37 +01:00
|
|
|
|
])
|
2016-12-06 09:19:15 +01:00
|
|
|
|
.then(([instances, strategies, [metaData]]) =>
|
|
|
|
|
res.json({ appName, instances, strategies, seenToggles, data: metaData })
|
|
|
|
|
)
|
2016-12-01 17:15:55 +01:00
|
|
|
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
2016-11-04 23:02:55 +01:00
|
|
|
|
});
|
2016-10-27 13:13:51 +02:00
|
|
|
|
};
|