ring-websites-toolbelt
Version:
Ring Publishing Platform tool to work with Ring Websites
280 lines (217 loc) • 9.68 kB
JavaScript
const chokidar = require('chokidar');
const path = require('path');
class Watchers {
constructor(options) {
options = options || {};
this._paths = options.paths;
this._providers = options.providers;
this._dbCodes = options.dbCodes;
this._directories = options.directories;
this._files = options.files;
this._ocdnData = options.ocdnData;
this._watchers = {};
this._jobs = [];
}
startSavingConfig() {
let watcherName = "savingConfig";
if (this._watchers[watcherName]) {
throw Error(`Watcher ${watcherName} is already running`);
}
const toWatch = [
path.join(this._paths.build, this._files.CONFIG_JSON),
path.join(this._paths.build, this._files.PARTIALS_JSON),
path.join(this._paths.build, this._directories.SCHEMES)
];
this._watchers[watcherName] = chokidar.watch(toWatch, {
persistent: true,
ignoreInitial: true,
usePolling: true,
awaitWriteFinish: {
stabilityThreshold: 1000,
pollInterval: 100
},
}).on('all', (event, p) => {
console.info(`Watcher | ${watcherName} reloaded ${p}`);
let configPath = path.join(this._paths.build, this._files.CONFIG_JSON);
let partialsPath = path.join(this._paths.build, this._files.PARTIALS_JSON);
let schemesPath = path.join(this._paths.build, this._directories.SCHEMES);
let configJson = this._providers.files.getConfigJson(configPath, partialsPath, schemesPath, this._ocdnData.Location + Watchers.DIRECTORIES.STATIC);
this._providers.api.insertThemeConfig(configJson);
console.info(`Watcher | ${watcherName} updated config.json`);
});
console.info(`Watcher | ${watcherName} is running`);
}
startBuildingTheme() {
let watcherName = "buildingTheme";
if (this._watchers[watcherName]) {
throw Error(`Watcher ${watcherName} is already running`);
}
let changeDetected = 0;
this._watchers[watcherName] = chokidar.watch([this._paths.theme, this._paths.modules], {
persistent: true,
ignoreInitial: true,
ignored: [
`${this._paths.theme}/node_modules`,
`${this._paths.theme}/.git`,
`**/${this._paths.modules}/**/node_modules`,
`**/${this._paths.modules}/**/.git`
]
}).on('all', (event, path) => {
changeDetected = 1;
});
let job = setInterval(async () => {
if (changeDetected) {
changeDetected = 0;
await this._providers.builder.build();
console.info(`Watcher | ${watcherName} build theme`);
}
}, Watchers.WATCHER_INTERVAL);
this._jobs.push(job);
console.info(`Watcher | ${watcherName} is running`);
}
startGetLogs(verboseLogging) {
let watcherName = "getLogs";
let lastLogDate = 0;
if (this._watchers[watcherName]) {
throw Error(`Watcher ${watcherName} is already running`);
}
let job = setInterval(async () => {
let data = await this._providers.api.getLogs();
if (data && data.length) {
for (let i = 0; i < data.length; i++) {
if (lastLogDate < data[i].add_time) {
for (let j = 0; j < data[i].logs.length; j++) {
try {
const log = JSON.parse(data[i].logs[j]);
const logType = Object.keys(log)[0];
let logMessage = log[logType];
const isWarnError = ['warn', 'error'].includes(logType);
const isSpecialLog = logMessage.includes('__USER_LOG:') || logMessage.includes('__FINAL:');
logMessage = logMessage.replace('__USER_LOG:', '').replace('__FINAL:', '');
if (verboseLogging || isWarnError || isSpecialLog) {
console[logType](logMessage);
}
} catch (e) {
console.error(e.message);
console.warn("Can't parse log, please contact CSP team");
}
}
lastLogDate = data[i].add_time;
}
}
}
}, Watchers.WATCHER_INTERVAL);
this._jobs.push(job);
console.info(`Watcher | ${watcherName} is running`);
}
_watchFiles(watcherName, dirs, addAction, delAction) {
if (this._watchers[watcherName]) {
throw Error(`Watcher ${watcherName} is already running`);
}
let changedFiles = new Set();
let deletedFiles = new Set();
this._watchers[watcherName] = chokidar.watch(dirs, {
persistent: true,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'add' || event === 'change') {
deletedFiles.delete(path);
changedFiles.add(path);
console.info(`Watcher | ${watcherName} event: ${event} (${path})`);
} else if (event === 'unlink') {
changedFiles.delete(path);
deletedFiles.add(path);
console.info(`Watcher | ${watcherName} event: ${event} (${path})`);
}
});
let job = setInterval(async () => {
let filesToDelete = [...deletedFiles];
deletedFiles = new Set();
let filesToSave = [...changedFiles];
changedFiles = new Set();
if (filesToDelete.length) {
await delAction(filesToDelete);
console.info(`Watcher | ${watcherName} delete files: ${JSON.stringify(filesToDelete)}`);
}
if (filesToSave.length) {
await addAction(filesToSave);
console.info(`Watcher | ${watcherName} save files: ${JSON.stringify(filesToSave)}`);
}
}, Watchers.WATCHER_INTERVAL);
this._jobs.push(job);
console.info(`Watcher | ${watcherName} is running`);
}
startSavingTheme() {
let codes = Object.keys(this._dbCodes);
for (let i = 0; i < codes.length; i++) {
let dbCode = this._dbCodes[codes[i]];
let dir = path.join(this._paths.build, this._directories[codes[i]]);
let addAction = async (files) => {
let objFiles = files.map((el) => {
return {
'basePath': dir,
'relativePath': path.relative(dir, el)
};
});
await this._providers.api.insertFiles(objFiles, dbCode);
};
let delAction = async (files) => {
let objFiles = files.map((el) => {
return {
'basePath': dir,
'relativePath': path.relative(dir, el)
};
});
await this._providers.api.deleteFiles(objFiles, dbCode);
};
this._watchFiles(`savingTheme_${codes[i]}`, dir, addAction, delAction);
}
}
startSavingStatic() {
let dir = path.join(this._paths.build, this._directories.STATIC);
let addAction = async (files) => {
// const tmpFile = path.join(this._paths.temp, `tmp_${Date.now()}.zip`);
// let filesToZip = files.map( (el) => {
// return {
// source: el,
// target: path.relative(this._paths.build, el)
// }
// });
// await this._providers.files.compressFiles(filesToZip, tmpFile);
// await this._providers.s3.uploadCompressedFile(tmpFile, this._ocdnData.Key);
// await this._providers.files.removeCompressedFile(tmpFile);
let promises = files.map((el) => {
return this._providers.s3.uploadFile(el, path.join(this._ocdnData.Key, path.relative(this._paths.build, el)));
});
return await Promise.all(promises);
};
let delAction = async (files) => {
// const filesToDelete = files.map( (el) => {
// return {
// Key: path.join(this._ocdnData.Key, path.relative(this._paths.build, el))
// }
// });
// await this._providers.s3.deleteFiles(filesToDelete);
let promises = files.map((el) => {
return this._providers.s3.deleteFile(path.join(this._ocdnData.Key, path.relative(this._paths.build, el)));
});
return await Promise.all(promises);
};
this._watchFiles('savingStatic', dir, addAction, delAction);
}
stopAll() {
let watcherNames = Object.keys(this._watchers);
for (let i = 0; i < watcherNames.length; i++) {
this._watchers[watcherNames[i]].close();
}
this._watchers = {};
for (let i = 0; i < this._jobs.length; i++) {
clearInterval(this._jobs[i]);
}
this._jobs = [];
}
}
Watchers.WATCHER_INTERVAL = 1000;
Watchers.DIRECTORIES = {};
Watchers.DIRECTORIES.STATIC = '/static/';
module.exports = Watchers;