david
3 years ago
commit
f979160335
9 changed files with 2738 additions and 0 deletions
@ -0,0 +1,82 @@ |
|||||||
|
import { axiosWrapper } from './axios.js'; |
||||||
|
import { exportDatabaseValidation } from './validation.js'; |
||||||
|
import fs from 'fs'; |
||||||
|
import path from 'path'; |
||||||
|
|
||||||
|
const getBackups = async () => { |
||||||
|
try { |
||||||
|
const { data } = await axiosWrapper({ |
||||||
|
method: 'get', |
||||||
|
url: '/backups/available', |
||||||
|
}); |
||||||
|
return data; |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const exportDatabase = async (tag) => { |
||||||
|
try { |
||||||
|
const { value: validValue, error } = exportDatabaseValidation({ tag }); |
||||||
|
if (error) throw error?.details[0]?.message; |
||||||
|
|
||||||
|
const { data } = await axiosWrapper({ |
||||||
|
method: 'post', |
||||||
|
url: '/backups/export/database', |
||||||
|
payload: { |
||||||
|
tag: validValue.tag, // 'Julyyy 24th 2021'
|
||||||
|
options: { |
||||||
|
recipes: true, |
||||||
|
settings: true, |
||||||
|
pages: true, |
||||||
|
themes: true, |
||||||
|
groups: true, |
||||||
|
users: true, |
||||||
|
notifications: true, |
||||||
|
}, |
||||||
|
templates: ['recipes.md'], |
||||||
|
}, |
||||||
|
}); |
||||||
|
return data; |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const getFileToken = async (filename) => { |
||||||
|
try { |
||||||
|
const { data } = await axiosWrapper({ |
||||||
|
method: 'get', |
||||||
|
url: `/backups/${filename}/download`, |
||||||
|
}); |
||||||
|
return data; |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const downloadBackup = async (fileToken, fileName) => { |
||||||
|
try { |
||||||
|
const target_path = path.resolve(`backups/${fileName}`); |
||||||
|
const writer = fs.createWriteStream(target_path, 'binary'); |
||||||
|
const streamResponse = await axiosWrapper({ |
||||||
|
method: 'get', |
||||||
|
url: `/utils/download?token=${fileToken}`, |
||||||
|
responseType: 'stream', |
||||||
|
}); |
||||||
|
streamResponse.data.pipe(writer); |
||||||
|
writer.on('finish', () => console.log(`Downloaded: ${fileName}`)); |
||||||
|
writer.on('error', () => |
||||||
|
console.error(`[ERROR] while dowloading ${fileName}`) |
||||||
|
); |
||||||
|
return true; |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
export { getBackups, exportDatabase, getFileToken, downloadBackup }; |
@ -0,0 +1,26 @@ |
|||||||
|
import axios from 'axios'; |
||||||
|
import dotenv from 'dotenv'; |
||||||
|
dotenv.config(); |
||||||
|
const { BASE_URL, TOKEN } = process.env; |
||||||
|
|
||||||
|
const config = { |
||||||
|
baseURL: BASE_URL, |
||||||
|
headers: { authorization: `Bearer ${TOKEN}` }, |
||||||
|
}; |
||||||
|
|
||||||
|
const axiosWrapper = async ({ method, url, payload, responseType }) => { |
||||||
|
try { |
||||||
|
return await axios({ |
||||||
|
method, |
||||||
|
url, |
||||||
|
...config, |
||||||
|
data: { ...payload }, |
||||||
|
responseType, |
||||||
|
}); |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
export { axiosWrapper }; |
@ -0,0 +1,15 @@ |
|||||||
|
import dayjs from 'dayjs'; |
||||||
|
|
||||||
|
const backupTimeDiff = (lastDate) => { |
||||||
|
try { |
||||||
|
const now = dayjs(); |
||||||
|
const last = dayjs(lastDate); |
||||||
|
const difference = now.diff(last, 'seconds'); |
||||||
|
return difference; |
||||||
|
} catch (error) { |
||||||
|
console.error(error); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
export { backupTimeDiff }; |
@ -0,0 +1,39 @@ |
|||||||
|
import dotenv from 'dotenv'; |
||||||
|
dotenv.config(); |
||||||
|
import { environmentVariableValidation } from './validation.js'; |
||||||
|
import { |
||||||
|
getBackups, |
||||||
|
exportDatabase, |
||||||
|
getFileToken, |
||||||
|
downloadBackup, |
||||||
|
} from './apiHelper.js'; |
||||||
|
import { backupTimeDiff } from './backupHelper.js'; |
||||||
|
|
||||||
|
const { value, error } = environmentVariableValidation({ |
||||||
|
baseUrl: process.env.BASE_URL, |
||||||
|
access_token: process.env.TOKEN, |
||||||
|
}); |
||||||
|
|
||||||
|
try { |
||||||
|
if (error) throw error?.details[0]?.message; |
||||||
|
} catch (error) { |
||||||
|
console.error(`[ERROR] ${error}`); |
||||||
|
process.exit(0); |
||||||
|
} |
||||||
|
|
||||||
|
const Main = async () => { |
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000)); |
||||||
|
const backups = await getBackups(); |
||||||
|
const [lastBackup] = backups?.imports; |
||||||
|
const secondsDiff = backupTimeDiff(lastBackup?.date); |
||||||
|
// TODO: actually make this timer like idk 1 day or something
|
||||||
|
if (secondsDiff >= 20) { |
||||||
|
const { export_path } = await exportDatabase('mealieDb'); |
||||||
|
console.log(`database backed up: ${export_path}`); |
||||||
|
const { fileToken } = await getFileToken(lastBackup?.name); |
||||||
|
await downloadBackup(fileToken, lastBackup?.name); |
||||||
|
} |
||||||
|
await Main(secondsDiff); |
||||||
|
}; |
||||||
|
|
||||||
|
Main(); |
@ -0,0 +1,21 @@ |
|||||||
|
{ |
||||||
|
"name": "mealiebackupservice", |
||||||
|
"version": "1.0.0", |
||||||
|
"description": "", |
||||||
|
"main": "index.js", |
||||||
|
"type": "module", |
||||||
|
"scripts": { |
||||||
|
"test": "echo \"Error: no test specified\" && exit 1" |
||||||
|
}, |
||||||
|
"author": "", |
||||||
|
"license": "ISC", |
||||||
|
"dependencies": { |
||||||
|
"axios": "^0.21.4", |
||||||
|
"dayjs": "^1.10.7", |
||||||
|
"dotenv": "^10.0.0", |
||||||
|
"joi": "^17.4.2" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"nodemon": "^2.0.13" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
import Joi from 'joi'; |
||||||
|
|
||||||
|
const environmentVariableValidation = (data) => { |
||||||
|
const schmea = Joi.object({ |
||||||
|
baseUrl: Joi.string().uri().required(), |
||||||
|
access_token: Joi.string().required(), |
||||||
|
}); |
||||||
|
return schmea.validate(data); |
||||||
|
}; |
||||||
|
|
||||||
|
const exportDatabaseValidation = (tag) => { |
||||||
|
const schema = Joi.object({ |
||||||
|
tag: Joi.string().required().trim(), |
||||||
|
}); |
||||||
|
return schema.validate(tag); |
||||||
|
}; |
||||||
|
|
||||||
|
export { environmentVariableValidation, exportDatabaseValidation }; |
Loading…
Reference in new issue