storage.js 6.1 KB

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