Split .config.json into separate files

This commit is contained in:
Nick O'Leary 2020-09-23 17:29:09 +01:00
parent b8b0247717
commit fb2da0ee9e
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 81 additions and 24 deletions

View File

@ -14,41 +14,99 @@
* limitations under the License.
**/
var when = require('when');
var fs = require('fs-extra');
var fspath = require("path");
const fs = require('fs-extra');
const fspath = require("path");
var log = require("@node-red/util").log; // TODO: separate module
var util = require("./util");
const log = require("@node-red/util").log;
const util = require("./util");
const configSections = ['nodes','users','projects'];
let initialisePromise;
const settingsCache = {};
var globalSettingsFile;
var globalSettingsBackup;
var settings;
async function migrateToMultipleConfigFiles() {
const data = await util.readFile(globalSettingsFile,globalSettingsBackup,{});
return writeSettings(data).then( () => fs.remove(globalSettingsFile) );
}
/**
* Takes the single settings object and splits it into separate files. This makes
* it easier to backup selected parts of the settings and also helps reduce the blast
* radius if a file is lost.
*
* The settings are written to four files:
* - .config.nodes.json - the node registry
* - .config.users.json - user specific settings (eg editor settings)
* - .config.projects.json - project settings, including the active project
* - .config.runtime.json - everything else - most notable _credentialSecret
*/
function writeSettings(data) {
const configKeys = Object.keys(data);
const writePromises = [];
configSections.forEach(key => {
const sectionData = data[key] || {};
delete data[key];
const sectionFilename = getSettingsFilename(key);
const sectionContent = JSON.stringify(sectionData,null,4);
if (sectionContent !== settingsCache[key]) {
settingsCache[key] = sectionContent;
writePromises.push(util.writeFile(sectionFilename,sectionContent,sectionFilename+".backup"))
}
})
// Having extracted nodes/users/projects, write whatever is left to the runtime config
const sectionFilename = getSettingsFilename("runtime");
const sectionContent = JSON.stringify(data,null,4);
if (sectionContent !== settingsCache["runtime"]) {
settingsCache["runtime"] = sectionContent;
writePromises.push(util.writeFile(sectionFilename,sectionContent,sectionFilename+".backup"));
}
return Promise.all(writePromises);
}
async function readSettings() {
// Read the 'runtime' settings file first
const runtimeFilename = getSettingsFilename("runtime");
const result = await util.readFile(runtimeFilename,runtimeFilename+".backup",{});
const readPromises = [];
// Read the other settings files and add them into the runtime settings
configSections.forEach(key => {
const sectionFilename = getSettingsFilename(key);
readPromises.push(util.readFile(sectionFilename,sectionFilename+".backup",{}).then(sectionData => {
result[key] = sectionData;
}))
});
return Promise.all(readPromises).then(() => result);
}
function getSettingsFilename(section) {
return fspath.join(settings.userDir,`.config.${section}.json`);
}
module.exports = {
init: function(_settings) {
settings = _settings;
globalSettingsFile = fspath.join(settings.userDir,".config.json");
globalSettingsBackup = fspath.join(settings.userDir,".config.json.backup");
if (fs.existsSync(globalSettingsFile) && !settings.readOnly) {
initialisePromise = migrateToMultipleConfigFiles();
} else {
initialisePromise = Promise.resolve();
}
},
getSettings: function() {
return when.promise(function(resolve,reject) {
fs.readFile(globalSettingsFile,'utf8',function(err,data) {
if (!err) {
try {
return resolve(util.parseJSON(data));
} catch(err2) {
log.trace("Corrupted config detected - resetting");
}
}
return resolve({});
})
})
return initialisePromise.then(readSettings)
},
saveSettings: function(newSettings) {
if (settings.readOnly) {
return when.resolve();
return Promise.resolve();
}
return util.writeFile(globalSettingsFile,JSON.stringify(newSettings,null,1),globalSettingsBackup);
return initialisePromise.then(() => writeSettings(newSettings));
}
}

View File

@ -14,11 +14,10 @@
* limitations under the License.
**/
var fs = require('fs-extra');
var fspath = require('path');
var when = require('when');
const fs = require('fs-extra');
const fspath = require('path');
var log = require("@node-red/util").log; // TODO: separate module
const log = require("@node-red/util").log;
function parseJSON(data) {
if (data.charCodeAt(0) === 0xFEFF) {
@ -27,7 +26,7 @@ function parseJSON(data) {
return JSON.parse(data);
}
function readFile(path,backupPath,emptyResponse,type) {
return when.promise(function(resolve) {
return new Promise(function(resolve) {
fs.readFile(path,'utf8',function(err,data) {
if (!err) {
if (data.length === 0) {