您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

PluginLoader.ts 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import { RPCExporter } from "rpclibrary";
  2. import { Git } from "upgiter"
  3. import { FolderStatus } from "upgiter/js/src/Types";
  4. import { Plugin } from "./Plugin";
  5. import { FrontworkAdmin } from "./Admin";
  6. class PluginLoader {
  7. private runningPlugins: Plugin[]
  8. private pluginUpdaters:{[name in string]:Git.Updater} = {}
  9. constructor(private admin:FrontworkAdmin){}
  10. async selfUpdate(force:boolean = false){
  11. const updater = new Git.Updater({
  12. schema: 'https',
  13. localPath: './dist',
  14. remoteHost: 'www.versioncontrol.me',
  15. remotePath: 'frontwork-distribution',
  16. repoName: 'admin'
  17. })
  18. let status = await updater.getStatus()
  19. if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){
  20. //logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":""))
  21. status = await updater.cloneRepo(force)
  22. const installer = eval("require")("./Installer").installAdmin
  23. installer(this.getPlugins())
  24. }
  25. return status
  26. }
  27. async installPlugin(name: string, force:boolean = false):Promise<FolderStatus>{
  28. //logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":""))
  29. this.pluginUpdaters[name] = new Git.Updater({
  30. schema: 'https',
  31. localPath: './dist',
  32. remoteHost: 'www.versioncontrol.me',
  33. remotePath: 'frontwork-distribution',
  34. repoName: name
  35. })
  36. const status = await this.pluginUpdaters[name].cloneRepo(force)
  37. return status
  38. }
  39. async startPlugin(name:string):Promise<boolean>{
  40. if(!this.pluginUpdaters[name]) return false
  41. const status = await this.pluginUpdaters[name].getStatus()
  42. if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
  43. if(status.currentTag && !status.latestTag){
  44. //git glitches sometimes if you check immediately after clone
  45. //logger.warn("re-fetching tag for "+name+"...")
  46. return await this.startPlugin(name)
  47. }
  48. //logger.error("Bad repo status", name, status)
  49. return false
  50. }
  51. /* if(this.loadedPlugins[name]){
  52. logger.error("Plugin", name, "is already started")
  53. return false
  54. }
  55. */
  56. let evalstr = "../plugins/"+name+"/Plugin"
  57. const pluginClass = await eval('require')(evalstr)
  58. const pluginObj = new pluginClass.default(this)
  59. try{
  60. if(pluginObj.start)
  61. await pluginObj.start()
  62. //this.pushNotification({message: "Started plugin "+pluginObj.name, severity: "Important", topic:"admin"})
  63. this.addPlugin(pluginObj)
  64. return true
  65. }catch(e){
  66. //logger.error(e)
  67. //this.pushNotification({message: "Start of plugin "+pluginObj.name+" failed because of "+String(e), severity: "Error", topic:"admin"})
  68. return false
  69. }
  70. }
  71. async updatePlugin(name:string):Promise<boolean>{
  72. if(!this.pluginUpdaters[name]) return false
  73. const status = await this.pluginUpdaters[name].getStatus()
  74. if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
  75. //logger.error("Bad repo status", name, status)
  76. return false
  77. }
  78. if(status.currentTag == status.latestTag){
  79. //logger.warn(name, "already at latest tag")
  80. return false
  81. }
  82. /*
  83. if(this.loadedPlugins[name]){
  84. logger.error("Plugin", name, "is running. Stop it first")
  85. return false
  86. }
  87. */
  88. this.pluginUpdaters[name].checkoutTag(status.latestTag!)
  89. return true
  90. }
  91. async setPluginVersion(pluginName:string, tag:string):Promise<FolderStatus>{
  92. const status = await this.pluginUpdaters[pluginName].getStatus()
  93. if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){
  94. //logger.error("Bad repo status", pluginName, status)
  95. return status
  96. }
  97. return await this.pluginUpdaters[pluginName].checkoutTag(tag)
  98. }
  99. async addPlugin(plugin: Plugin){
  100. this.runningPlugins.push(plugin)
  101. if(plugin.getTableDefinitions().length != 0)
  102. await this.admin.makeKnex()
  103. }
  104. removePlugin(plugin: Plugin){
  105. this.runningPlugins = this.runningPlugins.filter(p => p.name !== plugin.name)
  106. }
  107. getPlugins():Plugin[]{
  108. return [...this.runningPlugins]
  109. }
  110. }
  111. export type PluginLoaderIfc = {
  112. PluginLoader: {
  113. installPlugin: (name:string, force:boolean) => Promise<FolderStatus>
  114. startPlugin: (name:string) => Promise<boolean>
  115. updatePlugin: (name:string) => Promise<boolean>
  116. setPluginVersion: (name:string, tag:string) => Promise<FolderStatus>
  117. getLoadedPluginNames: () => Promise<String[]>
  118. selfUpdate: (force:boolean) => Promise<FolderStatus>
  119. }
  120. }
  121. class RPCPluginLoader
  122. extends PluginLoader
  123. implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
  124. name = "PluginLoader" as "PluginLoader";
  125. exportRPCs(){
  126. return [{
  127. name: "installPlugin" as "installPlugin",
  128. call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
  129. },{
  130. name: "startPlugin" as "startPlugin",
  131. call: async (name:string) => {return await this.startPlugin(name)},
  132. },{
  133. name: "updatePlugin" as "updatePlugin",
  134. call: async (name:string) => {return await this.updatePlugin(name)},
  135. },{
  136. name: "setPluginVersion" as "setPluginVersion",
  137. call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
  138. },{
  139. name: "getLoadedPluginNames" as "getLoadedPluginNames",
  140. call: async () => {return this.getPlugins().map(p => p.name)},
  141. },{
  142. name: "selfUpdate" as "selfUpdate",
  143. call: async (force: boolean) => {return await this.selfUpdate(force)},
  144. }]
  145. }
  146. }