136 lines
4.0 KiB
TypeScript
136 lines
4.0 KiB
TypeScript
'use strict'
|
|
|
|
import * as Logger from 'log4js';
|
|
import fetch = require('node-fetch');
|
|
import fs = require('fs');
|
|
import path = require('path')
|
|
import unzip = require('unzip')
|
|
|
|
Logger.configure({
|
|
appenders:
|
|
{
|
|
"plugin-manager": { type: 'stdout' },
|
|
//app: { type: 'file', filename: 'application.log' }
|
|
},
|
|
categories:
|
|
{
|
|
default: { appenders: [ 'plugin-manager' ], level: 'debug' }
|
|
}
|
|
})
|
|
const logger = Logger.getLogger("plugin-manager")
|
|
|
|
|
|
export class PluginManager{
|
|
|
|
private installDir: string
|
|
private cacheDir: string
|
|
private loadedPlugins: string[]
|
|
|
|
constructor(installDir: string = './plugins'){
|
|
this.installDir = installDir
|
|
this.cacheDir = path.join(installDir, '.cache')
|
|
this.initialize()
|
|
}
|
|
|
|
private initialize() {
|
|
logger.info('Initializing manager')
|
|
|
|
try {
|
|
fs.access(this.cacheDir, async err => {
|
|
if (err && err.code === 'ENOENT') {
|
|
await fs.promises.mkdir(this.cacheDir, {recursive: true})
|
|
logger.info('Manager installed to ' + this.installDir)
|
|
} else {
|
|
logger.info('Manager already installed at ' + this.installDir)
|
|
}
|
|
})
|
|
} catch (error) {
|
|
logger.error(error)
|
|
}
|
|
}
|
|
|
|
public async getAvailablePlugins(): Promise<string[] | void> {
|
|
return [
|
|
'apiclient',
|
|
'paymentmanager',
|
|
'wallet',
|
|
'htmlsupplier'
|
|
]
|
|
}
|
|
|
|
public async getInstalledPlugins(): Promise<string[] | void> {
|
|
try {
|
|
const installed = await fs.promises.readdir(this.installDir)
|
|
return installed.filter( entry => entry[0] != '.')
|
|
} catch (error) {
|
|
logger.error(error)
|
|
return
|
|
}
|
|
}
|
|
|
|
public async getLoadedPlugins(): Promise<string[] | void> {
|
|
return this.loadedPlugins
|
|
}
|
|
|
|
private async downloadFile(url: URL, dest: string) {
|
|
try {
|
|
fs.access(path.dirname(dest), err => {
|
|
if (err && err.code === 'ENOENT') {
|
|
fs.mkdirSync(path.dirname(dest), {recursive: true})
|
|
}
|
|
})
|
|
|
|
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)
|
|
} catch (error) {
|
|
logger.error(error)
|
|
await fs.promises.unlink(dest)
|
|
}
|
|
}
|
|
|
|
private async downloadPlugin(pluginName: string) {
|
|
try {
|
|
const response = await fetch('https://gitea.frontblock.me/api/v1/repos/fb-vendor/' + pluginName + '/releases')
|
|
if (!response.ok) throw new Error(response.statusText)
|
|
|
|
const releases = await response.json()
|
|
if (!releases || !releases.length) throw new Error('Empty response')
|
|
|
|
const latest = releases[0]
|
|
const version = latest.tag_name
|
|
const archiveURL = latest.assets.filter(asset => asset.name === pluginName + '.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 this.downloadFile(archiveURL, path.join(this.cacheDir, pluginName, version, 'plugin.zip'))
|
|
await this.downloadFile(checksumURL, path.join(this.cacheDir, pluginName, version, 'md5sum.txt'))
|
|
|
|
} catch (error) {
|
|
logger.error(error)
|
|
}
|
|
}
|
|
|
|
public async installPlugin(pluginName: string) {
|
|
try {
|
|
await this.downloadPlugin(pluginName)
|
|
} catch (error) {
|
|
logger.debug(error)
|
|
}
|
|
}
|
|
|
|
public uninstallPlugin(pluginName: string) {
|
|
|
|
}
|
|
|
|
|
|
public async loadPlugin() {
|
|
|
|
}
|
|
|
|
public async unloadPlugin() {
|
|
|
|
}
|
|
} |