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.

201 lines
5.9 KiB

  1. // ===========================================
  2. // Wiki.js - Background Agent
  3. // 1.0.0
  4. // Licensed under AGPLv3
  5. // ===========================================
  6. const path = require('path')
  7. const ROOTPATH = process.cwd()
  8. const SERVERPATH = path.join(ROOTPATH, 'server')
  9. global.ROOTPATH = ROOTPATH
  10. global.SERVERPATH = SERVERPATH
  11. const IS_DEBUG = process.env.NODE_ENV === 'development'
  12. let appconf = require('./libs/config')()
  13. global.appconfig = appconf.config
  14. global.appdata = appconf.data
  15. // ----------------------------------------
  16. // Load Winston
  17. // ----------------------------------------
  18. global.winston = require('./libs/logger')(IS_DEBUG, 'AGENT')
  19. // ----------------------------------------
  20. // Load global modules
  21. // ----------------------------------------
  22. winston.info('Background Agent is initializing...')
  23. global.db = require('./libs/db').init()
  24. global.upl = require('./libs/uploads-agent').init()
  25. global.git = require('./libs/git').init()
  26. global.entries = require('./libs/entries').init()
  27. global.mark = require('./libs/markdown')
  28. // ----------------------------------------
  29. // Load modules
  30. // ----------------------------------------
  31. const moment = require('moment')
  32. const Promise = require('bluebird')
  33. const fs = Promise.promisifyAll(require('fs-extra'))
  34. const klaw = require('klaw')
  35. const Cron = require('cron').CronJob
  36. const entryHelper = require('./helpers/entry')
  37. // ----------------------------------------
  38. // Start Cron
  39. // ----------------------------------------
  40. let job
  41. let jobIsBusy = false
  42. let jobUplWatchStarted = false
  43. db.onReady.then(() => {
  44. return db.Entry.remove({})
  45. }).then(() => {
  46. job = new Cron({
  47. cronTime: '0 */5 * * * *',
  48. onTick: () => {
  49. // Make sure we don't start two concurrent jobs
  50. if (jobIsBusy) {
  51. winston.warn('Previous job has not completed gracefully or is still running! Skipping for now. (This is not normal, you should investigate)')
  52. return
  53. }
  54. winston.info('Running all jobs...')
  55. jobIsBusy = true
  56. // Prepare async job collector
  57. let jobs = []
  58. let repoPath = path.resolve(ROOTPATH, appconfig.paths.repo)
  59. let dataPath = path.resolve(ROOTPATH, appconfig.paths.data)
  60. let uploadsTempPath = path.join(dataPath, 'temp-upload')
  61. // ----------------------------------------
  62. // REGULAR JOBS
  63. // ----------------------------------------
  64. //* ****************************************
  65. // -> Sync with Git remote
  66. //* ****************************************
  67. jobs.push(git.resync().then(() => {
  68. // -> Stream all documents
  69. let cacheJobs = []
  70. let jobCbStreamDocsResolve = null
  71. let jobCbStreamDocs = new Promise((resolve, reject) => {
  72. jobCbStreamDocsResolve = resolve
  73. })
  74. klaw(repoPath).on('data', function (item) {
  75. if (path.extname(item.path) === '.md' && path.basename(item.path) !== 'README.md') {
  76. let entryPath = entryHelper.parsePath(entryHelper.getEntryPathFromFullPath(item.path))
  77. let cachePath = entryHelper.getCachePath(entryPath)
  78. // -> Purge outdated cache
  79. cacheJobs.push(
  80. fs.statAsync(cachePath).then((st) => {
  81. return moment(st.mtime).isBefore(item.stats.mtime) ? 'expired' : 'active'
  82. }).catch((err) => {
  83. return (err.code !== 'EEXIST') ? err : 'new'
  84. }).then((fileStatus) => {
  85. // -> Delete expired cache file
  86. if (fileStatus === 'expired') {
  87. return fs.unlinkAsync(cachePath).return(fileStatus)
  88. }
  89. return fileStatus
  90. }).then((fileStatus) => {
  91. // -> Update cache and search index
  92. if (fileStatus !== 'active') {
  93. return entries.updateCache(entryPath).then(entry => {
  94. process.send({
  95. action: 'searchAdd',
  96. content: entry
  97. })
  98. return true
  99. })
  100. }
  101. return true
  102. })
  103. )
  104. }
  105. }).on('end', () => {
  106. jobCbStreamDocsResolve(Promise.all(cacheJobs))
  107. })
  108. return jobCbStreamDocs
  109. }))
  110. //* ****************************************
  111. // -> Clear failed temporary upload files
  112. //* ****************************************
  113. jobs.push(
  114. fs.readdirAsync(uploadsTempPath).then((ls) => {
  115. let fifteenAgo = moment().subtract(15, 'minutes')
  116. return Promise.map(ls, (f) => {
  117. return fs.statAsync(path.join(uploadsTempPath, f)).then((s) => { return { filename: f, stat: s } })
  118. }).filter((s) => { return s.stat.isFile() }).then((arrFiles) => {
  119. return Promise.map(arrFiles, (f) => {
  120. if (moment(f.stat.ctime).isBefore(fifteenAgo, 'minute')) {
  121. return fs.unlinkAsync(path.join(uploadsTempPath, f.filename))
  122. } else {
  123. return true
  124. }
  125. })
  126. })
  127. })
  128. )
  129. // ----------------------------------------
  130. // Run
  131. // ----------------------------------------
  132. Promise.all(jobs).then(() => {
  133. winston.info('All jobs completed successfully! Going to sleep for now.')
  134. if (!jobUplWatchStarted) {
  135. jobUplWatchStarted = true
  136. upl.initialScan().then(() => {
  137. job.start()
  138. })
  139. }
  140. return true
  141. }).catch((err) => {
  142. winston.error('One or more jobs have failed: ', err)
  143. }).finally(() => {
  144. jobIsBusy = false
  145. })
  146. },
  147. start: false,
  148. timeZone: 'UTC',
  149. runOnInit: true
  150. })
  151. })
  152. // ----------------------------------------
  153. // Shutdown gracefully
  154. // ----------------------------------------
  155. process.on('disconnect', () => {
  156. winston.warn('Lost connection to main server. Exiting...')
  157. job.stop()
  158. process.exit()
  159. })
  160. process.on('exit', () => {
  161. job.stop()
  162. })