2019-03-13 19:10:13 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const joi = require('joi');
|
|
|
|
const fs = require('fs');
|
|
|
|
const mime = require('mime');
|
|
|
|
const { featureShema } = require('./routes/admin-api/feature-schema');
|
|
|
|
const strategySchema = require('./routes/admin-api/strategy-schema');
|
2019-03-14 17:56:02 +01:00
|
|
|
const YAML = require('js-yaml');
|
2019-03-13 19:10:13 +01:00
|
|
|
const {
|
|
|
|
FEATURE_IMPORT,
|
|
|
|
DROP_FEATURES,
|
|
|
|
STRATEGY_IMPORT,
|
|
|
|
DROP_STRATEGIES,
|
|
|
|
} = require('./event-type');
|
|
|
|
|
|
|
|
const dataSchema = joi.object().keys({
|
2019-03-14 17:56:02 +01:00
|
|
|
version: joi.number(),
|
2019-03-13 19:10:13 +01:00
|
|
|
features: joi
|
|
|
|
.array()
|
|
|
|
.optional()
|
|
|
|
.items(featureShema),
|
|
|
|
strategies: joi
|
|
|
|
.array()
|
|
|
|
.optional()
|
|
|
|
.items(strategySchema),
|
|
|
|
});
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
function readFile(file) {
|
|
|
|
return new Promise((resolve, reject) =>
|
|
|
|
fs.readFile(file, (err, v) => (err ? reject(err) : resolve(v)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseFile(file, data) {
|
2019-04-26 10:36:17 +02:00
|
|
|
return mime.getType(file) === 'text/yaml'
|
2019-03-14 17:56:02 +01:00
|
|
|
? YAML.safeLoad(data)
|
|
|
|
: JSON.parse(data);
|
|
|
|
}
|
|
|
|
|
2019-03-13 19:10:13 +01:00
|
|
|
class StateService {
|
|
|
|
constructor(config) {
|
|
|
|
this.config = config;
|
2019-04-30 21:14:23 +02:00
|
|
|
this.logger = config.getLogger('state-service.js');
|
2019-03-13 19:10:13 +01:00
|
|
|
}
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
importFile({ file, dropBeforeImport, userName }) {
|
|
|
|
return readFile(file)
|
|
|
|
.then(data => parseFile(file, data))
|
|
|
|
.then(data => this.import({ data, userName, dropBeforeImport }));
|
2019-03-13 19:10:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async import({ data, userName, dropBeforeImport }) {
|
|
|
|
const { eventStore } = this.config.stores;
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
const importData = await joi.validate(data, dataSchema);
|
2019-03-13 19:10:13 +01:00
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
if (importData.features) {
|
2019-04-30 21:14:23 +02:00
|
|
|
this.logger.info(
|
|
|
|
`Importing ${importData.features.length} features`
|
|
|
|
);
|
2019-03-13 19:10:13 +01:00
|
|
|
if (dropBeforeImport) {
|
2019-04-30 21:14:23 +02:00
|
|
|
this.logger.info(`Dropping existing features`);
|
2019-03-13 19:10:13 +01:00
|
|
|
await eventStore.store({
|
|
|
|
type: DROP_FEATURES,
|
|
|
|
createdBy: userName,
|
|
|
|
data: { name: 'all-features' },
|
|
|
|
});
|
|
|
|
}
|
2019-03-14 17:56:02 +01:00
|
|
|
await Promise.all(
|
|
|
|
importData.features.map(feature =>
|
|
|
|
eventStore.store({
|
|
|
|
type: FEATURE_IMPORT,
|
|
|
|
createdBy: userName,
|
|
|
|
data: feature,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
2019-03-13 19:10:13 +01:00
|
|
|
}
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
if (importData.strategies) {
|
2019-04-30 21:14:23 +02:00
|
|
|
this.logger.info(
|
|
|
|
`Importing ${importData.strategies.length} strategies`
|
|
|
|
);
|
2019-03-13 19:10:13 +01:00
|
|
|
if (dropBeforeImport) {
|
2019-04-30 21:14:23 +02:00
|
|
|
this.logger.info(`Dropping existing strategies`);
|
2019-03-13 19:10:13 +01:00
|
|
|
await eventStore.store({
|
|
|
|
type: DROP_STRATEGIES,
|
|
|
|
createdBy: userName,
|
|
|
|
data: { name: 'all-strategies' },
|
|
|
|
});
|
|
|
|
}
|
2019-03-14 17:56:02 +01:00
|
|
|
await Promise.all(
|
|
|
|
importData.strategies.map(strategy =>
|
|
|
|
eventStore.store({
|
|
|
|
type: STRATEGY_IMPORT,
|
|
|
|
createdBy: userName,
|
|
|
|
data: strategy,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
2019-03-13 19:10:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
async export({ includeFeatureToggles = true, includeStrategies = true }) {
|
2019-03-13 19:10:13 +01:00
|
|
|
const { featureToggleStore, strategyStore } = this.config.stores;
|
|
|
|
|
2019-03-14 17:56:02 +01:00
|
|
|
return Promise.all([
|
|
|
|
includeFeatureToggles
|
|
|
|
? featureToggleStore.getFeatures()
|
|
|
|
: Promise.resolve(),
|
|
|
|
includeStrategies
|
|
|
|
? strategyStore.getEditableStrategies()
|
|
|
|
: Promise.resolve(),
|
|
|
|
]).then(([features, strategies]) => ({
|
|
|
|
version: 1,
|
|
|
|
features,
|
|
|
|
strategies,
|
|
|
|
}));
|
2019-03-13 19:10:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = StateService;
|