import { RPCExporter } from "rpclibrary"; import { Git } from "upgiter" import { FolderStatus } from "upgiter/js/src/Types"; import { Plugin } from "../Types/Plugin"; import { FrontworkAdmin } from "../Admin/Admin"; class PluginLoader { private runningPlugins: Plugin[] = [] private pluginUpdaters:{[name in string]:Git.Updater} = {} constructor(private admin:FrontworkAdmin){} async selfUpdate(force:boolean = false){ const updater = new Git.Updater({ schema: 'https', localPath: './dist', remoteHost: 'www.versioncontrol.me', remotePath: 'frontwork-distribution', repoName: 'admin' }) let status = await updater.getStatus() if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){ //logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":"")) status = await updater.cloneRepo(force) const installer = eval("require")("./Installer").installAdmin installer(this.getPlugins()) } return status } async installPlugin(name: string, force:boolean = false):Promise{ //logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":"")) this.pluginUpdaters[name] = new Git.Updater({ schema: 'https', localPath: './plugins/'+name, remoteHost: 'www.versioncontrol.me', remotePath: 'frontblock-distribution', repoName: name }) const status = await this.pluginUpdaters[name].cloneRepo(force) return status } async startPlugin(name:string):Promise{ if(!this.pluginUpdaters[name]) return false const status = await this.pluginUpdaters[name].getStatus() if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ if(status.currentTag && !status.latestTag){ //git glitches sometimes if you check immediately after clone //logger.warn("re-fetching tag for "+name+"...") return await this.startPlugin(name) } //logger.error("Bad repo status", name, status) return false } /* if(this.loadedPlugins[name]){ logger.error("Plugin", name, "is already started") return false } */ let evalstr = "../plugins/"+name+"/Plugin" const pluginClass = await eval('require')(evalstr) const pluginObj = new pluginClass.default(this.admin) try{ if(pluginObj.start) await pluginObj.start() //this.pushNotification({message: "Started plugin "+pluginObj.name, severity: "Important", topic:"admin"}) this.addPlugin(pluginObj) return true }catch(e){ //logger.error(e) //this.pushNotification({message: "Start of plugin "+pluginObj.name+" failed because of "+String(e), severity: "Error", topic:"admin"}) return false } } async updatePlugin(name:string):Promise{ if(!this.pluginUpdaters[name]) return false const status = await this.pluginUpdaters[name].getStatus() if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ //logger.error("Bad repo status", name, status) return false } if(status.currentTag == status.latestTag){ //logger.warn(name, "already at latest tag") return false } /* if(this.loadedPlugins[name]){ logger.error("Plugin", name, "is running. Stop it first") return false } */ this.pluginUpdaters[name].checkoutTag(status.latestTag!) return true } async setPluginVersion(pluginName:string, tag:string):Promise{ const status = await this.pluginUpdaters[pluginName].getStatus() if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){ //logger.error("Bad repo status", pluginName, status) return status } return await this.pluginUpdaters[pluginName].checkoutTag(tag) } async addPlugin(plugin: Plugin){ this.runningPlugins.push(plugin) if(plugin.getTableDefinitions().length != 0) await this.admin.makeKnex() } removePlugin(plugin: Plugin){ this.runningPlugins = this.runningPlugins.filter(p => p.name !== plugin.name) } getPlugins():Plugin[]{ return [...this.runningPlugins] } } export type PluginLoaderIfc = { PluginLoader: { installPlugin: (name:string, force:boolean) => Promise startPlugin: (name:string) => Promise updatePlugin: (name:string) => Promise setPluginVersion: (name:string, tag:string) => Promise getLoadedPluginNames: () => Promise selfUpdate: (force:boolean) => Promise } } export class RPCPluginLoader extends PluginLoader implements RPCExporter{ name = "PluginLoader" as "PluginLoader"; exportRPCs(){ return [{ name: "installPlugin" as "installPlugin", call: this.installPlugin, },{ name: "startPlugin" as "startPlugin", call: this.startPlugin, },{ name: "updatePlugin" as "updatePlugin", call: this.updatePlugin, },{ name: "setPluginVersion" as "setPluginVersion", call: this.setPluginVersion, },{ name: "getLoadedPluginNames" as "getLoadedPluginNames", call: async () => this.getPlugins().map(p => p.name), },{ name: "selfUpdate" as "selfUpdate", call: this.selfUpdate, }] } }