diff --git a/src/backend/PluginManager/Plugin.ts b/src/backend/PluginManager/Plugin.ts deleted file mode 100644 index 36e611a..0000000 --- a/src/backend/PluginManager/Plugin.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { default as PluginManager } from "./PluginManager"; -import { Plugin, socketioRPC } from "frontblock-generic/Plugin"; -import * as Logger from 'log4js'; - -Logger.configure({ - appenders: - { - "PluginManager/Plugin": { type: 'stdout' }, - //app: { type: 'file', filename: 'application.log' } - }, - categories: - { - default: { appenders: [ 'PluginManager/Plugin' ], level: 'debug' } - } -}) -const logger = Logger.getLogger("PluginManager/Plugin") - - -export default class PluginManagerPlugin extends PluginManager implements Plugin{ - - constructor(){ - super() - - this.loadedPlugins[this.name] = {backend: this, frontend: this.loadFrontend(this.name)} - } - - exportExtraRPCs(): socketioRPC[] { - return [ - { - name: "getAvailablePluginNames", - visibility: "private", - rpc: async() => { return await this.getAvailablePluginNames() }, - type: 'call' - }, - { - name: "getInstalledPluginNames", - visibility: "private", - rpc: async() => { return await this.getInstalledPluginNames() }, - type: 'call' - }, - { - name: "getLoadedPluginNames", - visibility: "private", - rpc: async () => { return this.getLoadedPluginNames() }, - type: 'call' - },{ - name: "installPlugin", - visibility: "private", - rpc: async(pluginName:string) => { return await this.installPlugin(pluginName) }, - type: 'call' - }, - { - name: "uninstallPlugin", - visibility: "private", - rpc: async(pluginName:string) => { return await this.uninstallPlugin(pluginName) }, - type: 'call' - }, - { - name: "loadPlugin", - visibility: "private", - rpc: async(pluginName:string) => { return await this.loadPlugin(pluginName) }, - type: 'call' - }, - { - name: "unloadPlugin", - visibility: "private", - rpc: async(pluginName:string) => { return this.unloadPlugin(pluginName) }, - type: 'call' - },{ - name: "extractPlugin", - visibility: "private", - rpc: async(conf) => { return this.extractPlugin(conf) }, - type: 'call' - },{ - name: "downloadPlugin", - visibility: "private", - rpc: async(conf) => { return this.downloadPlugin(conf) }, - type: 'call' - },{ - name: "getConfig", - visibility: "private", - rpc: async() => { return this.conf }, - type: 'call' - } - ] - } - - async start(): Promise { - await Promise.all(this.getInstalledPluginNames().map(name => { - if(name == this.name) return - return this.loadPlugin(name) - })); - } - - stop(): void { - - } -} \ No newline at end of file diff --git a/src/backend/PluginManager/PluginManager.ts b/src/backend/PluginManager/PluginManager.ts deleted file mode 100644 index 62582a8..0000000 --- a/src/backend/PluginManager/PluginManager.ts +++ /dev/null @@ -1,229 +0,0 @@ -'use strict' - -import * as Logger from 'log4js'; -import fetch = require('node-fetch'); -import fs = require('fs'); -import path = require('path') -import unzip = require('unzip') -import easyunzip = require('easy-unzip') - -import { Plugin, ConfigLoader, PluginConfigLoader } from 'frontblock-generic/Plugin'; -import { SemVer, parse } from "semver"; -import { once } from 'events'; - -Logger.configure({ - appenders: - { - "PluginManager": { type: 'stdout' }, - //app: { type: 'file', filename: 'application.log' } - }, - categories: - { - default: { appenders: [ 'PluginManager' ], level: 'debug' } - } -}) -const logger = Logger.getLogger("PluginManager") -const AdmZip = require('adm-zip'); - -type PluginVersion = { - installed?: SemVer, - cached?: SemVer, -} -export type PluginVersioning = { - [pluginName in string]?: PluginVersion | string -} -export type PluginMap = {[pluginName:string]: {backend: Plugin, frontend:any}} - -export type PluginManagerConfig = { - resourceLocation: string, - installDir:string -} - -export default abstract class PluginManager extends PluginConfigLoader{ - - private cacheDir: string - protected loadedPlugins: PluginMap = {} - - constructor(){ - super("PluginManager") - this.cacheDir = path.join(this.conf.installDir, '.cache') - this.initialize() - } - - getDefaultConfig(): PluginManagerConfig&PluginVersioning{ - return {resourceLocation: "https://gitea.frontblock.me/api/v1/repos/fb-vendor/", installDir: "plugins"} - } - - - private initialize() { - logger.info('Initializing manager') - - try { - fs.accessSync(this.cacheDir) - logger.info('Manager already installed at ' + this.conf.installDir) - } catch (error) { - fs.mkdirSync(this.cacheDir, {recursive: true}) - logger.info('Manager installed to ' + this.cacheDir) - } - } - - - public async getAvailablePluginNames(): Promise { - //TODO query api - return [ - 'apiclient', - 'paymentmanager', - 'wallet', - 'htmlsupplier' - ] - } - - public getInstalledPluginNames():string[] { - try { - const installed = fs.readdirSync(this.conf.installDir) - return installed.filter( entry => entry[0] != '.') - } catch (error) { - logger.error("getInstalledPlugins", error) - throw error - } - } - - public getLoadedPluginNames(): string[] { - return Object.keys(this.loadedPlugins) - } - - public getLoadedPlugins(): PluginMap { - //logger.debug(this.loadedPlugins) - return this.loadedPlugins - } - - - private async downloadFile(url: URL, dest: string) { - try { - const file = fs.createWriteStream(dest) - file.on('error', err => {throw new Error(err)}) - const response = await fetch(url) - if (!response.ok) throw new Error(response.statusText) - response.body.pipe(file) - await once(file, 'finish'); - - } catch (error) { - logger.error("downloadFile", error) - await fs.promises.unlink(dest) - } - } - - private async getLatestRelease(pluginName:string):Promise{ - const response = await fetch(this.conf.resourceLocation + pluginName + '/releases') - if (!response.ok) throw new Error(pluginName+": "+response.statusText) - - const releases = await response.json() - if (!releases || !releases.length) throw new Error('Empty response') - - return releases[0] - } - - private async getLatestVersion(pluginName:string):Promise{ - const latest = await this.getLatestRelease(pluginName) - const version = latest.tag_name - return parse(version)! - } - - async downloadPlugin(pluginName: string) { - try { - let version = await this.getLatestVersion(pluginName) - logger.info(version) - if(this.conf[pluginName] != null && version === this.conf[pluginName]!["installed"].raw){ - logger.info(pluginName, version, "already installed. skipping", this.conf[pluginName]!["installed"]) - return - } - - const latest = await this.getLatestRelease(pluginName) - const archiveURL = latest.assets.filter(asset => asset.name === 'plugin.zip')[0].browser_download_url - const checksumURL = latest.assets.filter(asset => asset.name === 'md5sum.txt')[0].browser_download_url - if (!version || ! archiveURL || !checksumURL) throw new Error('Malformed response') - - fs.mkdirSync(path.join(this.cacheDir, pluginName), {recursive: true}) - - await this.downloadFile(archiveURL, path.join(this.cacheDir, pluginName, 'plugin.zip')) - await this.downloadFile(checksumURL, path.join(this.cacheDir, pluginName, 'md5sum.txt')) - - if(this.conf[pluginName] == null){ - this.conf[pluginName] = {} - } - this.conf[pluginName]!["cached"] = version - this.setConfig(this.conf) - - - } catch (error) { - logger.error("downloadPlugin", error) - } - } - - extractPlugin(pluginName: string){ - const archivePath = path.join(this.cacheDir, pluginName, "plugin.zip") - const outputPath = path.join(this.conf.installDir,pluginName) - //fs.createReadStream(archivePath).pipe(unzip.Extract({ path: outputPath })); - var zip = new AdmZip(archivePath); - fs.mkdirSync(outputPath, {recursive: true}) - zip.extractAllTo(outputPath, true); - - if(this.conf[pluginName] == null){ - this.conf[pluginName] = {} - } - this.conf[pluginName]!["installed"] = this.conf[pluginName]!["cached"] - this.setConfig(this.conf) - } - - public async installPlugin(pluginName: string) { - try { - let version = await this.getLatestVersion(pluginName) - - if(this.conf[pluginName] == null || version != this.conf[pluginName]!["installed"].raw){ - await this.downloadPlugin(pluginName) - this.extractPlugin(pluginName) - } - await this.loadPlugin(pluginName) - } catch (error) { - logger.error("installPlugin", error) - } - } - - public getFrontend(pluginName: string):string{ - return this.loadedPlugins[pluginName].frontend.toString() - } - - public async uninstallPlugin(pluginName: string) { - //TODO check for exists - logger.info("Deleting plugin", pluginName) - await fs.promises.rmdir(path.join(this.conf.installDir,pluginName)) - } - - - public async loadPlugin(pluginName:string) { - const pth = path.join("..", "..", this.conf.installDir, pluginName) - logger.info("Loading plugin from fs", pth+"/Plugin") - const clazz = await import(pth+"/Plugin") - logger.warn(clazz) - let obj:Plugin = new clazz.default() - await obj.start() - this.loadedPlugins[pluginName] = {backend: obj, frontend: this.loadFrontend(pluginName)} - } - - public loadFrontend(pluginName:string){ - const pth = path.join("..", "..", this.conf.installDir, pluginName) - logger.info("Loading frontend plugin from fs", path.join(__dirname,pth,"FrontendPlugin.js")) - return fs.readFileSync(path.join(__dirname, pth,"FrontendPlugin.js")).toString() - } - - - public unloadPlugin(pluginName:string):void { - if(this.loadedPlugins[pluginName] == null){ - logger.warn("Cannt unload plugin: Unknown:", pluginName) - return - } - logger.info("Unloading plugin ", pluginName) - this.loadedPlugins[pluginName].backend.stop() - delete this.loadedPlugins[pluginName] - } -} \ No newline at end of file diff --git a/src/frontend/widget/main.ts b/src/frontend/widget/main.ts deleted file mode 100644 index f8085bd..0000000 --- a/src/frontend/widget/main.ts +++ /dev/null @@ -1 +0,0 @@ -export { PluginModule } from './widget/module'; \ No newline at end of file diff --git a/src/frontend/widget/rollup.config.js b/src/frontend/widget/rollup.config.js deleted file mode 100644 index aab22b6..0000000 --- a/src/frontend/widget/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import resolve from 'rollup-plugin-node-resolve'; -import typescript from 'rollup-plugin-typescript2'; - -export default { - input: 'src/frontend/widget/main.ts', - output: { - file: 'FrontendPlugin.js', - format: 'system' - }, - plugins: [ - resolve({ - // pass custom options to the resolve plugin - customResolveOptions: { - moduleDirectory: 'node_modules' - } - }), - typescript({ - typescript: require('typescript'), - tsconfig: "tsconfig.frontend.json" - }) - ], - external: [ - 'plugins-core', - '@angular/core', - '@angular/common', - '@angular/router' - ] -} \ No newline at end of file diff --git a/src/frontend/widget/widget/component.ts b/src/frontend/widget/widget/component.ts deleted file mode 100644 index 34b0a95..0000000 --- a/src/frontend/widget/widget/component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { SidebarEntry } from 'frontblock-generic/Plugin'; -declare const fb -@Component({ - selector: 'pluginmanager', //!!!! - template: ` -
-
-
-
- DEBUG -
-
-
- SETUP -
-
-

- Press this button to install all plugins. -
- Once the installation is done the page will refresh automatically -

-
-
- -
-
-
- ` -}) -export class PluginComponent implements OnInit { - - constructor() { } - - ngOnInit() { } - -} - -export const sidebarEntry: SidebarEntry = { - icon: "wrench", - route: "dev/pluginmanager", - text: "DEV Plugin manager", -} - - diff --git a/src/frontend/widget/widget/module.ts b/src/frontend/widget/widget/module.ts deleted file mode 100644 index 06d35ae..0000000 --- a/src/frontend/widget/widget/module.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { PluginComponent } from './component'; -import { RouterModule } from '@angular/router'; -import { FrontendPlugin, SidebarEntry, SidebarEntries } from 'frontblock-generic/Plugin'; - -@NgModule({ - imports: [ - CommonModule, - RouterModule.forChild([ - {path: "debug", component: PluginComponent} - ]), - ], - exports: [RouterModule], - declarations: [ - PluginComponent, -// ANestedComponent, - ], - entryComponents: [PluginComponent], - providers: [{ - provide: 'provider', - useValue: PluginComponent - }] -}) -export class PluginModule implements FrontendPlugin{ - getSidebarEntry(): SidebarEntries { - return { - icon: "wrench", - parentRoute: "pluginmanager", - text: "Plugin manager", - links: [{ - route: "debug", - text: "DEBUG" - }] - } - } -}