add PluginLoader

This commit is contained in:
peter
2019-10-30 18:48:03 +01:00
parent f0104e8665
commit fd324300ea
2 changed files with 165 additions and 11 deletions
+1 -1
View File
@@ -134,7 +134,7 @@ implements TableDefinitionExporter {
logger.info("Webserver stopped") logger.info("Webserver stopped")
} }
protected async makeKnex():Promise<Knex>{ public async makeKnex():Promise<Knex>{
const conf:Knex.Config = this.config.getConfigKey("dbConf") const conf:Knex.Config = this.config.getConfigKey("dbConf")
logger.debug("Making new knex:", conf) logger.debug("Making new knex:", conf)
+164 -10
View File
@@ -1,19 +1,173 @@
import { RPCExporter } from "rpclibrary/js/src/Interfaces"; import { RPCExporter } from "rpclibrary/js/src/Interfaces";
import { Git, Types } from "upgiter" import { Git } from "upgiter"
import { FolderStatus } from "upgiter/js/src/Types";
import { Plugin } from "./Plugin";
import { FrontworkAdmin } from "./Admin";
export type GitUpdaterIfc = { export type PluginLoaderIfc = {
cloneRepo: (force:boolean) => Promise<Types.FolderStatus> PluginLoader: {
getStatus: () => Promise<Types.FolderStatus> installPlugin: (name:string, force:boolean) => Promise<FolderStatus>
checkoutTag: (tag:string) => Promise<Types.FolderStatus> startPlugin: (name:string) => Promise<boolean>
isOutdated: () => Promise<boolean> updatePlugin: (name:string) => Promise<boolean>
setPluginVersion: (name:string, tag:string) => Promise<FolderStatus>
getLoadedPluginNames: () => Promise<String[]>
selfUpdate: (force:boolean) => Promise<FolderStatus>
destroy: () => Promise<void>
}
} }
class RPCUpgiter class PluginLoader
extends Git.Updater implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
implements RPCExporter<any, "PluginLoader">{
name = "PluginLoader" as "PluginLoader"; name = "PluginLoader" as "PluginLoader";
private runningPlugins: Plugin[]
private pluginUpdaters:{[name in string]:Git.Updater} = {}
constructor(private admin:FrontworkAdmin){}
private 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)
//this.destroy()
const installer = eval("require")("./Installer").installAdmin
installer(this.getPlugins())
}
return status
}
async installPlugin(name: string, force:boolean = false):Promise<FolderStatus>{
//logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":""))
this.pluginUpdaters[name] = new Git.Updater({
schema: 'https',
localPath: './dist',
remoteHost: 'www.versioncontrol.me',
remotePath: 'frontwork-distribution',
repoName: name
})
//new GitUpdater("./plugins/"+name)
const status = await this.pluginUpdaters[name].cloneRepo(force)
return status
}
async startPlugin(name:string):Promise<boolean>{
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 str = "../plugins/"+name+"/Plugin"
const pluginClass = await eval('require')(str)
const pluginObj = new pluginClass.default(this)
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<boolean>{
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<FolderStatus>{
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]
}
private async destroy(){
return
}
exportRPCs(){ exportRPCs(){
return [] return [{
name: "installPlugin" as "installPlugin",
call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
},{
name: "startPlugin" as "startPlugin",
call: async (name:string) => {return await this.startPlugin(name)},
},{
name: "updatePlugin" as "updatePlugin",
call: async (name:string) => {return await this.updatePlugin(name)},
},{
name: "setPluginVersion" as "setPluginVersion",
call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
},{
name: "getLoadedPluginNames" as "getLoadedPluginNames",
call: async () => {return this.getPlugins().map(p => p.name)},
},{
name: "selfUpdate" as "selfUpdate",
call: async (force: boolean) => {return await this.selfUpdate(force)},
},{
name: "destroy" as "destroy",
call: async () => {return this.destroy()}
}]
} }
} }