Compare commits

..

2 Commits

4 changed files with 151 additions and 219 deletions

View File

@ -21,7 +21,7 @@ function updatetNextDate() {
class CronContainer { class CronContainer {
constructor() { constructor() {
this.cronJobs = []; this.cronJob = null;
this.cronClean = null; this.cronClean = null;
} }
@ -33,70 +33,52 @@ class CronContainer {
this.cronClean = new CronJob("0 1 * * *", this._clean, null, false, Intl.DateTimeFormat().resolvedOptions().timeZone); this.cronClean = new CronJob("0 1 * * *", this._clean, null, false, Intl.DateTimeFormat().resolvedOptions().timeZone);
this.cronClean.start(); this.cronClean.start();
} }
if (this.cronJob != null) {
logger.info("Stopping Cron...");
this.cronJob.stop();
this.cronJob = null;
}
if (!settingsTools.check_cron(settingsTools.getSettings())) { if (!settingsTools.check_cron(settingsTools.getSettings())) {
logger.warn("No Cron settings available."); logger.warn("No Cron settings available.");
return; return;
} }
if(this.cronJobs.length != 0){ switch (settings.cron_base) {
this._clean_cron_jobs(); case "0":
}
if (settings.cron.length == 0){
logger.warn("No Cron settings available."); logger.warn("No Cron settings available.");
} return;
else {
let i = 0;
for(let cron of settings.cron){
logger.info(`Starting cron #${i} ...`)
switch (cron.cron_base) {
case "1": { case "1": {
let splited = cron.cron_hour.split(":"); let splited = settings.cron_hour.split(":");
cronStr = "" + splited[1] + " " + splited[0] + " * * *"; cronStr = "" + splited[1] + " " + splited[0] + " * * *";
break; break;
} }
case "2": { case "2": {
let splited = cron.cron_hour.split(":"); let splited = settings.cron_hour.split(":");
cronStr = "" + splited[1] + " " + splited[0] + " * * " + cron.cron_weekday; cronStr = "" + splited[1] + " " + splited[0] + " * * " + settings.cron_weekday;
break; break;
} }
case "3": { case "3": {
let splited = cron.cron_hour.split(":"); let splited = settings.cron_hour.split(":");
cronStr = "" + splited[1] + " " + splited[0] + " " + cron.cron_month_day + " * *"; cronStr = "" + splited[1] + " " + splited[0] + " " + settings.cron_month_day + " * *";
break; break;
} }
case "4": { case "4": {
cronStr = cron.cron_custom; cronStr = settings.cron_custom;
break; break;
} }
} }
this.cronJobs.push(new CronJob(cronStr, this._createBackup, null, true, Intl.DateTimeFormat().resolvedOptions().timeZone)); logger.info("Starting Cron...");
i ++ ; this.cronJob = new CronJob(cronStr, this._createBackup, null, false, Intl.DateTimeFormat().resolvedOptions().timeZone);
} this.cronJob.start();
}
this.updateNextDate(); this.updateNextDate();
} }
updateNextDate() { updateNextDate() {
let date; let date;
if (this.cronJobs.length == 0) if (this.cronJob == null) date = null;
date = null; else date = this.cronJob.nextDate().format("MMM D, YYYY HH:mm");
else {
let last_date = null;
for(let item of this.cronJobs){
if(last_date == null)
last_date = item.nextDate();
else{
if(last_date > item.nextDate())
last_date = item.nextDate();
}
}
date = last_date.format("MMM D, YYYY HH:mm");
}
let status = statusTools.getStatus(); let status = statusTools.getStatus();
status.next_backup = date; status.next_backup = date;
statusTools.setStatus(status); statusTools.setStatus(status);
@ -142,16 +124,6 @@ class CronContainer {
webdav.clean().catch(); webdav.clean().catch();
} }
} }
_clean_cron_jobs(){
let i = 0;
for(let elem of this.cronJobs){
logger.info(`Stopping Crong job #${i}`)
elem.stop();
i++;
}
this.cronJobs = []
}
} }
class Singleton { class Singleton {

View File

@ -19,7 +19,7 @@ function getVersion() {
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
@ -50,7 +50,7 @@ function getAddonList() {
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
@ -97,6 +97,8 @@ function getAddonToBackup() {
if (!excluded_addon.includes(addon.slug)) if (!excluded_addon.includes(addon.slug))
slugs.push(addon.slug) slugs.push(addon.slug)
} }
logger.debug("Addon to backup:")
logger.debug(slugs)
resolve(slugs) resolve(slugs)
}) })
.catch(() => reject()); .catch(() => reject());
@ -136,6 +138,8 @@ function getFolderToBackup() {
if (!excluded_folder.includes(folder.slug)) if (!excluded_folder.includes(folder.slug))
slugs.push(folder.slug) slugs.push(folder.slug)
} }
logger.debug("Folders to backup:");
logger.debug(slugs)
return slugs; return slugs;
} }
@ -144,11 +148,11 @@ function getSnapshots() {
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
got("http://hassio/snapshots", option) got("http://hassio/backups", option)
.then((result) => { .then((result) => {
if (status.error_code === 1) { if (status.error_code === 1) {
status.status = "idle"; status.status = "idle";
@ -156,7 +160,7 @@ function getSnapshots() {
status.error_code = null; status.error_code = null;
statusTools.setStatus(status); statusTools.setStatus(status);
} }
let snaps = result.body.data.snapshots; let snaps = result.body.data.backups;
resolve(snaps); resolve(snaps);
}) })
.catch((error) => { .catch((error) => {
@ -184,11 +188,11 @@ function downloadSnapshot(id) {
status.progress = 0; status.progress = 0;
statusTools.setStatus(status); statusTools.setStatus(status);
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
}; };
pipeline( pipeline(
got.stream.get(`http://hassio/snapshots/${id}/download`, option) got.stream.get(`http://hassio/backups/${id}/download`, option)
.on("downloadProgress", (e) => { .on("downloadProgress", (e) => {
let percent = Math.round(e.percent * 100) / 100; let percent = Math.round(e.percent * 100) / 100;
if (status.progress !== percent) { if (status.progress !== percent) {
@ -233,11 +237,11 @@ function dellSnap(id) {
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
got.post(`http://hassio/snapshots/${id}/remove`, option) got.post(`http://hassio/backups/${id}/remove`, option)
.then(() => resolve()) .then(() => resolve())
.catch(() => reject()); .catch(() => reject());
}) })
@ -251,11 +255,11 @@ function checkSnap(id) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
got(`http://hassio/snapshots/${id}/info`, option) got(`http://hassio/backups/${id}/info`, option)
.then((result) => { .then((result) => {
logger.debug(`Snapshot size: ${result.body.data.size}`); logger.debug(`Snapshot size: ${result.body.data.size}`);
resolve(); resolve();
@ -275,7 +279,7 @@ function createNewBackup(name) {
getAddonToBackup().then((addons) => { getAddonToBackup().then((addons) => {
let folders = getFolderToBackup(); let folders = getFolderToBackup();
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
timeout: create_snap_timeout, timeout: create_snap_timeout,
json: { json: {
@ -288,7 +292,7 @@ function createNewBackup(name) {
option.json.password = settingsTools.getSettings().password_protect_value option.json.password = settingsTools.getSettings().password_protect_value
} }
got.post(`http://hassio/snapshots/new/partial`, option) got.post(`http://hassio/backups/new/partial`, option)
.then((result) => { .then((result) => {
logger.info(`Snapshot created with id ${result.body.data.slug}`); logger.info(`Snapshot created with id ${result.body.data.slug}`);
resolve(result.body.data.slug); resolve(result.body.data.slug);
@ -354,11 +358,11 @@ function uploadSnapshot(path) {
body: form, body: form,
username: this.username, username: this.username,
password: this.password, password: this.password,
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
}; };
got.stream got.stream
.post(`http://hassio/snapshots/new/upload`, options) .post(`http://hassio/backups/new/upload`, options)
.on("uploadProgress", (e) => { .on("uploadProgress", (e) => {
let percent = e.percent; let percent = e.percent;
if (status.progress !== percent) { if (status.progress !== percent) {
@ -413,7 +417,7 @@ function stopAddons() {
let promises = []; let promises = [];
let token = process.env.HASSIO_TOKEN; let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "X-HASSIO-KEY": token }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
}; };
let addons_slug = settingsTools.getSettings().auto_stop_addon let addons_slug = settingsTools.getSettings().auto_stop_addon
@ -496,72 +500,72 @@ function startAddons() {
function publish_state(state){ function publish_state(state){
let data_error_sensor = { // let data_error_sensor = {
state: state.status == "error" ? "on" : "off", // state: state.status == "error" ? "on" : "off",
attributes: { // attributes: {
friendly_name: "Nexcloud Backup Error", // friendly_name: "Nexcloud Backup Error",
device_class: "problem", // device_class: "problem",
error_code: state.error_code, // error_code: state.error_code,
message: state.message, // message: state.message,
icon: state.status == "error" ? "mdi:cloud-alert" : "mdi:cloud-check" // icon: state.status == "error" ? "mdi:cloud-alert" : "mdi:cloud-check"
}, // },
} // }
let token = process.env.HASSIO_TOKEN; // let token = process.env.HASSIO_TOKEN;
let option = { // let option = {
headers: { "Authorization": `Bearer ${token}` }, // headers: { "Authorization": `Bearer ${token}` },
responseType: "json", // responseType: "json",
json: data_error_sensor // json: data_error_sensor
}; // };
got.post(`http://hassio/core/api/states/binary_sensor.nextcloud_backup_error`, option) // got.post(`http://hassio/core/api/states/binary_sensor.nextcloud_backup_error`, option)
.then((result) => { // .then((result) => {
logger.debug('Home assistant sensor updated (error status)'); // logger.debug('Home assistant sensor updated (error status)');
}) // })
.catch((error) => { // .catch((error) => {
logger.error(error); // logger.error(error);
}); // });
let icon = "" // let icon = ""
switch(state.status){ // switch(state.status){
case "error": // case "error":
icon = "mdi:cloud-alert"; // icon = "mdi:cloud-alert";
break; // break;
case "download": // case "download":
case "download-b": // case "download-b":
icon = "mdi:cloud-download"; // icon = "mdi:cloud-download";
break; // break;
case "upload": // case "upload":
case "upload-b": // case "upload-b":
icon = "mdi:cloud-upload"; // icon = "mdi:cloud-upload";
break; // break;
case "idle": // case "idle":
icon = "mdi:cloud-check"; // icon = "mdi:cloud-check";
break; // break;
default: // default:
icon = "mdi:cloud-sync"; // icon = "mdi:cloud-sync";
break; // break;
} // }
let data_state_sensor = { // let data_state_sensor = {
state: state.status, // state: state.status,
attributes: { // attributes: {
friendly_name: "Nexcloud Backup Status", // friendly_name: "Nexcloud Backup Status",
error_code: state.error_code, // error_code: state.error_code,
message: state.message, // message: state.message,
icon: icon, // icon: icon,
last_backup: state.last_backup == null || state.last_backup == "" ? "" : new Date(state.last_backup).toISOString(), // last_backup: state.last_backup == null || state.last_backup == "" ? "" : new Date(state.last_backup).toISOString(),
next_backup: state.next_backup == null || state.next_backup == "" ? "" : new Date(state.next_backup).toISOString() // next_backup: state.next_backup == null || state.next_backup == "" ? "" : new Date(state.next_backup).toISOString()
}, // },
} // }
option.json = data_state_sensor // option.json = data_state_sensor
got.post(`http://hassio/core/api/states/sensor.nextcloud_backup_status`, option) // got.post(`http://hassio/core/api/states/sensor.nextcloud_backup_status`, option)
.then((result) => { // .then((result) => {
logger.debug('Home assistant sensor updated (status)'); // logger.debug('Home assistant sensor updated (status)');
}) // })
.catch((error) => { // .catch((error) => {
logger.error(error); // logger.error(error);
}); // });
} }
exports.getVersion = getVersion; exports.getVersion = getVersion;

View File

@ -6,92 +6,48 @@ const CronJob = require("cron").CronJob;
const settingsPath = "/data/backup_conf.json"; const settingsPath = "/data/backup_conf.json";
function check_cron(conf) { function check_cron(conf) {
if (conf.cron != null) { if (conf.cron_base != null) {
if (!Array.isArray(conf.cron)) if (conf.cron_base === "1" || conf.cron_base === "2" || conf.cron_base === "3") {
return false; if (conf.cron_hour != null && conf.cron_hour.match(/\d\d:\d\d/)) {
if (conf.cron_base === "1") return true;
for (let elem of conf.cron){ } else return false;
if (elem.cron_base != null) {
if (elem.cron_base === "1" || elem.cron_base === "2" || elem.cron_base === "3") {
if (elem.cron_hour != null && elem.cron_hour.match(/\d\d:\d\d/)) {
if (elem.cron_base === "1")
continue;
}
else
return false;
} }
if (elem.cron_base === "2") { if (conf.cron_base === "2") {
if( elem.cron_weekday != null && elem.cron_weekday >= 0 && elem.cron_weekday <= 6) return conf.cron_weekday != null && conf.cron_weekday >= 0 && conf.cron_weekday <= 6;
continue;
else
return false;
} }
if (elem.cron_base === "3") { if (conf.cron_base === "3") {
if( elem.cron_month_day != null && elem.cron_month_day >= 1 && elem.cron_month_day <= 28) return conf.cron_month_day != null && conf.cron_month_day >= 1 && conf.cron_month_day <= 28;
continue;
else
return false
} }
if (elem.cron_base === "4") { if (conf.cron_base === "4") {
if (elem.cron_custom != null) { if (conf.cron_custom != null) {
try { try {
new CronJob(elem.cron_custom, () => { }); new CronJob(conf.cron_custom, () => {});
continue;
} catch (e) {
return false;
}
}
else
return false;
}
}
else
return false
}
}
else
return false;
return true; return true;
} } catch(e) {
return false;
function migrate_cron_conf(conf) {
let obj = {
cron_base: conf.cron_base,
cron_hour: conf.cron_hour,
cron_weekday: conf.cron_weekday,
cron_month_day: conf.cron_month_day,
cron_custom: conf.cron_custom,
} }
conf.cron = [obj]; }else return false;
delete conf.cron_base; }
delete conf.cron_hour;
delete conf.cron_weekday; if (conf.cron_base === "0") return true;
delete conf.cron_month_day; } else return false;
delete conf.cron_custom;
return conf return false;
} }
function check(conf, fallback = false) { function check(conf, fallback = false) {
let needSave = false; let needSave = false;
if (conf.cron == null && !Array.isArray(conf.cron) && conf.cron_base != null) {
// Migrate to new cron conf format
logger.warn("Migrating to new cron conf format !")
conf = migrate_cron_conf(conf);
needSave = true;
}
if (!check_cron(conf)) { if (!check_cron(conf)) {
if (fallback) { if (fallback) {
logger.warn("Bad value for cron settings, fallback to default "); logger.warn("Bad value for cron settings, fallback to default ");
conf.cron = [] conf.cron_base = "0";
conf.cron_hour = "00:00";
conf.cron_weekday = "0";
conf.cron_month_day = "1";
conf.cron_custom = "5 4 * * *";
} else { } else {
logger.error("Bad value for cron settings"); logger.error("Bad value for cron settings");
return [false, "Bad cron settings"]; return [false, "Bad cron settings"];
@ -228,7 +184,7 @@ function getSettings() {
} }
function setSettings(settings) { function setSettings(settings) {
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
} }
exports.getSettings = getSettings; exports.getSettings = getSettings;

View File

@ -32,8 +32,8 @@ function getStatus() {
function setStatus(state) { function setStatus(state) {
if (fs.existsSync(statusPath)) { if (fs.existsSync(statusPath)) {
let old_state_str = fs.readFileSync(statusPath).toString(); let old_state_str = fs.readFileSync(statusPath).toString();
if(old_state_str !== JSON.stringify(state, null, 2)){ if(old_state_str !== JSON.stringify(state)){
fs.writeFileSync(statusPath, JSON.stringify(state, null, 2)); fs.writeFileSync(statusPath, JSON.stringify(state));
hassioApiTools.publish_state(state); hassioApiTools.publish_state(state);
} }
}else{ }else{