mirror of
https://github.com/Sebclem/hassio-nextcloud-backup.git
synced 2024-11-22 09:12:58 +01:00
[Back] Add basic status
This commit is contained in:
parent
1c84225111
commit
eeb6f64de3
@ -3,6 +3,7 @@ import configRouter from "./config.js";
|
|||||||
import homeAssistant from "./homeAssistant.js"
|
import homeAssistant from "./homeAssistant.js"
|
||||||
import messageRouter from "./messages.js";
|
import messageRouter from "./messages.js";
|
||||||
import webdavRouter from "./webdav.js";
|
import webdavRouter from "./webdav.js";
|
||||||
|
import statusRouter from "./status.js";
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -10,6 +11,7 @@ const router = express.Router();
|
|||||||
router.use("/homeAssistant", homeAssistant)
|
router.use("/homeAssistant", homeAssistant)
|
||||||
router.use("/config", configRouter);
|
router.use("/config", configRouter);
|
||||||
router.use("/webdav", webdavRouter);
|
router.use("/webdav", webdavRouter);
|
||||||
router.use("/messages", messageRouter)
|
router.use("/messages", messageRouter);
|
||||||
|
router.use('/status', statusRouter);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
12
nextcloud_backup/backend/src/routes/status.ts
Normal file
12
nextcloud_backup/backend/src/routes/status.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { getStatus } from "../tools/status.js";
|
||||||
|
|
||||||
|
const statusRouter = express.Router();
|
||||||
|
|
||||||
|
|
||||||
|
statusRouter.get('/', (req, res) => {
|
||||||
|
res.json(getStatus());
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default statusRouter
|
@ -1,7 +1,12 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
import FormData from "form-data";
|
import FormData from "form-data";
|
||||||
import got, { type OptionsOfJSONResponseBody, type Response } from "got";
|
import got, {
|
||||||
|
RequestError,
|
||||||
|
type OptionsOfJSONResponseBody,
|
||||||
|
type PlainResponse,
|
||||||
|
type Response,
|
||||||
|
} from "got";
|
||||||
import stream from "stream";
|
import stream from "stream";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import logger from "../config/winston.js";
|
import logger from "../config/winston.js";
|
||||||
@ -18,7 +23,7 @@ import type {
|
|||||||
CoreInfoBody,
|
CoreInfoBody,
|
||||||
SupervisorResponse,
|
SupervisorResponse,
|
||||||
} from "../types/services/ha_os_response.js";
|
} from "../types/services/ha_os_response.js";
|
||||||
import type { Status } from "../types/status.js";
|
import { States, type Status } from "../types/status.js";
|
||||||
|
|
||||||
const pipeline = promisify(stream.pipeline);
|
const pipeline = promisify(stream.pipeline);
|
||||||
|
|
||||||
@ -86,7 +91,6 @@ function getAddonToBackup(addons: AddonModel[]) {
|
|||||||
return slugs;
|
return slugs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getFolderToBackup() {
|
function getFolderToBackup() {
|
||||||
const excluded_folder = settingsTools.getSettings().exclude_folder;
|
const excluded_folder = settingsTools.getSettings().exclude_folder;
|
||||||
const all_folder = getFolderList();
|
const all_folder = getFolderList();
|
||||||
@ -126,7 +130,7 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
const tmp_file = `./temp/${id}.tar`;
|
const tmp_file = `./temp/${id}.tar`;
|
||||||
const stream = fs.createWriteStream(tmp_file);
|
const stream = fs.createWriteStream(tmp_file);
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = "download";
|
status.status = States.BKUP_DOWNLOAD_HA;
|
||||||
status.progress = 0;
|
status.progress = 0;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
const option = {
|
const option = {
|
||||||
@ -147,7 +151,9 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
).then(
|
).then(
|
||||||
() => {
|
() => {
|
||||||
logger.info("Download success !");
|
logger.info("Download success !");
|
||||||
status.progress = 1;
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024
|
"Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024
|
||||||
@ -160,6 +166,10 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
"Fail to download Home Assistant backup",
|
"Fail to download Home Assistant backup",
|
||||||
reason.message
|
reason.message
|
||||||
);
|
);
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
return Promise.reject(reason);
|
return Promise.reject(reason);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -217,7 +227,7 @@ function createNewBackup(
|
|||||||
folders: string[]
|
folders: string[]
|
||||||
) {
|
) {
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = "creating";
|
status.status = States.BKUP_CREATION;
|
||||||
status.progress = -1;
|
status.progress = -1;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.info("Creating new snapshot...");
|
logger.info("Creating new snapshot...");
|
||||||
@ -248,12 +258,20 @@ function createNewBackup(
|
|||||||
.then(
|
.then(
|
||||||
(result) => {
|
(result) => {
|
||||||
logger.info(`Snapshot created with id ${result.body.data.slug}`);
|
logger.info(`Snapshot created with id ${result.body.data.slug}`);
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
(reason) => {
|
(reason) => {
|
||||||
messageManager.error("Fail to create new backup.", reason.message);
|
messageManager.error("Fail to create new backup.", reason.message);
|
||||||
logger.error("Fail to create new backup");
|
logger.error("Fail to create new backup");
|
||||||
logger.error(reason);
|
logger.error(reason);
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
return Promise.reject(reason);
|
return Promise.reject(reason);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -297,6 +315,7 @@ function clean(backups: BackupModel[]) {
|
|||||||
function uploadSnapshot(path: string) {
|
function uploadSnapshot(path: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.BKUP_UPLOAD_HA;
|
||||||
status.progress = 0;
|
status.progress = 0;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.info("Uploading backup...");
|
logger.info("Uploading backup...");
|
||||||
@ -320,22 +339,36 @@ function uploadSnapshot(path: string) {
|
|||||||
logger.info("Upload done...");
|
logger.info("Upload done...");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("response", (res) => {
|
.on("response", (res: PlainResponse) => {
|
||||||
if (res.statusCode !== 200) {
|
if (res.statusCode !== 200) {
|
||||||
logger.error(status.message);
|
messageManager.error(
|
||||||
|
"Fail to upload backup to Home Assistant",
|
||||||
|
`Code: ${res.statusCode} Body: ${res.body}`
|
||||||
|
);
|
||||||
|
logger.error("Fail to upload backup to Home Assistant");
|
||||||
|
logger.error(`Code: ${res.statusCode}`);
|
||||||
|
logger.error(`Body: ${res.body}`);
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
reject(status.message);
|
reject(res.statusCode);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`...Upload finish ! (status: ${res.statusCode})`);
|
logger.info(`...Upload finish ! (status: ${res.statusCode})`);
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("error", (err) => {
|
.on("error", (err: RequestError) => {
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
messageManager.error(
|
messageManager.error(
|
||||||
"Fail to upload backup to Home Assistant",
|
"Fail to upload backup to Home Assistant",
|
||||||
err?.message
|
err.message
|
||||||
);
|
);
|
||||||
logger.error("Fail to upload backup to Home Assistant");
|
logger.error("Fail to upload backup to Home Assistant");
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
@ -346,6 +379,10 @@ function uploadSnapshot(path: string) {
|
|||||||
|
|
||||||
function stopAddons(addonSlugs: string[]) {
|
function stopAddons(addonSlugs: string[]) {
|
||||||
logger.info("Stopping addons...");
|
logger.info("Stopping addons...");
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.STOP_ADDON;
|
||||||
|
status.progress = -1;
|
||||||
|
statusTools.setStatus(status);
|
||||||
const promises = [];
|
const promises = [];
|
||||||
const option: OptionsOfJSONResponseBody = {
|
const option: OptionsOfJSONResponseBody = {
|
||||||
headers: { authorization: `Bearer ${token}` },
|
headers: { authorization: `Bearer ${token}` },
|
||||||
@ -359,11 +396,16 @@ function stopAddons(addonSlugs: string[]) {
|
|||||||
}
|
}
|
||||||
return Promise.allSettled(promises).then((values) => {
|
return Promise.allSettled(promises).then((values) => {
|
||||||
let errors = false;
|
let errors = false;
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
for (const val of values) {
|
for (const val of values) {
|
||||||
if (val.status == "rejected") {
|
if (val.status == "rejected") {
|
||||||
messageManager.error("Fail to stop addon", val.reason);
|
messageManager.error("Fail to stop addon", val.reason);
|
||||||
logger.error("Fail to stop addon");
|
logger.error("Fail to stop addon");
|
||||||
logger.error(val.reason);
|
logger.error(val.reason);
|
||||||
|
logger.error;
|
||||||
errors = true;
|
errors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +420,7 @@ function stopAddons(addonSlugs: string[]) {
|
|||||||
function startAddons(addonSlugs: string[]) {
|
function startAddons(addonSlugs: string[]) {
|
||||||
logger.info("Starting addons...");
|
logger.info("Starting addons...");
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = "starting";
|
status.status = States.START_ADDON;
|
||||||
status.progress = -1;
|
status.progress = -1;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@ -393,6 +435,10 @@ function startAddons(addonSlugs: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.allSettled(promises).then((values) => {
|
return Promise.allSettled(promises).then((values) => {
|
||||||
|
const status = statusTools.getStatus();
|
||||||
|
status.status = States.IDLE;
|
||||||
|
status.progress = undefined;
|
||||||
|
statusTools.setStatus(status);
|
||||||
let errors = false;
|
let errors = false;
|
||||||
for (const val of values) {
|
for (const val of values) {
|
||||||
if (val.status == "rejected") {
|
if (val.status == "rejected") {
|
||||||
@ -435,7 +481,6 @@ export function getFolderList() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function publish_state(state: Status) {
|
function publish_state(state: Status) {
|
||||||
// let data_error_sensor = {
|
// let data_error_sensor = {
|
||||||
// state: state.status == "error" ? "on" : "off",
|
// state: state.status == "error" ? "on" : "off",
|
||||||
@ -511,5 +556,5 @@ export {
|
|||||||
startAddons,
|
startAddons,
|
||||||
clean,
|
clean,
|
||||||
publish_state,
|
publish_state,
|
||||||
getBackupInfo
|
getBackupInfo,
|
||||||
};
|
};
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
import { publish_state } from "../services/homeAssistantService.js";
|
import { publish_state } from "../services/homeAssistantService.js";
|
||||||
import logger from "../config/winston.js";
|
import { States, type Status } from "../types/status.js";
|
||||||
import { type Status, WebdabStatus } from "../types/status.js";
|
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
let status: Status = {
|
let status: Status = {
|
||||||
status: "idle",
|
status: States.IDLE,
|
||||||
last_backup: undefined,
|
last_backup: {},
|
||||||
next_backup: undefined,
|
next_backup: undefined,
|
||||||
progress: -1,
|
progress: undefined,
|
||||||
webdav: {
|
webdav: {
|
||||||
state: WebdabStatus.INIT,
|
logged_in: false,
|
||||||
|
folder_created: false,
|
||||||
last_check: DateTime.now(),
|
last_check: DateTime.now(),
|
||||||
blocked: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
if (status.status !== "idle") {
|
if (status.status !== States.IDLE) {
|
||||||
status.status = "idle";
|
status.status = States.IDLE;
|
||||||
status.message = undefined;
|
status.progress = undefined;
|
||||||
status.progress = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,13 +32,3 @@ export function setStatus(new_state: Status) {
|
|||||||
publish_state(status);
|
publish_state(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setError(message: string, error_code: number) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
@ -1,24 +1,28 @@
|
|||||||
import type { DateTime } from "luxon";
|
import type { DateTime } from "luxon";
|
||||||
|
|
||||||
export enum WebdabStatus {
|
export enum States {
|
||||||
OK = "OK",
|
IDLE = "IDLE",
|
||||||
LOGIN_FAIL = "LOGIN_FAIL",
|
BKUP_CREATION = "BKUP_CREATION",
|
||||||
UPLOAD_FAIL = "UPLOAD_FAIL",
|
BKUP_DOWNLOAD_HA = "BKUP_DOWNLOAD_HA",
|
||||||
CON_ERROR = "CON_ERROR",
|
BKUP_DOWNLOAD_CLOUD = "BKUP_DOWNLOAD_CLOUD",
|
||||||
INIT = "INIT",
|
BKUP_UPLOAD_HA = "BKUP_UPLOAD_HA",
|
||||||
MK_FOLDER_FAIL = "MK_FOLDER_FAIL"
|
BKUP_UPLOAD_CLOUD = "BKUP_UPLOAD_CLOUD",
|
||||||
|
STOP_ADDON = "STOP_ADDON",
|
||||||
|
START_ADDON = "START_ADDON",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
status: string;
|
status: States;
|
||||||
progress: number;
|
progress?: number;
|
||||||
last_backup?: string;
|
last_backup: {
|
||||||
next_backup?: string;
|
success?: boolean;
|
||||||
|
last_success?: DateTime;
|
||||||
message?: string;
|
message?: string;
|
||||||
error_code?: number;
|
};
|
||||||
|
next_backup?: string;
|
||||||
webdav: {
|
webdav: {
|
||||||
state: WebdabStatus;
|
logged_in: boolean;
|
||||||
|
folder_created: boolean;
|
||||||
last_check: DateTime;
|
last_check: DateTime;
|
||||||
blocked: boolean;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user