[Back] Add basic status

This commit is contained in:
SebClem 2024-04-18 10:47:21 +02:00
parent 1c84225111
commit eeb6f64de3
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
5 changed files with 103 additions and 52 deletions

View File

@ -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;

View 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

View File

@ -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,
}; };

View File

@ -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);
}

View File

@ -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: {
success?: boolean;
last_success?: DateTime;
message?: string;
};
next_backup?: string; next_backup?: string;
message?: string;
error_code?: number;
webdav: { webdav: {
state: WebdabStatus; logged_in: boolean;
folder_created: boolean;
last_check: DateTime; last_check: DateTime;
blocked: boolean;
}; };
} }