You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.7 KiB

  1. const fs = require('fs-extra')
  2. const _ = require('lodash')
  3. const path = require('path')
  4. const tar = require('tar-fs')
  5. const zlib = require('zlib')
  6. const stream = require('stream')
  7. const Promise = require('bluebird')
  8. const pipeline = Promise.promisify(stream.pipeline)
  9. const pageHelper = require('../../../helpers/page.js')
  10. const moment = require('moment')
  11. /* global WIKI */
  12. /**
  13. * Get file extension based on content type
  14. */
  15. const getFileExtension = (contentType) => {
  16. switch (contentType) {
  17. case 'markdown':
  18. return 'md'
  19. case 'html':
  20. return 'html'
  21. default:
  22. return 'txt'
  23. }
  24. }
  25. module.exports = {
  26. async activated() {
  27. // not used
  28. },
  29. async deactivated() {
  30. // not used
  31. },
  32. async init() {
  33. WIKI.logger.info('(STORAGE/DISK) Initializing...')
  34. await fs.ensureDir(this.config.path)
  35. WIKI.logger.info('(STORAGE/DISK) Initialization completed.')
  36. },
  37. async sync({ manual } = { manual: false }) {
  38. if (this.config.createDailyBackups || manual) {
  39. const dirPath = path.join(this.config.path, manual ? '_manual' : '_daily')
  40. await fs.ensureDir(dirPath)
  41. const dateFilename = moment().format(manual ? 'YYYYMMDD-HHmmss' : 'DD')
  42. WIKI.logger.info(`(STORAGE/DISK) Creating backup archive...`)
  43. await pipeline(
  44. tar.pack(this.config.path, {
  45. ignore: (filePath) => {
  46. return filePath.indexOf('_daily') >= 0 || filePath.indexOf('_manual') >= 0
  47. }
  48. }),
  49. zlib.createGzip(),
  50. fs.createWriteStream(path.join(dirPath, `wiki-${dateFilename}.tar.gz`))
  51. )
  52. WIKI.logger.info('(STORAGE/DISK) Backup archive created successfully.')
  53. }
  54. },
  55. async created(page) {
  56. WIKI.logger.info(`(STORAGE/DISK) Creating file ${page.path}...`)
  57. const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`)
  58. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  59. },
  60. async updated(page) {
  61. WIKI.logger.info(`(STORAGE/DISK) Updating file ${page.path}...`)
  62. const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`)
  63. await fs.outputFile(filePath, page.injectMetadata(), 'utf8')
  64. },
  65. async deleted(page) {
  66. WIKI.logger.info(`(STORAGE/DISK) Deleting file ${page.path}...`)
  67. const filePath = path.join(this.config.path, `${page.path}.${getFileExtension(page.contentType)}`)
  68. await fs.unlink(filePath)
  69. },
  70. async renamed(page) {
  71. WIKI.logger.info(`(STORAGE/DISK) Renaming file ${page.sourcePath} to ${page.destinationPath}...`)
  72. const sourceFilePath = path.join(this.config.path, `${page.sourcePath}.${getFileExtension(page.contentType)}`)
  73. const destinationFilePath = path.join(this.config.path, `${page.destinationPath}.${getFileExtension(page.contentType)}`)
  74. await fs.move(sourceFilePath, destinationFilePath, { overwrite: true })
  75. },
  76. /**
  77. * HANDLERS
  78. */
  79. async dump() {
  80. WIKI.logger.info(`(STORAGE/DISK) Dumping all content to disk...`)
  81. await pipeline(
  82. WIKI.models.knex.column('path', 'localeCode', 'title', 'description', 'contentType', 'content', 'isPublished', 'updatedAt').select().from('pages').where({
  83. isPrivate: false
  84. }).stream(),
  85. new stream.Transform({
  86. objectMode: true,
  87. transform: async (page, enc, cb) => {
  88. const fileName = `${page.path}.${getFileExtension(page.contentType)}`
  89. WIKI.logger.info(`(STORAGE/DISK) Dumping ${fileName}...`)
  90. const filePath = path.join(this.config.path, fileName)
  91. await fs.outputFile(filePath, pageHelper.injectPageMetadata(page), 'utf8')
  92. cb()
  93. }
  94. })
  95. )
  96. WIKI.logger.info('(STORAGE/DISK) All content was dumped to disk successfully.')
  97. },
  98. async backup() {
  99. return this.sync({ manual: true })
  100. }
  101. }