This commit is contained in:
peter
2019-08-04 00:57:23 +02:00
parent 6601b4bf2f
commit 6aae2146e9
14 changed files with 90 additions and 171 deletions
+13 -1
View File
@@ -20,6 +20,8 @@ export default class PluginManagerPlugin extends PluginManager implements Plugin
constructor(){
super()
this.loadedPlugins[this.name] = {backend: this, frontend: this.loadFrontend(this.name)}
}
exportRPCs(): import("frontblock-generic/Plugin").socketioRPC[] {
@@ -75,12 +77,22 @@ export default class PluginManagerPlugin extends PluginManager implements Plugin
visibility: "private",
rpc: async(conf) => { return this.updateConfig(conf) },
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'
}
]
}
async start(): Promise<void> {
await this.loadPlugin("admin")
}
stop(): void {
+31 -28
View File
@@ -5,8 +5,11 @@ 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 } from 'frontblock-generic/Plugin';
import { SemVer, parse } from "semver";
import { once } from 'events';
Logger.configure({
appenders:
@@ -20,6 +23,7 @@ Logger.configure({
}
})
const logger = Logger.getLogger("PluginManager")
const AdmZip = require('adm-zip');
type PluginVersion = {
installed?: SemVer,
@@ -55,16 +59,11 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
logger.info('Initializing manager')
try {
fs.access(this.cacheDir, err => {
if (err && err.code === 'ENOENT') {
fs.mkdirSync(this.cacheDir, {recursive: true})
logger.info('Manager installed to ' + this.conf.installDir)
} else {
logger.info('Manager already installed at ' + this.conf.installDir)
}
})
fs.accessSync(this.cacheDir)
logger.info('Manager already installed at ' + this.conf.installDir)
} catch (error) {
logger.error(error)
fs.mkdirSync(this.cacheDir, {recursive: true})
logger.info('Manager installed to ' + this.cacheDir)
}
}
@@ -79,12 +78,12 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
]
}
public async getInstalledPlugins(): Promise<string[]> {
public getInstalledPlugins():string[] {
try {
const installed = await fs.promises.readdir(this.conf.installDir)
const installed = fs.readdirSync(this.conf.installDir)
return installed.filter( entry => entry[0] != '.')
} catch (error) {
logger.error(error)
logger.error("getInstalledPlugins", error)
throw error
}
}
@@ -104,17 +103,18 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
file.on('error', err => {throw new Error(err)})
const response = await fetch(url)
if (!response.ok) throw new Error(response.statusText)
await response.body.pipe(file)
response.body.pipe(file)
await once(file, 'finish');
} catch (error) {
logger.error(error)
logger.error("downloadFile", error)
await fs.promises.unlink(dest)
}
}
private async getLatestRelease(pluginName:string):Promise<any>{
logger.info("Downloading Plugin", pluginName)
logger.info("Downloading Plugin", pluginName, "from", this.conf.resourceLocation + pluginName + '/releases')
if(pluginName === this.name) pluginName = "admin"
logger.error(this.conf.resourceLocation + pluginName + '/releases')
const response = await fetch(this.conf.resourceLocation + pluginName + '/releases')
if (!response.ok) throw new Error(pluginName+": "+response.statusText)
@@ -130,23 +130,20 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
return parse(version)!
}
private async downloadPlugin(pluginName: string) {
async downloadPlugin(pluginName: string) {
try {
let version = await this.getLatestVersion(pluginName)
if(this.conf[pluginName] != null && version == 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')
await fs.access(path.join(this.cacheDir, pluginName), err => {
if (err && err.code === 'ENOENT') {
fs.mkdirSync(path.join(this.cacheDir, pluginName), {recursive: true})
}
})
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'))
@@ -159,15 +156,18 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
} catch (error) {
logger.error(error)
logger.error("downloadPlugin", error)
}
}
private async extractPlugin(pluginName: string){
extractPlugin(pluginName: string){
if(pluginName === this.name) pluginName = "admin"
const archivePath = path.join(this.cacheDir, pluginName, "plugin.zip")
const outputPath = path.join(this.conf.installDir,pluginName)
await fs.createReadStream(archivePath).pipe(unzip.Extract({ path: outputPath }));
//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] = {}
@@ -177,16 +177,18 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
}
public async installPlugin(pluginName: string) {
if(pluginName === this.name) pluginName = "admin"
try {
let version = await this.getLatestVersion(pluginName)
if(this.conf[pluginName] != null || version != this.conf[pluginName]!["installed"]){
if(this.conf[pluginName] == null || version != this.conf[pluginName]!["installed"]){
await this.downloadPlugin(pluginName)
await this.extractPlugin(pluginName)
this.extractPlugin(pluginName)
}
await this.loadPlugin(pluginName)
} catch (error) {
logger.error(error)
logger.error("installPlugin", error)
}
}
@@ -213,6 +215,7 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
}
public loadFrontend(pluginName:string){
if(pluginName === this.name) pluginName = "admin"
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"))