mirror of
https://github.com/Sebclem/hassio-nextcloud-backup.git
synced 2024-11-30 12:54:52 +01:00
Compare commits
7 Commits
8287bdeedc
...
ace8fe7caa
Author | SHA1 | Date | |
---|---|---|---|
ace8fe7caa | |||
9a62814c38 | |||
6f20b97488 | |||
7abd6bab8b | |||
2b639a0df5 | |||
f6db3499a4 | |||
bd444ad8d6 |
4
nextcloud_backup/backend/.vscode/launch.json
vendored
4
nextcloud_backup/backend/.vscode/launch.json
vendored
@ -12,9 +12,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"restart": true,
|
"restart": true,
|
||||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/nodemon",
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/nodemon",
|
||||||
"skipFiles": [
|
"skipFiles": ["<node_internals>/**"],
|
||||||
"<node_internals>/**"
|
|
||||||
],
|
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"preLaunchTask": "npm: build:watch"
|
"preLaunchTask": "npm: build:watch"
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ app.use(
|
|||||||
|
|
||||||
app.set("port", process.env.PORT || 3000);
|
app.set("port", process.env.PORT || 3000);
|
||||||
|
|
||||||
app.use(
|
// app.use(
|
||||||
morgan("dev", { stream: { write: (message) => logger.debug(message) } })
|
// morgan("dev", { stream: { write: (message) => logger.debug(message) } })
|
||||||
);
|
// );
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
@ -35,13 +35,14 @@ app.use("/v2/api/", apiV2Router);
|
|||||||
Error handler
|
Error handler
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
// catch 404 and forward to error handler
|
|
||||||
app.use((req, res, next) => {
|
|
||||||
next(createError(404));
|
|
||||||
});
|
|
||||||
|
|
||||||
// error handler
|
// error handler
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (app.get("env") == "development") {
|
||||||
|
// catch 404 and forward to error handler
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
next(createError(404));
|
||||||
|
});
|
||||||
|
|
||||||
// only use in development
|
// only use in development
|
||||||
app.use(errorHandler());
|
app.use(errorHandler());
|
||||||
}
|
}
|
||||||
|
@ -1,279 +0,0 @@
|
|||||||
// import express from "express";
|
|
||||||
// import * as statusTools from "../tools/status.js";
|
|
||||||
// import webdav from "../services/webdavService.js";
|
|
||||||
// import * as settingsTools from "../tools/settingsTools.js";
|
|
||||||
// import * as pathTools from "../tools/pathTools.js";
|
|
||||||
// import * as hassioApiTools from "../tools/hassioApiTools.js";
|
|
||||||
// import { humanFileSize } from "../tools/toolbox.js";
|
|
||||||
// import cronTools from "../tools/cronTools.js";
|
|
||||||
// import logger from "../config/winston.js";
|
|
||||||
// import { DateTime } from "luxon";
|
|
||||||
|
|
||||||
// const router = express.Router();
|
|
||||||
|
|
||||||
// router.get("/status", (req, res, next) => {
|
|
||||||
// cronTools.updateNextDate();
|
|
||||||
// const status = statusTools.getStatus();
|
|
||||||
// res.json(status);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.get("/formated-local-snap", function (req, res, next) {
|
|
||||||
// hassioApiTools
|
|
||||||
// .getSnapshots()
|
|
||||||
// .then((snaps) => {
|
|
||||||
// snaps.sort((a, b) => {
|
|
||||||
// return a.date < b.date ? 1 : -1;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// res.render("localSnaps", { snaps: snaps, DateTime: DateTime });
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// logger.error(err);
|
|
||||||
// res.status(500);
|
|
||||||
// res.send("");
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.get("/formated-backup-manual", function (req, res, next) {
|
|
||||||
// if (webdav.getConf() == null) {
|
|
||||||
// res.send("");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// webdav
|
|
||||||
// .getFolderContent(webdav.getConf()?.back_dir + pathTools.manual)
|
|
||||||
// .then((contents: any) => {
|
|
||||||
// contents.sort((a: any, b: any) => {
|
|
||||||
// return a.date < b.date ? 1 : -1;
|
|
||||||
// });
|
|
||||||
// //TODO Remove this when bug is fixed, etag contain '"' at start and end ?
|
|
||||||
// for (const backup of contents) {
|
|
||||||
// backup.etag = backup.etag.replace(/"/g, "");
|
|
||||||
// }
|
|
||||||
// res.render("backupSnaps", {
|
|
||||||
// backups: contents,
|
|
||||||
// DateTime: DateTime,
|
|
||||||
// humanFileSize: humanFileSize,
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// res.status(500);
|
|
||||||
// res.send(err);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.get("/formated-backup-auto", function (req, res, next) {
|
|
||||||
// if (webdav.getConf() == null) {
|
|
||||||
// res.send("");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// const url = webdav.getConf()?.back_dir + pathTools.auto;
|
|
||||||
// webdav
|
|
||||||
// .getFolderContent(url)
|
|
||||||
// .then((contents: any) => {
|
|
||||||
// contents.sort((a: any, b: any) => {
|
|
||||||
// return a.date < b.date ? 1 : -1;
|
|
||||||
// });
|
|
||||||
// //TODO Remove this when bug is fixed, etag contain '"' at start and end ?
|
|
||||||
// for (const backup of contents) {
|
|
||||||
// backup.etag = backup.etag.replace(/"/g, "");
|
|
||||||
// }
|
|
||||||
// res.render("backupSnaps", {
|
|
||||||
// backups: contents,
|
|
||||||
// DateTime: DateTime,
|
|
||||||
// humanFileSize: humanFileSize,
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// res.status(500);
|
|
||||||
// res.send(err);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/nextcloud-settings", function (req, res, next) {
|
|
||||||
// const settings = req.body;
|
|
||||||
// if (
|
|
||||||
// settings.ssl != null &&
|
|
||||||
// settings.host != null &&
|
|
||||||
// settings.host !== "" &&
|
|
||||||
// settings.username != null &&
|
|
||||||
// settings.password != null
|
|
||||||
// ) {
|
|
||||||
// webdav.setConf(settings);
|
|
||||||
// webdav
|
|
||||||
// .confIsValid()
|
|
||||||
// .then(() => {
|
|
||||||
// res.status(201);
|
|
||||||
// res.send();
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// res.status(406);
|
|
||||||
// res.json({ message: err });
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// res.status(400);
|
|
||||||
// res.send();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.get("/nextcloud-settings", function (req, res, next) {
|
|
||||||
// const conf = webdav.getConf();
|
|
||||||
// if (conf == null) {
|
|
||||||
// res.status(404);
|
|
||||||
// res.send();
|
|
||||||
// } else {
|
|
||||||
// res.json(conf);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/manual-backup", function (req, res, next) {
|
|
||||||
// const id = req.query.id;
|
|
||||||
// const name = req.query.name;
|
|
||||||
// const status = statusTools.getStatus();
|
|
||||||
// if (
|
|
||||||
// status.status == "creating" ||
|
|
||||||
// status.status == "upload" ||
|
|
||||||
// status.status == "download"
|
|
||||||
// ) {
|
|
||||||
// res.status(503);
|
|
||||||
// res.send();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// hassioApiTools
|
|
||||||
// .downloadSnapshot(id as string)
|
|
||||||
// .then(() => {
|
|
||||||
// webdav
|
|
||||||
// .uploadFile(
|
|
||||||
// id as string,
|
|
||||||
// webdav.getConf()?.back_dir + pathTools.manual + name + ".tar"
|
|
||||||
// )
|
|
||||||
// .then(() => {
|
|
||||||
// res.status(201);
|
|
||||||
// res.send();
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// res.status(500);
|
|
||||||
// res.send();
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// res.status(500);
|
|
||||||
// res.send();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/new-backup", function (req, res, next) {
|
|
||||||
// const status = statusTools.getStatus();
|
|
||||||
// if (
|
|
||||||
// status.status == "creating" ||
|
|
||||||
// status.status == "upload" ||
|
|
||||||
// status.status == "download" ||
|
|
||||||
// status.status == "stopping" ||
|
|
||||||
// status.status == "starting"
|
|
||||||
// ) {
|
|
||||||
// res.status(503);
|
|
||||||
// res.send();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// hassioApiTools
|
|
||||||
// .stopAddons()
|
|
||||||
// .then(() => {
|
|
||||||
// hassioApiTools
|
|
||||||
// .getVersion()
|
|
||||||
// .then((version) => {
|
|
||||||
// const name = settingsTools.getFormatedName(true, version);
|
|
||||||
// hassioApiTools
|
|
||||||
// .createNewBackup(name)
|
|
||||||
// .then((id) => {
|
|
||||||
// hassioApiTools
|
|
||||||
// .downloadSnapshot(id)
|
|
||||||
// .then(() => {
|
|
||||||
// webdav
|
|
||||||
// .uploadFile(
|
|
||||||
// id,
|
|
||||||
// webdav.getConf()?.back_dir +
|
|
||||||
// pathTools.manual +
|
|
||||||
// name +
|
|
||||||
// ".tar"
|
|
||||||
// )
|
|
||||||
// .then(() => {
|
|
||||||
// hassioApiTools.startAddons().catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// hassioApiTools.startAddons().catch(() => {
|
|
||||||
// // Skip
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// res.status(201);
|
|
||||||
// res.send();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.get("/backup-settings", function (req, res, next) {
|
|
||||||
// hassioApiTools.getAddonList().then((addonList) => {
|
|
||||||
// const data = {
|
|
||||||
// folder: hassioApiTools.getFolderList(),
|
|
||||||
// addonList: addonList,
|
|
||||||
// settings: settingsTools.getSettings()
|
|
||||||
// };
|
|
||||||
// res.send(data);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/backup-settings", function (req, res, next) {
|
|
||||||
// const [result, message] = settingsTools.check(req.body);
|
|
||||||
// if (result) {
|
|
||||||
// settingsTools.setSettings(req.body);
|
|
||||||
// cronTools.init();
|
|
||||||
// res.send();
|
|
||||||
// } else {
|
|
||||||
// res.status(400);
|
|
||||||
// res.send(message);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/clean-now", function (req, res, next) {
|
|
||||||
// webdav
|
|
||||||
// .clean()
|
|
||||||
// .then(() => {
|
|
||||||
// hassioApiTools.clean().catch();
|
|
||||||
// })
|
|
||||||
// .catch(() => {
|
|
||||||
// hassioApiTools.clean().catch();
|
|
||||||
// });
|
|
||||||
// res.status(201);
|
|
||||||
// res.send();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// router.post("/restore", function (req, res, next) {
|
|
||||||
// if (req.body["path"] != null) {
|
|
||||||
// webdav.downloadFile(req.body["path"]).then((path) => {
|
|
||||||
// hassioApiTools.uploadSnapshot(path).catch();
|
|
||||||
// });
|
|
||||||
// res.status(200);
|
|
||||||
// res.send();
|
|
||||||
// } else {
|
|
||||||
// res.status(400);
|
|
||||||
// res.send();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// export default router;
|
|
@ -73,17 +73,20 @@ export function doBackupWorkflow(type: WorkflowType) {
|
|||||||
if (webdavConfig.chunckedUpload) {
|
if (webdavConfig.chunckedUpload) {
|
||||||
return webDavService.chunkedUpload(
|
return webDavService.chunkedUpload(
|
||||||
tmpFile,
|
tmpFile,
|
||||||
getBackupFolder(type, webdavConfig) + name,
|
getBackupFolder(type, webdavConfig) + name + ".tar",
|
||||||
webdavConfig
|
webdavConfig
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return webDavService.webdavUploadFile(
|
return webDavService.webdavUploadFile(
|
||||||
tmpFile,
|
tmpFile,
|
||||||
getBackupFolder(type, webdavConfig) + name,
|
getBackupFolder(type, webdavConfig) + name + ".tar",
|
||||||
webdavConfig
|
webdavConfig
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.then(() => {
|
||||||
|
return homeAssistantService.startAddons(addonsToStartStop);
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info("Backup workflow finished successfully !");
|
logger.info("Backup workflow finished successfully !");
|
||||||
messageManager.info("Backup workflow finished successfully !");
|
messageManager.info("Backup workflow finished successfully !");
|
||||||
@ -104,8 +107,7 @@ export function doBackupWorkflow(type: WorkflowType) {
|
|||||||
|
|
||||||
// This methods remove addon that are no installed in HA from the conf array
|
// This methods remove addon that are no installed in HA from the conf array
|
||||||
function sanitizeAddonList(addonInConf: string[], addonInHA: AddonModel[]) {
|
function sanitizeAddonList(addonInConf: string[], addonInHA: AddonModel[]) {
|
||||||
addonInConf.filter((value) => addonInHA.some((v) => v.slug == value));
|
return addonInConf.filter((value) => addonInHA.some((v) => v.slug == value));
|
||||||
return addonInConf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAddonToBackup(excludedAddon: string[], addonInHA: AddonModel[]) {
|
function getAddonToBackup(excludedAddon: string[], addonInHA: AddonModel[]) {
|
||||||
|
@ -414,6 +414,12 @@ export async function chunkedUpload(
|
|||||||
logger.debug("Chunked upload funished, assembling chunks.");
|
logger.debug("Chunked upload funished, assembling chunks.");
|
||||||
try {
|
try {
|
||||||
await assembleChunkedUpload(chunkedUrl, finalDestination, fileSize, config);
|
await assembleChunkedUpload(chunkedUrl, finalDestination, fileSize, config);
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
|
logger.info(`...Upload finish !`);
|
||||||
|
fs.unlinkSync(localPath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof RequestError) {
|
if (err instanceof RequestError) {
|
||||||
messageManager.error(
|
messageManager.error(
|
||||||
@ -482,7 +488,7 @@ export function initChunkedUpload(
|
|||||||
finalDestination: string,
|
finalDestination: string,
|
||||||
config: WebdavConfig
|
config: WebdavConfig
|
||||||
) {
|
) {
|
||||||
logger.debug(`Init chuncked upload.`);
|
logger.info(`Init chuncked upload.`);
|
||||||
logger.debug(`...URI: ${encodeURI(url)}`);
|
logger.debug(`...URI: ${encodeURI(url)}`);
|
||||||
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
||||||
return got(encodeURI(url), {
|
return got(encodeURI(url), {
|
||||||
@ -504,7 +510,7 @@ export function assembleChunkedUpload(
|
|||||||
config: WebdavConfig
|
config: WebdavConfig
|
||||||
) {
|
) {
|
||||||
const chunckFile = `${url}/.file`;
|
const chunckFile = `${url}/.file`;
|
||||||
logger.debug(`Assemble chuncked upload.`);
|
logger.info(`Assemble chuncked upload.`);
|
||||||
logger.debug(`...URI: ${encodeURI(chunckFile)}`);
|
logger.debug(`...URI: ${encodeURI(chunckFile)}`);
|
||||||
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
||||||
return got(encodeURI(chunckFile), {
|
return got(encodeURI(chunckFile), {
|
||||||
|
@ -32,9 +32,12 @@
|
|||||||
</v-select>
|
</v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row v-if="data.webdavEndpoint.type == WebdavEndpointType.CUSTOM">
|
<div v-if="data.webdavEndpoint.type == WebdavEndpointType.CUSTOM">
|
||||||
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<div class="text-subtitle-1 text-medium-emphasis">Custom Endpoint</div>
|
<div class="text-subtitle-1 text-medium-emphasis">
|
||||||
|
Custom endpoint
|
||||||
|
</div>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
placeholder="/remote.php/dav/files/$username"
|
placeholder="/remote.php/dav/files/$username"
|
||||||
hint="You can use the $username variable"
|
hint="You can use the $username variable"
|
||||||
@ -48,10 +51,30 @@
|
|||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<div class="text-subtitle-1 text-medium-emphasis">
|
||||||
|
Custom chunk endpoint
|
||||||
|
</div>
|
||||||
|
<v-text-field
|
||||||
|
placeholder="/remote.php/dav/uploads/$username"
|
||||||
|
hint="You can use the $username variable"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
hide-details="auto"
|
||||||
|
v-model="data.webdavEndpoint.customChunkEndpoint"
|
||||||
|
:error-messages="errors.customChunkEndpoint"
|
||||||
|
:loading="loading"
|
||||||
|
color="orange"
|
||||||
|
></v-text-field>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-row class="mt-0">
|
<v-row class="mt-0">
|
||||||
<v-col class="d-flex align-content-end">
|
<v-col class="d-flex align-content-end">
|
||||||
<v-switch
|
<v-switch
|
||||||
label="Allow Self Signed Certificate"
|
label="Allow self signed certificate"
|
||||||
v-model="data.allowSelfSignedCerts"
|
v-model="data.allowSelfSignedCerts"
|
||||||
hide-details="auto"
|
hide-details="auto"
|
||||||
density="compact"
|
density="compact"
|
||||||
@ -65,7 +88,7 @@
|
|||||||
<v-row class="mt-0">
|
<v-row class="mt-0">
|
||||||
<v-col class="d-flex align-content-end">
|
<v-col class="d-flex align-content-end">
|
||||||
<v-switch
|
<v-switch
|
||||||
label="Chunked Upload (Beta)"
|
label="Chunked upload (Beta)"
|
||||||
v-model="data.chunckedUpload"
|
v-model="data.chunckedUpload"
|
||||||
hide-details="auto"
|
hide-details="auto"
|
||||||
density="compact"
|
density="compact"
|
||||||
@ -171,6 +194,7 @@ const errors = ref({
|
|||||||
allowSelfSignedCerts: [],
|
allowSelfSignedCerts: [],
|
||||||
type: [],
|
type: [],
|
||||||
customEndpoint: [],
|
customEndpoint: [],
|
||||||
|
customChunkEndpoint: [],
|
||||||
chunckedUpload: [],
|
chunckedUpload: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,5 +13,6 @@ export interface WebdavConfig {
|
|||||||
webdavEndpoint: {
|
webdavEndpoint: {
|
||||||
type: WebdavEndpointType;
|
type: WebdavEndpointType;
|
||||||
customEndpoint?: string;
|
customEndpoint?: string;
|
||||||
|
customChunkEndpoint?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user