|
|
|
@@ -6,7 +6,7 @@ import fs = require('fs');
|
|
|
|
|
import path = require('path')
|
|
|
|
|
import unzip = require('unzip')
|
|
|
|
|
import { Plugin, ConfigLoader } from 'frontblock-generic/Plugin';
|
|
|
|
|
import { SemVer } from "semver";
|
|
|
|
|
import { SemVer, parse } from "semver";
|
|
|
|
|
|
|
|
|
|
Logger.configure({
|
|
|
|
|
appenders:
|
|
|
|
@@ -24,7 +24,6 @@ const logger = Logger.getLogger("PluginManager")
|
|
|
|
|
type PluginVersion = {
|
|
|
|
|
installed?: SemVer,
|
|
|
|
|
cached?: SemVer,
|
|
|
|
|
loaded?: SemVer
|
|
|
|
|
}
|
|
|
|
|
export type PluginVersioning = {
|
|
|
|
|
[pluginName in string]?: PluginVersion | string
|
|
|
|
@@ -45,9 +44,6 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
|
|
|
|
|
super("PluginManager")
|
|
|
|
|
this.cacheDir = path.join(this.conf.installDir, '.cache')
|
|
|
|
|
this.initialize()
|
|
|
|
|
|
|
|
|
|
//this.installPlugin("ApiClient")
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getDefaultConfig(): PluginManagerConfig&PluginVersioning{
|
|
|
|
@@ -108,26 +104,40 @@ 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)
|
|
|
|
|
response.body.pipe(file)
|
|
|
|
|
await response.body.pipe(file)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(error)
|
|
|
|
|
await fs.promises.unlink(dest)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async getLatestRelease(pluginName:string):Promise<any>{
|
|
|
|
|
logger.info("Downloading Plugin", pluginName)
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
const releases = await response.json()
|
|
|
|
|
if (!releases || !releases.length) throw new Error('Empty response')
|
|
|
|
|
|
|
|
|
|
return releases[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async getLatestVersion(pluginName:string):Promise<SemVer>{
|
|
|
|
|
const latest = await this.getLatestRelease(pluginName)
|
|
|
|
|
const version = latest.tag_name
|
|
|
|
|
return parse(version)!
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async downloadPlugin(pluginName: string) {
|
|
|
|
|
try {
|
|
|
|
|
logger.info("Downloading Plugin", pluginName)
|
|
|
|
|
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)
|
|
|
|
|
let version = await this.getLatestVersion(pluginName)
|
|
|
|
|
|
|
|
|
|
const releases = await response.json()
|
|
|
|
|
if (!releases || !releases.length) throw new Error('Empty response')
|
|
|
|
|
|
|
|
|
|
const latest = releases[0]
|
|
|
|
|
const version = latest.tag_name
|
|
|
|
|
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')
|
|
|
|
@@ -141,6 +151,13 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
|
|
|
|
|
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.updateConfig(this.conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(error)
|
|
|
|
|
}
|
|
|
|
@@ -151,12 +168,22 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
|
|
|
|
|
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 }));
|
|
|
|
|
|
|
|
|
|
if(this.conf[pluginName] == null){
|
|
|
|
|
this.conf[pluginName] = {}
|
|
|
|
|
}
|
|
|
|
|
this.conf[pluginName]!["installed"] = this.conf[pluginName]!["cached"]
|
|
|
|
|
this.updateConfig(this.conf)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async installPlugin(pluginName: string) {
|
|
|
|
|
try {
|
|
|
|
|
await this.downloadPlugin(pluginName)
|
|
|
|
|
await this.extractPlugin(pluginName)
|
|
|
|
|
let version = await this.getLatestVersion(pluginName)
|
|
|
|
|
|
|
|
|
|
if(this.conf[pluginName] != null || version != this.conf[pluginName]!["installed"]){
|
|
|
|
|
await this.downloadPlugin(pluginName)
|
|
|
|
|
await this.extractPlugin(pluginName)
|
|
|
|
|
}
|
|
|
|
|
await this.loadPlugin(pluginName)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(error)
|
|
|
|
@@ -179,6 +206,7 @@ export default class PluginManager extends ConfigLoader<PluginManagerConfig&Plug
|
|
|
|
|
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)}
|
|
|
|
|