storage.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. const Model = require('objection').Model
  2. const path = require('path')
  3. const fs = require('fs-extra')
  4. const _ = require('lodash')
  5. const yaml = require('js-yaml')
  6. const commonHelper = require('../helpers/common')
  7. /* global WIKI */
  8. /**
  9. * Storage model
  10. */
  11. module.exports = class Storage extends Model {
  12. static get tableName() { return 'storage' }
  13. static get idColumn() { return 'id' }
  14. static get jsonSchema () {
  15. return {
  16. type: 'object',
  17. required: ['module', 'isEnabled', 'siteId'],
  18. properties: {
  19. module: {type: 'string'},
  20. isEnabled: {type: 'boolean'}
  21. }
  22. }
  23. }
  24. static get jsonAttributes() {
  25. return ['contentTypes', 'assetDelivery', 'versioning', 'schedule', 'config', 'state']
  26. }
  27. static async getTargets ({ siteId }) {
  28. return WIKI.models.storage.query().where(builder => {
  29. if (siteId) {
  30. builder.where('siteId', siteId)
  31. }
  32. })
  33. }
  34. static async refreshTargetsFromDisk () {
  35. let trx
  36. try {
  37. // -> Fetch definitions from disk
  38. const storageDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/storage'))
  39. WIKI.storage.defs = []
  40. for (const dir of storageDirs) {
  41. const def = await fs.readFile(path.join(WIKI.SERVERPATH, 'modules/storage', dir, 'definition.yml'), 'utf8')
  42. const defParsed = yaml.load(def)
  43. defParsed.key = dir
  44. defParsed.isLoaded = false
  45. WIKI.storage.defs.push(defParsed)
  46. WIKI.logger.debug(`Loaded storage module definition ${dir}: [ OK ]`)
  47. }
  48. WIKI.logger.info(`Loaded ${WIKI.storage.defs.length} storage module definitions: [ OK ]`)
  49. } catch (err) {
  50. WIKI.logger.error('Failed to scan or load new storage providers: [ FAILED ]')
  51. WIKI.logger.error(err)
  52. if (trx) {
  53. trx.rollback()
  54. }
  55. }
  56. }
  57. /**
  58. * Ensure a storage module is loaded
  59. */
  60. static async ensureModule (moduleName) {
  61. if (!_.has(WIKI.storage.modules, moduleName)) {
  62. try {
  63. WIKI.storage.modules[moduleName] = require(`../modules/storage/${moduleName}/storage`)
  64. WIKI.logger.debug(`Activated storage module ${moduleName}: [ OK ]`)
  65. return true
  66. } catch (err) {
  67. WIKI.logger.warn(`Failed to load storage module ${moduleName}: [ FAILED ]`)
  68. WIKI.logger.warn(err)
  69. return false
  70. }
  71. } else {
  72. return true
  73. }
  74. }
  75. /**
  76. * Initialize active storage targets
  77. */
  78. static async initTargets () {
  79. const dbTargets = await WIKI.models.storage.query().where('isEnabled', true)
  80. const activeModules = _.uniq(dbTargets.map(t => t.module))
  81. try {
  82. // -> Stop and delete existing jobs
  83. // const prevjobs = _.remove(WIKI.scheduler.jobs, job => job.name === 'sync-storage')
  84. // if (prevjobs.length > 0) {
  85. // prevjobs.forEach(job => job.stop())
  86. // }
  87. // -> Load active modules
  88. for (const md of activeModules) {
  89. this.ensureModule(md)
  90. }
  91. // -> Initialize targets
  92. // for (const target of this.targets) {
  93. // const targetDef = _.find(WIKI.data.storage, ['key', target.key])
  94. // target.fn = require(`../modules/storage/${target.key}/storage`)
  95. // target.fn.config = target.config
  96. // target.fn.mode = target.mode
  97. // try {
  98. // await target.fn.init()
  99. // // -> Save succeeded init state
  100. // await WIKI.models.storage.query().patch({
  101. // state: {
  102. // status: 'operational',
  103. // message: '',
  104. // lastAttempt: new Date().toISOString()
  105. // }
  106. // }).where('key', target.key)
  107. // // -> Set recurring sync job
  108. // if (targetDef.schedule && target.syncInterval !== 'P0D') {
  109. // WIKI.scheduler.registerJob({
  110. // name: 'sync-storage',
  111. // immediate: false,
  112. // schedule: target.syncInterval,
  113. // repeat: true
  114. // }, target.key)
  115. // }
  116. // // -> Set internal recurring sync job
  117. // if (targetDef.internalSchedule && targetDef.internalSchedule !== 'P0D') {
  118. // WIKI.scheduler.registerJob({
  119. // name: 'sync-storage',
  120. // immediate: false,
  121. // schedule: target.internalSchedule,
  122. // repeat: true
  123. // }, target.key)
  124. // }
  125. // } catch (err) {
  126. // // -> Save initialization error
  127. // await WIKI.models.storage.query().patch({
  128. // state: {
  129. // status: 'error',
  130. // message: err.message,
  131. // lastAttempt: new Date().toISOString()
  132. // }
  133. // }).where('key', target.key)
  134. // }
  135. // }
  136. } catch (err) {
  137. WIKI.logger.warn(err)
  138. throw err
  139. }
  140. }
  141. static async pageEvent({ event, page }) {
  142. try {
  143. for (let target of this.targets) {
  144. await target.fn[event](page)
  145. }
  146. } catch (err) {
  147. WIKI.logger.warn(err)
  148. throw err
  149. }
  150. }
  151. static async assetEvent({ event, asset }) {
  152. try {
  153. for (let target of this.targets) {
  154. await target.fn[`asset${_.capitalize(event)}`](asset)
  155. }
  156. } catch (err) {
  157. WIKI.logger.warn(err)
  158. throw err
  159. }
  160. }
  161. static async getLocalLocations({ asset }) {
  162. const locations = []
  163. const promises = this.targets.map(async (target) => {
  164. try {
  165. const path = await target.fn.getLocalLocation(asset)
  166. locations.push({
  167. path,
  168. key: target.key
  169. })
  170. } catch (err) {
  171. WIKI.logger.warn(err)
  172. }
  173. })
  174. await Promise.all(promises)
  175. return locations
  176. }
  177. static async executeAction(targetKey, handler) {
  178. try {
  179. const target = _.find(this.targets, ['key', targetKey])
  180. if (target) {
  181. if (_.hasIn(target.fn, handler)) {
  182. await target.fn[handler]()
  183. } else {
  184. throw new Error('Invalid Handler for Storage Target')
  185. }
  186. } else {
  187. throw new Error('Invalid or Inactive Storage Target')
  188. }
  189. } catch (err) {
  190. WIKI.logger.warn(err)
  191. throw err
  192. }
  193. }
  194. }