Browse Source

feat: storage disk - actions + daily backup

pull/821/head
Nick 5 years ago
parent
commit
e2518c7a8d
5 changed files with 79 additions and 2 deletions
  1. 1
      package.json
  2. 10
      server/models/storage.js
  3. 8
      server/modules/storage/disk/definition.yml
  4. 57
      server/modules/storage/disk/storage.js
  5. 5
      yarn.lock

1
package.json

@ -157,6 +157,7 @@
"sqlite3": "4.0.6",
"striptags": "3.1.1",
"subscriptions-transport-ws": "0.9.15",
"tar-fs": "2.0.0",
"twemoji": "11.3.0",
"uslug": "1.0.4",
"uuid": "3.3.2",

10
server/models/storage.js

@ -142,6 +142,16 @@ module.exports = class Storage extends Model {
repeat: true
}, target.key)
}
// -> Set internal recurring sync job
if (targetDef.intervalSchedule && targetDef.intervalSchedule !== `P0D`) {
WIKI.scheduler.registerJob({
name: `sync-storage`,
immediate: false,
schedule: target.intervalSchedule,
repeat: true
}, target.key)
}
} catch (err) {
// -> Save initialization error
await WIKI.models.storage.query().patch({

8
server/modules/storage/disk/definition.yml

@ -9,6 +9,7 @@ supportedModes:
- push
defaultMode: push
schedule: false
internalSchedule: P1D
props:
path:
type: String
@ -21,3 +22,10 @@ props:
title: Create Daily Backups
hint: A tar.gz archive containing all content will be created daily in subfolder named _daily. Archives are kept for a month.
order: 2
actions:
- handler: dump
label: Dump all content to disk
hint: Output all content from the DB to the local disk. If you enabled this module after content was created or you temporarily disabled this module, you'll want to execute this action to add the missing files.
- handler: backup
label: Create Backup
hint: Will create a manual backup archive at this point in time, in a subfolder named _manual, from the contents currently on disk.

57
server/modules/storage/disk/storage.js

@ -1,5 +1,15 @@
const fs = require('fs-extra')
const _ = require('lodash')
const path = require('path')
const tar = require('tar-fs')
const zlib = require('zlib')
const stream = require('stream')
const Promise = require('bluebird')
const pipeline = Promise.promisify(stream.pipeline)
const pageHelper = require('../../../helpers/page.js')
const moment = require('moment')
/* global WIKI */
/**
* Get file extension based on content type
@ -27,8 +37,25 @@ module.exports = {
await fs.ensureDir(this.config.path)
WIKI.logger.info('(STORAGE/DISK) Initialization completed.')
},
async sync() {
// not used
async sync({ manual } = { manual: false }) {
if (this.config.createDailyBackups || manual) {
const dirPath = path.join(this.config.path, manual ? '_manual' : '_daily')
await fs.ensureDir(dirPath)
const dateFilename = moment().format(manual ? 'YYYYMMDD-HHmmss' : 'DD')
WIKI.logger.info(`(STORAGE/DISK) Creating backup archive...`)
await pipeline(
tar.pack(this.config.path, {
ignore: (filePath) => {
return filePath.indexOf('_daily') >= 0 || filePath.indexOf('_manual') >= 0
}
}),
zlib.createGzip(),
fs.createWriteStream(path.join(dirPath, `wiki-${dateFilename}.tar.gz`))
)
WIKI.logger.info('(STORAGE/DISK) Backup archive created successfully.')
}
},
async created(page) {
WIKI.logger.info(`(STORAGE/DISK) Creating file ${page.path}...`)
@ -50,5 +77,31 @@ module.exports = {
const sourceFilePath = path.join(this.config.path, `${page.sourcePath}.${getFileExtension(page.contentType)}`)
const destinationFilePath = path.join(this.config.path, `${page.destinationPath}.${getFileExtension(page.contentType)}`)
await fs.move(sourceFilePath, destinationFilePath, { overwrite: true })
},
/**
* HANDLERS
*/
async dump() {
WIKI.logger.info(`(STORAGE/DISK) Dumping all content to disk...`)
await pipeline(
WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
isPrivate: false
}).stream(),
new stream.Transform({
objectMode: true,
transform: async (page, enc, cb) => {
const fileName = `${page.path}.${getFileExtension(page.contentType)}`
WIKI.logger.info(`(STORAGE/DISK) Dumping ${fileName}...`)
const filePath = path.join(this.config.path, fileName)
await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8')
cb()
}
})
)
WIKI.logger.info('(STORAGE/DISK) All content was dumped to disk successfully.')
},
async backup() {
return this.sync({ manual: true })
}
}

5
yarn.lock

@ -12438,6 +12438,11 @@ tapable@^1.0.0, tapable@^1.1.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e"
integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==
tar-js@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/tar-js/-/tar-js-0.3.0.tgz#6949aabfb0ba18bb1562ae51a439fd0f30183a17"
integrity sha1-aUmqv7C6GLsVYq5RpDn9DzAYOhc=
tar@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"

Loading…
Cancel
Save