🔨 Migrate all code to ESM (#124)

* 🔨 Convert everything to es6 modules

* 🔨 Cath in manual backup

* 🔨 Change status storage method

* 🔨 Move token to static in hassioApiTools

* 🚑 Fix crash on backup upload to ha

* 🚑 Fix multiple upload

* 🔨 Add logs for protected

* 🔨 Catch some errors
This commit is contained in:
Sébastien Clément 2022-04-30 16:19:31 +02:00 committed by GitHub
parent 0fa020d0ab
commit ec957041e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 299 additions and 324 deletions

View File

@ -1,11 +1,26 @@
const createError = require("http-errors"); import createError from "http-errors";
const express = require("express"); import express from "express";
const path = require("path"); import path from "path";
const cookieParser = require("cookie-parser"); import cookieParser from "cookie-parser";
const logger = require("morgan"); import logger from "morgan";
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import fs from "fs"
import newlog from "./config/winston.js"
import * as statusTools from "./tools/status.js"
import * as hassioApiTools from "./tools/hassioApiTools.js"
import webdav from "./tools/webdavTools.js"
import * as settingsTools from "./tools/settingsTools.js"
import cronTools from "./tools/cronTools.js"
const indexRouter = require("./routes/index"); import indexRouter from "./routes/index.js"
const apiRouter = require("./routes/api"); import apiRouter from "./routes/api.js"
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const app = express(); const app = express();
// view engine setup // view engine setup
@ -71,17 +86,15 @@ app.use(function (err, req, res, next) {
---------------------------------------------------------- ----------------------------------------------------------
*/ */
const fs = require("fs");
const newlog = require("./config/winston");
newlog.info(`Log level: ${ process.env.LOG_LEVEL }`); newlog.info(`Log level: ${ process.env.LOG_LEVEL }`);
newlog.info(`Backup timeout: ${ parseInt(process.env.CREATE_BACKUP_TIMEOUT) || ( 90 * 60 * 1000 ) }`) newlog.info(`Backup timeout: ${ parseInt(process.env.CREATE_BACKUP_TIMEOUT) || ( 90 * 60 * 1000 ) }`)
if (!fs.existsSync("/data")) fs.mkdirSync("/data"); if (!fs.existsSync("/data")) fs.mkdirSync("/data");
const statusTools = require("./tools/status");
statusTools.init(); statusTools.init();
newlog.info("Satus : \x1b[32mGo !\x1b[0m"); newlog.info("Satus : \x1b[32mGo !\x1b[0m");
const hassioApiTools = require("./tools/hassioApiTools");
hassioApiTools.getSnapshots().then( hassioApiTools.getSnapshots().then(
() => { () => {
newlog.info("Hassio API : \x1b[32mGo !\x1b[0m"); newlog.info("Hassio API : \x1b[32mGo !\x1b[0m");
@ -92,8 +105,6 @@ hassioApiTools.getSnapshots().then(
} }
); );
const WebdavTools = require("./tools/webdavTools");
const webdav = new WebdavTools().getInstance();
webdav.confIsValid().then( webdav.confIsValid().then(
() => { () => {
newlog.info("Nextcloud connection : \x1b[32mGo !\x1b[0m"); newlog.info("Nextcloud connection : \x1b[32mGo !\x1b[0m");
@ -103,11 +114,9 @@ webdav.confIsValid().then(
newlog.error("... " + err); newlog.error("... " + err);
} }
); );
const settingTool = require('./tools/settingsTools')
settingTool.check(settingTool.getSettings(), true); settingsTools.check(settingsTools.getSettings(), true);
const cronTools = require("./tools/cronTools"); cronTools.init();
cronTools.startCron();
export default app;
module.exports = app;

View File

@ -4,9 +4,11 @@
* Module dependencies. * Module dependencies.
*/ */
var app = require('../app'); import app from "../app.js"
var debug = require('debug')('nexcloud-backup:server'); import http from "http"
var http = require('http'); import _debug from 'debug';
const debug = _debug('nexcloud-backup:server');
/** /**
* Get port from environment and store in Express. * Get port from environment and store in Express.

View File

@ -1,4 +1,4 @@
const winston = require("winston"); import winston from "winston";
const logger = winston.createLogger({ const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info', level: process.env.LOG_LEVEL || 'info',
@ -24,4 +24,5 @@ const logger = winston.createLogger({
], ],
}); });
module.exports = logger;
export default logger;

View File

@ -17,7 +17,7 @@
"ejs": "~3.1.6", "ejs": "~3.1.6",
"express": "~4.17.2", "express": "~4.17.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"got": "^11.8.2", "got": "12.0.1",
"http-errors": "~2.0.0", "http-errors": "~2.0.0",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"moment": "^2.29.1", "moment": "^2.29.1",
@ -64,9 +64,9 @@
} }
}, },
"node_modules/@sindresorhus/is": { "node_modules/@sindresorhus/is": {
"version": "4.0.1", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz",
"integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@ -75,14 +75,14 @@
} }
}, },
"node_modules/@szmarczak/http-timer": { "node_modules/@szmarczak/http-timer": {
"version": "4.0.6", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
"dependencies": { "dependencies": {
"defer-to-connect": "^2.0.0" "defer-to-connect": "^2.0.1"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=14.16"
} }
}, },
"node_modules/@types/cacheable-request": { "node_modules/@types/cacheable-request": {
@ -275,9 +275,9 @@
} }
}, },
"node_modules/cacheable-lookup": { "node_modules/cacheable-lookup": {
"version": "5.0.4", "version": "6.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz",
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", "integrity": "sha512-mbcDEZCkv2CZF4G01kr8eBd/5agkt9oCqz75tJMSIsquvRZ2sL6Hi5zGVKi/0OSC9oO1GHfJ2AV0ZIOY9vye0A==",
"engines": { "engines": {
"node": ">=10.6.0" "node": ">=10.6.0"
} }
@ -766,6 +766,11 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/form-data-encoder": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz",
"integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg=="
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -797,29 +802,53 @@
} }
}, },
"node_modules/got": { "node_modules/got": {
"version": "11.8.2", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", "resolved": "https://registry.npmjs.org/got/-/got-12.0.1.tgz",
"integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", "integrity": "sha512-1Zhoh+lDej3t7Ks1BP/Jufn+rNqdiHQgUOcTxHzg2Dao1LQfp5S4Iq0T3iBxN4Zdo7QqCJL+WJUNzDX6rCP2Ew==",
"dependencies": { "dependencies": {
"@sindresorhus/is": "^4.0.0", "@sindresorhus/is": "^4.2.0",
"@szmarczak/http-timer": "^4.0.5", "@szmarczak/http-timer": "^5.0.1",
"@types/cacheable-request": "^6.0.1", "@types/cacheable-request": "^6.0.2",
"@types/responselike": "^1.0.0", "@types/responselike": "^1.0.0",
"cacheable-lookup": "^5.0.3", "cacheable-lookup": "^6.0.4",
"cacheable-request": "^7.0.1", "cacheable-request": "^7.0.2",
"decompress-response": "^6.0.0", "decompress-response": "^6.0.0",
"http2-wrapper": "^1.0.0-beta.5.2", "form-data-encoder": "1.7.1",
"lowercase-keys": "^2.0.0", "get-stream": "^6.0.1",
"p-cancelable": "^2.0.0", "http2-wrapper": "^2.1.9",
"lowercase-keys": "^3.0.0",
"p-cancelable": "^3.0.0",
"responselike": "^2.0.0" "responselike": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=10.19.0" "node": ">=14.16"
}, },
"funding": { "funding": {
"url": "https://github.com/sindresorhus/got?sponsor=1" "url": "https://github.com/sindresorhus/got?sponsor=1"
} }
}, },
"node_modules/got/node_modules/get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/got/node_modules/lowercase-keys": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
"integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/has-flag": { "node_modules/has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -878,12 +907,12 @@
} }
}, },
"node_modules/http2-wrapper": { "node_modules/http2-wrapper": {
"version": "1.0.3", "version": "2.1.10",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.10.tgz",
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", "integrity": "sha512-QHgsdYkieKp+6JbXP25P+tepqiHYd+FVnDwXpxi/BlUcoIB0nsmTOymTNvETuTO+pDuwcSklPE72VR3DqV+Haw==",
"dependencies": { "dependencies": {
"quick-lru": "^5.1.1", "quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0" "resolve-alpn": "^1.2.0"
}, },
"engines": { "engines": {
"node": ">=10.19.0" "node": ">=10.19.0"
@ -1199,11 +1228,11 @@
} }
}, },
"node_modules/p-cancelable": { "node_modules/p-cancelable": {
"version": "2.1.1", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
"engines": { "engines": {
"node": ">=8" "node": ">=12.20"
} }
}, },
"node_modules/parseurl": { "node_modules/parseurl": {
@ -1662,16 +1691,16 @@
"peer": true "peer": true
}, },
"@sindresorhus/is": { "@sindresorhus/is": {
"version": "4.0.1", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz",
"integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==" "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ=="
}, },
"@szmarczak/http-timer": { "@szmarczak/http-timer": {
"version": "4.0.6", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
"requires": { "requires": {
"defer-to-connect": "^2.0.0" "defer-to-connect": "^2.0.1"
} }
}, },
"@types/cacheable-request": { "@types/cacheable-request": {
@ -1839,9 +1868,9 @@
"integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg=="
}, },
"cacheable-lookup": { "cacheable-lookup": {
"version": "5.0.4", "version": "6.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz",
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" "integrity": "sha512-mbcDEZCkv2CZF4G01kr8eBd/5agkt9oCqz75tJMSIsquvRZ2sL6Hi5zGVKi/0OSC9oO1GHfJ2AV0ZIOY9vye0A=="
}, },
"cacheable-request": { "cacheable-request": {
"version": "7.0.2", "version": "7.0.2",
@ -2205,6 +2234,11 @@
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
} }
}, },
"form-data-encoder": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz",
"integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg=="
},
"forwarded": { "forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -2224,21 +2258,35 @@
} }
}, },
"got": { "got": {
"version": "11.8.2", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", "resolved": "https://registry.npmjs.org/got/-/got-12.0.1.tgz",
"integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", "integrity": "sha512-1Zhoh+lDej3t7Ks1BP/Jufn+rNqdiHQgUOcTxHzg2Dao1LQfp5S4Iq0T3iBxN4Zdo7QqCJL+WJUNzDX6rCP2Ew==",
"requires": { "requires": {
"@sindresorhus/is": "^4.0.0", "@sindresorhus/is": "^4.2.0",
"@szmarczak/http-timer": "^4.0.5", "@szmarczak/http-timer": "^5.0.1",
"@types/cacheable-request": "^6.0.1", "@types/cacheable-request": "^6.0.2",
"@types/responselike": "^1.0.0", "@types/responselike": "^1.0.0",
"cacheable-lookup": "^5.0.3", "cacheable-lookup": "^6.0.4",
"cacheable-request": "^7.0.1", "cacheable-request": "^7.0.2",
"decompress-response": "^6.0.0", "decompress-response": "^6.0.0",
"http2-wrapper": "^1.0.0-beta.5.2", "form-data-encoder": "1.7.1",
"lowercase-keys": "^2.0.0", "get-stream": "^6.0.1",
"p-cancelable": "^2.0.0", "http2-wrapper": "^2.1.9",
"lowercase-keys": "^3.0.0",
"p-cancelable": "^3.0.0",
"responselike": "^2.0.0" "responselike": "^2.0.0"
},
"dependencies": {
"get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="
},
"lowercase-keys": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
"integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="
}
} }
}, },
"has-flag": { "has-flag": {
@ -2286,12 +2334,12 @@
} }
}, },
"http2-wrapper": { "http2-wrapper": {
"version": "1.0.3", "version": "2.1.10",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.10.tgz",
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", "integrity": "sha512-QHgsdYkieKp+6JbXP25P+tepqiHYd+FVnDwXpxi/BlUcoIB0nsmTOymTNvETuTO+pDuwcSklPE72VR3DqV+Haw==",
"requires": { "requires": {
"quick-lru": "^5.1.1", "quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0" "resolve-alpn": "^1.2.0"
} }
}, },
"iconv-lite": { "iconv-lite": {
@ -2534,9 +2582,9 @@
} }
}, },
"p-cancelable": { "p-cancelable": {
"version": "2.1.1", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw=="
}, },
"parseurl": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",

View File

@ -2,8 +2,9 @@
"name": "nexcloud-backup", "name": "nexcloud-backup",
"version": "0.8.0", "version": "0.8.0",
"private": true, "private": true,
"type": "module",
"scripts": { "scripts": {
"start": "node ./bin/www " "start": "node ./bin/www.js "
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.0.0", "@fortawesome/fontawesome-free": "^6.0.0",
@ -15,7 +16,7 @@
"ejs": "~3.1.6", "ejs": "~3.1.6",
"express": "~4.17.2", "express": "~4.17.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"got": "^11.8.2", "got": "12.0.1",
"http-errors": "~2.0.0", "http-errors": "~2.0.0",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"moment": "^2.29.1", "moment": "^2.29.1",

View File

@ -29,13 +29,15 @@ function updateDynamicListeners() {
console.log(id); console.log(id);
}); });
let manual_back_list = $(".manual-back-list"); let manual_back_list = $(".manual-back-list");
manual_back_list.off(); manual_back_list.unbind();
manual_back_list.on("click", function () { manual_back_list.on("click", function () {
let id = this.getAttribute("data-id"); let id = this.getAttribute("data-id");
let name = this.getAttribute("data-name"); let name = this.getAttribute("data-name");
manualBackup(id, name); manualBackup(id, name);
}); });
$(".restore").click(function () { let restore_btn = $(".restore");
restore_btn.unbind();
restore_btn.click(function () {
let to_restore = this.getAttribute("data-id"); let to_restore = this.getAttribute("data-id");
console.log(to_restore); console.log(to_restore);
restore(to_restore); restore(to_restore);
@ -243,7 +245,6 @@ function sendNextcloudSettings() {
console.log("Saved"); console.log("Saved");
$("#nextcloud_settings_message").parent().addClass("d-none"); $("#nextcloud_settings_message").parent().addClass("d-none");
create_toast("success", "Nextcloud settings saved !", default_toast_timeout); create_toast("success", "Nextcloud settings saved !", default_toast_timeout);
0;
}) })
.fail((data) => { .fail((data) => {
let nextcloud_settings_message = $("#nextcloud_settings_message"); let nextcloud_settings_message = $("#nextcloud_settings_message");

View File

@ -1,20 +1,18 @@
const express = require("express"); import express from 'express';
const router = express.Router(); import moment from "moment";
const moment = require("moment"); import * as statusTools from "../tools/status.js"
const statusTools = require("../tools/status"); import webdav from "../tools/webdavTools.js"
const WebdavTools = require("../tools/webdavTools"); import * as settingsTools from "../tools/settingsTools.js"
const webdav = new WebdavTools().getInstance(); import * as pathTools from "../tools/pathTools.js"
const settingsTools = require("../tools/settingsTools"); import * as hassioApiTools from "../tools/hassioApiTools.js"
const pathTools = require("../tools/pathTools"); import { humanFileSize } from "../tools/toolbox.js";
const hassioApiTools = require("../tools/hassioApiTools"); import cronTools from "../tools/cronTools.js"
const humanFileSize = require("../tools/toolbox").humanFileSize; import logger from "../config/winston.js"
const cronTools = require("../tools/cronTools"); var router = express.Router();
const logger = require("../config/winston");
router.get("/status", (req, res, next) => { router.get("/status", (req, res, next) => {
cronTools.updatetNextDate(); cronTools.updateNextDate();
let status = statusTools.getStatus(); let status = statusTools.getStatus();
res.json(status); res.json(status);
}); });
@ -130,9 +128,15 @@ router.post("/manual-backup", function (req, res, next) {
hassioApiTools hassioApiTools
.downloadSnapshot(id) .downloadSnapshot(id)
.then(() => { .then(() => {
webdav.uploadFile(id, webdav.getConf().back_dir + pathTools.manual + name + ".tar").catch(); webdav.uploadFile(id, webdav.getConf().back_dir + pathTools.manual + name + ".tar").then(()=>{
res.status(201); res.status(201);
res.send(); res.send();
}).catch(()=>{
res.status(500);
res.send();
}
);
}) })
.catch(() => { .catch(() => {
res.status(500); res.status(500);
@ -161,10 +165,10 @@ router.post("/new-backup", function (req, res, next) {
.then(() => { .then(() => {
hassioApiTools.startAddons().catch(() => { hassioApiTools.startAddons().catch(() => {
}) })
}); }).catch(()=>{});
}); }).catch(()=>{});
}); }).catch(()=>{});
}); }).catch(()=>{});
}) })
.catch(() => { .catch(() => {
hassioApiTools.startAddons().catch(() => { hassioApiTools.startAddons().catch(() => {
@ -191,7 +195,7 @@ router.post("/backup-settings", function (req, res, next) {
let [result, message] = settingsTools.check(req.body) let [result, message] = settingsTools.check(req.body)
if (result) { if (result) {
settingsTools.setSettings(req.body); settingsTools.setSettings(req.body);
cronTools.startCron(); cronTools.init();
res.send(); res.send();
} else { } else {
res.status(400); res.status(400);
@ -225,5 +229,5 @@ router.post("/restore", function (req, res, next) {
} }
}); });
module.exports = router; export default router;

View File

@ -1,9 +1,9 @@
const express = require("express"); import express from 'express';
const router = express.Router(); var router = express.Router();
/* GET home page. */ /* GET home page. */
router.get("/", function (req, res, next) { router.get("/", function (req, res, next) {
res.render("index"); res.render("index");
}); });
module.exports = router; export default router;

View File

@ -1,23 +1,13 @@
const CronJob = require("cron").CronJob; import { CronJob } from "cron"
import * as settingsTools from "./settingsTools.js"
import * as hassioApiTools from "./hassioApiTools.js"
import * as statusTools from "./status.js"
import * as pathTools from "./pathTools.js"
import webdav from "./webdavTools.js"
const settingsTools = require("./settingsTools");
const WebdavTools = require("./webdavTools");
const webdav = new WebdavTools().getInstance();
const hassioApiTools = require("./hassioApiTools");
const statusTools = require("./status");
const pathTools = require("./pathTools");
const logger = require("../config/winston"); import logger from "../config/winston.js"
function startCron() {
let cronContainer = new Singleton().getInstance();
cronContainer.init();
}
function updatetNextDate() {
let cronContainer = new Singleton().getInstance();
cronContainer.updateNextDate();
}
class CronContainer { class CronContainer {
constructor() { constructor() {
@ -126,17 +116,6 @@ class CronContainer {
} }
} }
class Singleton { const INSTANCE = new CronContainer();
constructor() { export default INSTANCE;
if (!Singleton.instance) {
Singleton.instance = new CronContainer();
}
}
getInstance() {
return Singleton.instance;
}
}
exports.startCron = startCron;
exports.updatetNextDate = updatetNextDate;

View File

@ -1,23 +1,24 @@
const fs = require("fs"); import fs from "fs"
import moment from "moment";
import stream from "stream"
import { promisify } from "util";
import got from "got";
import FormData from "form-data";
import * as statusTools from "../tools/status.js"
import * as settingsTools from "../tools/settingsTools.js"
const moment = require("moment"); import logger from "../config/winston.js"
const stream = require("stream");
const { promisify } = require("util");
const pipeline = promisify(stream.pipeline); const pipeline = promisify(stream.pipeline);
const got = require("got");
const FormData = require("form-data");
const statusTools = require("./status");
const settingsTools = require("./settingsTools");
const logger = require("../config/winston");
// Default timout to 90min const token = process.env.SUPERVISOR_TOKEN;
// Default timeout to 90min
const create_snap_timeout = parseInt(process.env.CREATE_BACKUP_TIMEOUT) || (90 * 60 * 1000); const create_snap_timeout = parseInt(process.env.CREATE_BACKUP_TIMEOUT) || (90 * 60 * 1000);
function getVersion() { function getVersion() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
@ -36,19 +37,14 @@ function getVersion() {
resolve(version); resolve(version);
}) })
.catch((error) => { .catch((error) => {
status.status = "error"; statusTools.setError(`Fail to fetch HA Version (${error.message})`, 1);
status.message = "Fail to fetch HA Version (" + error.message + ")"; reject(`Fail to fetch HA Version (${error.message})`);
status.error_code = 1;
statusTools.setStatus(status);
logger.error(status.message);
reject(error.message);
}); });
}); });
} }
function getAddonList() { function getAddonList() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
@ -78,12 +74,8 @@ function getAddonList() {
resolve(installed); resolve(installed);
}) })
.catch((error) => { .catch((error) => {
status.status = "error"; statusTools.setError(`Fail to fetch addons list (${error.message})`, 1);
status.message = "Fail to fetch addons list (" + error.message + ")"; reject(`Fail to fetch addons list (${error.message})`);
status.error_code = 1;
statusTools.setStatus(status);
logger.error(status.message);
reject(error.message);
}); });
}); });
} }
@ -146,7 +138,6 @@ function getFolderToBackup() {
function getSnapshots() { function getSnapshots() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
@ -165,12 +156,8 @@ function getSnapshots() {
resolve(snaps); resolve(snaps);
}) })
.catch((error) => { .catch((error) => {
status.status = "error"; statusTools.setError(`Fail to fetch Hassio backups (${error.message})`, 1);
status.message = "Fail to fetch Hassio snapshots (" + error.message + ")"; reject(`Fail to fetch Hassio backups (${error.message})`);
status.error_code = 1;
statusTools.setStatus(status);
logger.error(status.message);
reject(error.message);
}); });
}); });
} }
@ -181,7 +168,6 @@ function downloadSnapshot(id) {
if (!fs.existsSync("./temp/")) fs.mkdirSync("./temp/"); if (!fs.existsSync("./temp/")) fs.mkdirSync("./temp/");
let tmp_file = `./temp/${id}.tar`; let tmp_file = `./temp/${id}.tar`;
let stream = fs.createWriteStream(tmp_file); let stream = fs.createWriteStream(tmp_file);
let token = process.env.HASSIO_TOKEN;
let status = statusTools.getStatus(); let status = statusTools.getStatus();
checkSnap(id) checkSnap(id)
.then(() => { .then(() => {
@ -203,29 +189,21 @@ function downloadSnapshot(id) {
}), }),
stream stream
) )
.then((res) => { .then(() => {
logger.info("Download success !"); logger.info("Download success !");
status.progress = 1; status.progress = 1;
statusTools.setStatus(status); statusTools.setStatus(status);
logger.debug("Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024); logger.debug("Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024);
resolve(); resolve();
}) })
.catch((err) => { .catch((error) => {
fs.unlinkSync(tmp_file); fs.unlinkSync(tmp_file);
status.status = "error"; statusTools.setError(`Fail to download Hassio backup (${error.message})`, 7);
status.message = "Fail to download Hassio snapshot (" + err.message + ")"; reject(`Fail to download Hassio backup (${error.message})`);
status.error_code = 7;
statusTools.setStatus(status);
logger.error(status.message);
reject(err.message);
}); });
}) })
.catch((err) => { .catch(() => {
status.status = "error"; statusTools.setError("Fail to download Hassio backup. Not found ?", 7);
status.message = "Fail to download Hassio snapshot. Not found ?";
status.error_code = 7;
statusTools.setStatus(status);
logger.error(status.message);
reject(); reject();
}); });
}); });
@ -235,8 +213,6 @@ function dellSnap(id) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
checkSnap(id) checkSnap(id)
.then(() => { .then(() => {
let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
@ -257,7 +233,6 @@ function dellSnap(id) {
function checkSnap(id) { function checkSnap(id) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
@ -279,20 +254,23 @@ function createNewBackup(name) {
status.progress = -1; status.progress = -1;
statusTools.setStatus(status); statusTools.setStatus(status);
logger.info("Creating new snapshot..."); logger.info("Creating new snapshot...");
let token = process.env.HASSIO_TOKEN;
getAddonToBackup().then((addons) => { getAddonToBackup().then((addons) => {
let folders = getFolderToBackup(); let folders = getFolderToBackup();
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
timeout: create_snap_timeout, timeout: {
response: create_snap_timeout
},
json: { json: {
name: name, name: name,
addons: addons, addons: addons,
folders: folders folders: folders
}, },
}; };
if (settingsTools.getSettings().password_protected === "true") { let password_protected = settingsTools.getSettings().password_protected;
logger.debug(`Is password protected ? ${password_protected}`)
if ( password_protected === "true") {
option.json.password = settingsTools.getSettings().password_protect_value option.json.password = settingsTools.getSettings().password_protect_value
} }
@ -302,12 +280,8 @@ function createNewBackup(name) {
resolve(result.body.data.slug); resolve(result.body.data.slug);
}) })
.catch((error) => { .catch((error) => {
status.status = "error"; statusTools.setError(`Can't create new snapshot (${error.message})`, 5);
status.message = "Can't create new snapshot (" + error.message + ")"; reject(`Can't create new snapshot (${error.message})`);
status.error_code = 5;
statusTools.setStatus(status);
logger.error(status.message);
reject(status.message);
}); });
}).catch(reject); }).catch(reject);
@ -337,8 +311,9 @@ function clean() {
logger.info("Local clean done."); logger.info("Local clean done.");
resolve(); resolve();
}) })
.catch(() => { .catch((e) => {
reject(); statusTools.setError(`Fail to clean backups (${e}) !`, 6);
reject(`Fail to clean backups (${e}) !`);
}); });
}); });
} }
@ -353,15 +328,11 @@ function uploadSnapshot(path) {
statusTools.setStatus(status); statusTools.setStatus(status);
logger.info("Uploading backup..."); logger.info("Uploading backup...");
let stream = fs.createReadStream(path); let stream = fs.createReadStream(path);
let token = process.env.HASSIO_TOKEN;
let form = new FormData(); let form = new FormData();
form.append("file", stream); form.append("file", stream);
let options = { let options = {
body: form, body: form,
username: this.username,
password: this.password,
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
}; };
@ -399,19 +370,15 @@ function uploadSnapshot(path) {
}) })
.on("error", (err) => { .on("error", (err) => {
fs.unlinkSync(path); fs.unlinkSync(path);
status.status = "error"; statusTools.setError(`Fail to upload backup to home assistant (${err}) !`, 4);
status.error_code = 4; reject(`Fail to upload backup to home assistant (${err}) !`);
status.message = `Fail to upload backup to home assistant (${err}) !`;
statusTools.setStatus(status);
logger.error(status.message);
reject(status.message);
}); });
}); });
} }
function stopAddons() { function stopAddons() {
return new Promise(((resolve, reject) => { return new Promise(((resolve, reject) => {
logger.info('Stopping addons...') logger.info('Stopping addons...');
let status = statusTools.getStatus(); let status = statusTools.getStatus();
status.status = "stopping"; status.status = "stopping";
status.progress = -1; status.progress = -1;
@ -419,7 +386,6 @@ function stopAddons() {
status.error_code = null; status.error_code = null;
statusTools.setStatus(status); statusTools.setStatus(status);
let promises = []; let promises = [];
let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
@ -427,7 +393,7 @@ function stopAddons() {
let addons_slug = settingsTools.getSettings().auto_stop_addon let addons_slug = settingsTools.getSettings().auto_stop_addon
for (let addon of addons_slug) { for (let addon of addons_slug) {
if (addon !== "") { if (addon !== "") {
logger.debug(`... Stopping addon ${addon}`) logger.debug(`... Stopping addon ${addon}`);
promises.push(got.post(`http://hassio/addons/${addon}/stop`, option)); promises.push(got.post(`http://hassio/addons/${addon}/stop`, option));
} }
@ -439,14 +405,11 @@ function stopAddons() {
error = val.reason; error = val.reason;
if (error) { if (error) {
status.status = "error"; statusTools.setError(`Fail to stop addons(${error}) !`, 8);
status.error_code = 8;
status.message = `Fail to stop addons(${error}) !`;
statusTools.setStatus(status);
logger.error(status.message); logger.error(status.message);
reject(status.message); reject(status.message);
} else { } else {
logger.info('... Ok') logger.info('... Ok');
resolve(); resolve();
} }
}); });
@ -463,7 +426,6 @@ function startAddons() {
status.error_code = null; status.error_code = null;
statusTools.setStatus(status); statusTools.setStatus(status);
let promises = []; let promises = [];
let token = process.env.HASSIO_TOKEN;
let option = { let option = {
headers: { "Authorization": `Bearer ${token}` }, headers: { "Authorization": `Bearer ${token}` },
responseType: "json", responseType: "json",
@ -482,12 +444,7 @@ function startAddons() {
error = val.reason; error = val.reason;
if (error) { if (error) {
let status = statusTools.getStatus(); statusTools.setError(`Fail to start addons (${error}) !`, 9)
status.status = "error";
status.error_code = 9;
status.message = `Fail to start addons (${error}) !`;
statusTools.setStatus(status);
logger.error(status.message);
reject(status.message); reject(status.message);
} else { } else {
logger.info('... Ok') logger.info('... Ok')
@ -516,7 +473,6 @@ function publish_state(state){
// } // }
// let token = process.env.HASSIO_TOKEN;
// let option = { // let option = {
// headers: { "Authorization": `Bearer ${token}` }, // headers: { "Authorization": `Bearer ${token}` },
// responseType: "json", // responseType: "json",
@ -572,14 +528,16 @@ function publish_state(state){
// }); // });
} }
exports.getVersion = getVersion; export {
exports.getAddonList = getAddonList; getVersion,
exports.getFolderList = getFolderList; getAddonList,
exports.getSnapshots = getSnapshots; getFolderList,
exports.downloadSnapshot = downloadSnapshot; getSnapshots,
exports.createNewBackup = createNewBackup; downloadSnapshot,
exports.uploadSnapshot = uploadSnapshot; createNewBackup,
exports.stopAddons = stopAddons; uploadSnapshot,
exports.startAddons = startAddons; stopAddons,
exports.clean = clean; startAddons,
exports.publish_state = publish_state; clean,
publish_state
}

View File

@ -1,4 +1,4 @@
let default_root = "/Hassio Backup/"; const default_root = "/Hassio Backup/";
exports.default_root = default_root; export { default_root };
exports.manual = "Manual/"; export const manual = "Manual/";
exports.auto = "Auto/"; export const auto = "Auto/";

View File

@ -1,7 +1,8 @@
const fs = require("fs"); import fs from "fs"
const logger = require("../config/winston"); import moment from "moment";
const moment = require("moment"); import { CronJob } from "cron";
const CronJob = require("cron").CronJob;
import logger from "../config/winston.js"
const settingsPath = "/data/backup_conf.json"; const settingsPath = "/data/backup_conf.json";
@ -24,6 +25,7 @@ function check_cron(conf) {
if (conf.cron_base === "4") { if (conf.cron_base === "4") {
if (conf.cron_custom != null) { if (conf.cron_custom != null) {
try { try {
// TODO Need to be destroy
new CronJob(conf.cron_custom, () => {}); new CronJob(conf.cron_custom, () => {});
return true; return true;
} catch(e) { } catch(e) {
@ -187,8 +189,4 @@ function setSettings(settings) {
fs.writeFileSync(settingsPath, JSON.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
} }
exports.getSettings = getSettings; export { getSettings, setSettings, check, check_cron, getFormatedName };
exports.setSettings = setSettings;
exports.check = check;
exports.check_cron = check_cron;
exports.getFormatedName = getFormatedName;

View File

@ -1,49 +1,38 @@
const fs = require("fs"); import * as hassioApiTools from "./hassioApiTools.js";
const hassioApiTools = require("./hassioApiTools"); import logger from "../config/winston.js"
const statusPath = "/data/status.json";
let baseStatus = { let status = {
status: "idle", status: "idle",
last_backup: null, last_backup: null,
next_backup: null, next_backup: null,
}; };
function init() { export function init() {
if (!fs.existsSync(statusPath)) { if (status.status !== "idle") {
fs.writeFileSync(statusPath, JSON.stringify(baseStatus)); status.status = "idle";
} else { status.message = null;
let content = getStatus();
if (content.status !== "idle") {
content.status = "idle";
content.message = null;
setStatus(content);
}
} }
} }
function getStatus() { export function getStatus() {
if (!fs.existsSync(statusPath)) { return status;
fs.writeFileSync(statusPath, JSON.stringify(baseStatus));
}
return JSON.parse(fs.readFileSync(statusPath).toString());
} }
function setStatus(state) { export function setStatus(new_state) {
if (fs.existsSync(statusPath)) { let old_state_str = JSON.stringify(status);
let old_state_str = fs.readFileSync(statusPath).toString(); if(old_state_str !== JSON.stringify(new_state)){
if(old_state_str !== JSON.stringify(state)){ status = new_state;
fs.writeFileSync(statusPath, JSON.stringify(state)); hassioApiTools.publish_state(status);
hassioApiTools.publish_state(state);
} }
}else{
fs.writeFileSync(statusPath, JSON.stringify(state));
hassioApiTools.publish_state(state);
} }
export function setError(message, error_code){
// Check if we don't have another error stored
if (status.status != "error") {
status.status = "error"
status.message = message
status.error_code = error_code;
}
logger.error(message);
} }
exports.init = init;
exports.getStatus = getStatus;
exports.setStatus = setStatus;

View File

@ -18,4 +18,4 @@ function humanFileSize(bytes, si = false, dp = 1) {
return bytes.toFixed(dp) + " " + units[u]; return bytes.toFixed(dp) + " " + units[u];
} }
exports.humanFileSize = humanFileSize; export { humanFileSize } ;

View File

@ -1,20 +1,21 @@
const { createClient } = require("webdav"); import { createClient } from "webdav";
const fs = require("fs"); import fs from "fs"
const moment = require("moment"); import moment from "moment";
const https = require("https"); import https from "https"
import path from "path";
import got from "got";
import stream from "stream";
import { promisify } from "util";
import * as statusTools from "../tools/status.js"
import * as settingsTools from "../tools/settingsTools.js"
import * as pathTools from "../tools/pathTools.js"
import * as hassioApiTools from "../tools/hassioApiTools.js"
import logger from "../config/winston.js"
const statusTools = require("./status");
const endpoint = "/remote.php/webdav"; const endpoint = "/remote.php/webdav";
const configPath = "/data/webdav_conf.json"; const configPath = "/data/webdav_conf.json";
const path = require("path");
const settingsTools = require("./settingsTools");
const pathTools = require("./pathTools");
const hassioApiTools = require("./hassioApiTools");
const logger = require("../config/winston");
const got = require("got");
const stream = require("stream");
const { promisify } = require("util");
const pipeline = promisify(stream.pipeline); const pipeline = promisify(stream.pipeline);
class WebdavTools { class WebdavTools {
@ -69,12 +70,7 @@ class WebdavTools {
}); });
} }
__cant_connect_status(err){ __cant_connect_status(err){
let status = statusTools.getStatus(); statusTools.setError(`Can't connect to Nextcloud (${err})`, 3);
status.status = "error";
status.error_code = 3;
status.message = "Can't connect to Nextcloud (" + err + ") !";
statusTools.setStatus(status);
logger.error("Can't connect to Nextcloud (" + err + ") !");
} }
async __createRoot() { async __createRoot() {
@ -427,16 +423,5 @@ function cleanTempFolder() {
}); });
} }
class Singleton { const INSTANCE = new WebdavTools();
constructor() { export default INSTANCE;
if (!Singleton.instance) {
Singleton.instance = new WebdavTools();
}
}
getInstance() {
return Singleton.instance;
}
}
module.exports = Singleton;