diff --git a/src/backend/Admin.ts b/src/backend/Admin.ts index 6effa21..b99d223 100644 --- a/src/backend/Admin.ts +++ b/src/backend/Admin.ts @@ -7,8 +7,7 @@ import { AdminBase } from 'frontblock-generic/Admin'; import { FrontblockApi } from 'frontblock-generic/Api'; import { Plugin } from 'frontblock-generic/Plugin'; import { socketioRPC } from 'frontblock-generic/RPC'; -import { GitUpdater } from './GitUpdater'; -import { UpdateManager } from './UpdateManger'; +import { GitUpdater, RepoFolderStatus } from './GitUpdater'; Logger.configure({ appenders: @@ -28,9 +27,10 @@ export type AdminConf = { httpPort: number} export class FrontblockAdmin extends AdminBase{ + private pluginUpdaters:{[name in string]:GitUpdater} = {} + constructor(runningPlugins: Plugin[] = []){ super(runningPlugins) - this.addPlugin(new UpdateManager(this)) } getDefaultConfig(): { apiConf: FrontblockApiConf; } & AdminConf & { dbConf:Knex.Config; } { @@ -66,6 +66,31 @@ export class FrontblockAdmin extends AdminBase{ return [ ...super.exportRPCs(), { + name: 'installPlugin', + func: async (name:string, force = false) => {return await this.installPlugin(name, force)}, + type: 'call', + visibility: 'private' + },{ + name: 'startPlugin', + func: async (name:string) => {return await this.startPlugin(name)}, + type: 'call', + visibility: 'private' + },{ + name: 'updatePlugin', + func: async (name) => {return await this.updatePlugin(name)}, + type: 'call', + visibility: 'private' + },{ + name: 'setPluginVersion', + func: async (name, tag) => {return await this.setPluginVersion(name, tag)}, + type: 'call', + visibility: 'private' + },{ + name: 'getLoadedPluginNames', + func: async () => {return await this.getPlugins().map(p => p.name)}, + type: 'call', + visibility: 'private' + },{ name: 'selfUpdate', type:'call', func: async (force: boolean) => {return await this.selfUpdate(force)}, @@ -87,6 +112,73 @@ export class FrontblockAdmin extends AdminBase{ } 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 GitUpdater("./plugins/"+name) + const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", 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 str = "../plugins/"+name+"/Plugin" + const pluginClass = await eval('require')(str) + const pluginObj = new pluginClass.default() + await pluginObj.start() + this.addPlugin(pluginObj) + return true + } + + 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) + } } process.on( 'SIGINT', function() { diff --git a/src/backend/FrontblockLib.ts b/src/backend/FrontblockLib.ts index 7b00b5e..3168208 100644 --- a/src/backend/FrontblockLib.ts +++ b/src/backend/FrontblockLib.ts @@ -89,20 +89,20 @@ export class FrontblockConfigLib{ } window['fb'] = new FrontblockConfigLib() -declare const fb:{UpdateManager:any} +declare const fb:{Admin:any} window['setup'] = async() => { const i = await Promise.all([ - fb.UpdateManager.installPlugin("ApiClient"), - fb.UpdateManager.installPlugin("HtmlSupplier"), - fb.UpdateManager.installPlugin("PaymentManager"), - fb.UpdateManager.installPlugin("Wallet"), + fb.Admin.installPlugin("ApiClient"), + fb.Admin.installPlugin("HtmlSupplier"), + fb.Admin.installPlugin("PaymentManager"), + fb.Admin.installPlugin("Wallet"), ]) console.log(i) const s = await Promise.all([ - fb.UpdateManager.startPlugin("ApiClient"), - fb.UpdateManager.startPlugin("HtmlSupplier"), - fb.UpdateManager.startPlugin("PaymentManager"), - fb.UpdateManager.startPlugin("Wallet"), + fb.Admin.startPlugin("ApiClient"), + fb.Admin.startPlugin("HtmlSupplier"), + fb.Admin.startPlugin("PaymentManager"), + fb.Admin.startPlugin("Wallet"), ]) if(s.reduce((p,c) => p && c), true) location.reload(); diff --git a/src/backend/UpdateManger.ts b/src/backend/UpdateManger.ts deleted file mode 100644 index 1868e73..0000000 --- a/src/backend/UpdateManger.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { Plugin } from "frontblock-generic/Plugin"; -import { socketioRPC } from "frontblock-generic/RPC"; -import { GitUpdater, RepoFolderStatus } from "./GitUpdater"; -import { FrontblockCherryPicker } from "git-cherrypicker"; -import * as Logger from 'log4js' -import { FrontblockAdmin } from "./Admin"; -import { TableDefiniton } from "frontblock-generic/Admin"; - -Logger.configure({ - appenders: - { - "admin/updatemanager": { type: 'stdout' }, - //app: { type: 'file', filename: 'application.log' } - }, - categories: - { - default: { appenders: [ 'admin/updatemanager' ], level: 'debug' } - } -}) -const logger = Logger.getLogger("admin/updatemanager") - -export class UpdateManager extends Plugin{ - - private loadedPlugins:{[name in string]:Plugin} = {} - private dashboardUpdater:GitUpdater - private adminUpdater:GitUpdater - private pluginUpdaters:{[name in string]:GitUpdater} = {} - - constructor(admin:FrontblockAdmin){ - super(admin, "UpdateManager") - } - - getDefaultConfig(): {} { - return {} - } - - exportRPCs(): socketioRPC[] { - return [{ - name: 'installPlugin', - func: async (name:string, force = false) => {return await this.installPlugin(name, force)}, - type: 'call', - visibility: 'private' - },{ - name: 'startPlugin', - func: async (name:string) => {return await this.startPlugin(name)}, - type: 'call', - visibility: 'private' - },{ - name: 'updatePlugin', - func: async (name) => {return await this.updatePlugin(name)}, - type: 'call', - visibility: 'private' - },{ - name: 'setPluginVersion', - func: async (name, tag) => {return await this.setPluginVersion(name, tag)}, - type: 'call', - visibility: 'private' - },{ - name: 'getLoadedPluginNames', - func: async () => {return await this.getLoadedPluginNames()}, - type: 'call', - visibility: 'private' - }] - } - - getTableDefinitions(): TableDefiniton[] { - return [] - } - - 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 GitUpdater("./plugins/"+name) - const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", 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 str = "../plugins/"+name+"/Plugin" - const pluginClass = await eval('require')(str) - const pluginObj = new pluginClass.default() - await pluginObj.start() - this.admin.addPlugin(pluginObj) - this.loadedPlugins[name] = pluginObj - return true - } - - 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) - } - - getLoadedPlugins():Plugin[]{ - return Object.values(this.loadedPlugins) - } - - getLoadedPluginNames():string[]{ - return Object.keys(this.loadedPlugins) - } -} \ No newline at end of file diff --git a/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts b/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts index c50df45..484bbd8 100644 --- a/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts +++ b/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts @@ -52,7 +52,7 @@ import { FrontendPlugin, SidebarEntries, SidebarEntry } from "frontblock-generic import { environment } from "../../environments/environment" const fb = environment.production ? window["fb"] : { - UpdateManager: { + Admin: { getLoadedPluginNames: () => ["ApiClient", "Wallet"] } } @@ -78,10 +78,10 @@ export class DynamicLoaderComponent implements AfterViewInit { } private async loadWidgets() { - while (!fb.UpdateManager) { + while (!fb.Admin) { await new Promise((resolve) => setTimeout(resolve, 50)) } - const pluginNames = await fb.UpdateManager.getLoadedPluginNames() + const pluginNames = await fb.Admin.getLoadedPluginNames() pluginNames.forEach(element => this.installWidget(element)); }