From 16c76b80e1b62d533d00dfbaa6e77c20d390bdb7 Mon Sep 17 00:00:00 2001 From: SebClem Date: Thu, 18 Apr 2024 10:47:21 +0200 Subject: [PATCH] [Back] Add basic status --- nextcloud_backup/backend/src/routes/apiV2.ts | 4 +- nextcloud_backup/backend/src/routes/status.ts | 12 +++ .../src/services/homeAssistantService.ts | 73 +++++++++++++++---- nextcloud_backup/backend/src/tools/status.ts | 32 +++----- nextcloud_backup/backend/src/types/status.ts | 34 +++++---- 5 files changed, 103 insertions(+), 52 deletions(-) create mode 100644 nextcloud_backup/backend/src/routes/status.ts diff --git a/nextcloud_backup/backend/src/routes/apiV2.ts b/nextcloud_backup/backend/src/routes/apiV2.ts index 600dacd..b82da05 100644 --- a/nextcloud_backup/backend/src/routes/apiV2.ts +++ b/nextcloud_backup/backend/src/routes/apiV2.ts @@ -3,6 +3,7 @@ import configRouter from "./config.js"; import homeAssistant from "./homeAssistant.js" import messageRouter from "./messages.js"; import webdavRouter from "./webdav.js"; +import statusRouter from "./status.js"; const router = express.Router(); @@ -10,6 +11,7 @@ const router = express.Router(); router.use("/homeAssistant", homeAssistant) router.use("/config", configRouter); router.use("/webdav", webdavRouter); -router.use("/messages", messageRouter) +router.use("/messages", messageRouter); +router.use('/status', statusRouter); export default router; \ No newline at end of file diff --git a/nextcloud_backup/backend/src/routes/status.ts b/nextcloud_backup/backend/src/routes/status.ts new file mode 100644 index 0000000..56307ca --- /dev/null +++ b/nextcloud_backup/backend/src/routes/status.ts @@ -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 diff --git a/nextcloud_backup/backend/src/services/homeAssistantService.ts b/nextcloud_backup/backend/src/services/homeAssistantService.ts index b53707e..6967001 100644 --- a/nextcloud_backup/backend/src/services/homeAssistantService.ts +++ b/nextcloud_backup/backend/src/services/homeAssistantService.ts @@ -1,7 +1,12 @@ import fs from "fs"; 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 { promisify } from "util"; import logger from "../config/winston.js"; @@ -18,7 +23,7 @@ import type { CoreInfoBody, SupervisorResponse, } 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); @@ -86,7 +91,6 @@ function getAddonToBackup(addons: AddonModel[]) { return slugs; } - function getFolderToBackup() { const excluded_folder = settingsTools.getSettings().exclude_folder; const all_folder = getFolderList(); @@ -126,7 +130,7 @@ function downloadSnapshot(id: string): Promise { const tmp_file = `./temp/${id}.tar`; const stream = fs.createWriteStream(tmp_file); const status = statusTools.getStatus(); - status.status = "download"; + status.status = States.BKUP_DOWNLOAD_HA; status.progress = 0; statusTools.setStatus(status); const option = { @@ -147,7 +151,9 @@ function downloadSnapshot(id: string): Promise { ).then( () => { logger.info("Download success !"); - status.progress = 1; + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; statusTools.setStatus(status); logger.debug( "Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024 @@ -160,6 +166,10 @@ function downloadSnapshot(id: string): Promise { "Fail to download Home Assistant backup", reason.message ); + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; + statusTools.setStatus(status); return Promise.reject(reason); } ); @@ -217,7 +227,7 @@ function createNewBackup( folders: string[] ) { const status = statusTools.getStatus(); - status.status = "creating"; + status.status = States.BKUP_CREATION; status.progress = -1; statusTools.setStatus(status); logger.info("Creating new snapshot..."); @@ -248,12 +258,20 @@ function createNewBackup( .then( (result) => { 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; }, (reason) => { messageManager.error("Fail to create new backup.", reason.message); logger.error("Fail to create new backup"); logger.error(reason); + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; + statusTools.setStatus(status); return Promise.reject(reason); } ); @@ -297,6 +315,7 @@ function clean(backups: BackupModel[]) { function uploadSnapshot(path: string) { return new Promise((resolve, reject) => { const status = statusTools.getStatus(); + status.status = States.BKUP_UPLOAD_HA; status.progress = 0; statusTools.setStatus(status); logger.info("Uploading backup..."); @@ -320,22 +339,36 @@ function uploadSnapshot(path: string) { logger.info("Upload done..."); } }) - .on("response", (res) => { + .on("response", (res: PlainResponse) => { 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); - reject(status.message); + reject(res.statusCode); } else { logger.info(`...Upload finish ! (status: ${res.statusCode})`); + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; + statusTools.setStatus(status); fs.unlinkSync(path); 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); messageManager.error( "Fail to upload backup to Home Assistant", - err?.message + err.message ); logger.error("Fail to upload backup to Home Assistant"); logger.error(err); @@ -346,6 +379,10 @@ function uploadSnapshot(path: string) { function stopAddons(addonSlugs: string[]) { logger.info("Stopping addons..."); + const status = statusTools.getStatus(); + status.status = States.STOP_ADDON; + status.progress = -1; + statusTools.setStatus(status); const promises = []; const option: OptionsOfJSONResponseBody = { headers: { authorization: `Bearer ${token}` }, @@ -359,11 +396,16 @@ function stopAddons(addonSlugs: string[]) { } return Promise.allSettled(promises).then((values) => { let errors = false; + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; + statusTools.setStatus(status); for (const val of values) { if (val.status == "rejected") { messageManager.error("Fail to stop addon", val.reason); logger.error("Fail to stop addon"); logger.error(val.reason); + logger.error; errors = true; } } @@ -378,7 +420,7 @@ function stopAddons(addonSlugs: string[]) { function startAddons(addonSlugs: string[]) { logger.info("Starting addons..."); const status = statusTools.getStatus(); - status.status = "starting"; + status.status = States.START_ADDON; status.progress = -1; statusTools.setStatus(status); const promises = []; @@ -393,6 +435,10 @@ function startAddons(addonSlugs: string[]) { } } return Promise.allSettled(promises).then((values) => { + const status = statusTools.getStatus(); + status.status = States.IDLE; + status.progress = undefined; + statusTools.setStatus(status); let errors = false; for (const val of values) { if (val.status == "rejected") { @@ -435,7 +481,6 @@ export function getFolderList() { ]; } - function publish_state(state: Status) { // let data_error_sensor = { // state: state.status == "error" ? "on" : "off", @@ -511,5 +556,5 @@ export { startAddons, clean, publish_state, - getBackupInfo + getBackupInfo, }; diff --git a/nextcloud_backup/backend/src/tools/status.ts b/nextcloud_backup/backend/src/tools/status.ts index 52c3f29..4bb0887 100644 --- a/nextcloud_backup/backend/src/tools/status.ts +++ b/nextcloud_backup/backend/src/tools/status.ts @@ -1,25 +1,23 @@ import { publish_state } from "../services/homeAssistantService.js"; -import logger from "../config/winston.js"; -import { type Status, WebdabStatus } from "../types/status.js"; +import { States, type Status } from "../types/status.js"; import { DateTime } from "luxon"; let status: Status = { - status: "idle", - last_backup: undefined, + status: States.IDLE, + last_backup: {}, next_backup: undefined, - progress: -1, + progress: undefined, webdav: { - state: WebdabStatus.INIT, + logged_in: false, + folder_created: false, last_check: DateTime.now(), - blocked: true, }, }; export function init() { - if (status.status !== "idle") { - status.status = "idle"; - status.message = undefined; - status.progress = -1; + if (status.status !== States.IDLE) { + status.status = States.IDLE; + status.progress = undefined; } } @@ -33,14 +31,4 @@ export function setStatus(new_state: Status) { status = new_state; 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); -} +} \ No newline at end of file diff --git a/nextcloud_backup/backend/src/types/status.ts b/nextcloud_backup/backend/src/types/status.ts index bedca6e..f3e7af8 100644 --- a/nextcloud_backup/backend/src/types/status.ts +++ b/nextcloud_backup/backend/src/types/status.ts @@ -1,24 +1,28 @@ import type { DateTime } from "luxon"; -export enum WebdabStatus { - OK = "OK", - LOGIN_FAIL = "LOGIN_FAIL", - UPLOAD_FAIL = "UPLOAD_FAIL", - CON_ERROR = "CON_ERROR", - INIT = "INIT", - MK_FOLDER_FAIL = "MK_FOLDER_FAIL" +export enum States { + IDLE = "IDLE", + BKUP_CREATION = "BKUP_CREATION", + BKUP_DOWNLOAD_HA = "BKUP_DOWNLOAD_HA", + BKUP_DOWNLOAD_CLOUD = "BKUP_DOWNLOAD_CLOUD", + BKUP_UPLOAD_HA = "BKUP_UPLOAD_HA", + BKUP_UPLOAD_CLOUD = "BKUP_UPLOAD_CLOUD", + STOP_ADDON = "STOP_ADDON", + START_ADDON = "START_ADDON", } export interface Status { - status: string; - progress: number; - last_backup?: string; + status: States; + progress?: number; + last_backup: { + success?: boolean; + last_success?: DateTime; + message?: string; + }; next_backup?: string; - message?: string; - error_code?: number; webdav: { - state: WebdabStatus; + logged_in: boolean; + folder_created: boolean; last_check: DateTime; - blocked: boolean; - }; + }; }