0.1.0 move to gitea dist for downloads
This commit is contained in:
+1
-1
@@ -46,7 +46,7 @@ steps:
|
|||||||
- cp -r ./dist/* ./${DRONE_REPO_NAME}
|
- cp -r ./dist/* ./${DRONE_REPO_NAME}
|
||||||
- cd ./${DRONE_REPO_NAME}
|
- cd ./${DRONE_REPO_NAME}
|
||||||
- git add -A
|
- git add -A
|
||||||
- git commit -m "drone tagged as version ${DRONE_TAG}" || true
|
- git commit --allow-empty -m "drone tagged as version ${DRONE_TAG}"
|
||||||
- git tag ${DRONE_TAG}
|
- git tag ${DRONE_TAG}
|
||||||
- git push https://$GIT_USER:$GIT_PASSWORD@gitea.frontblock.me/fb-dist/${DRONE_REPO_NAME}.git master ${DRONE_TAG}
|
- git push https://$GIT_USER:$GIT_PASSWORD@gitea.frontblock.me/fb-dist/${DRONE_REPO_NAME}.git master ${DRONE_TAG}
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Generated
+26
-2
@@ -5546,6 +5546,11 @@
|
|||||||
"isobject": "^3.0.1"
|
"isobject": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"is-promise": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
|
||||||
|
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
|
||||||
|
},
|
||||||
"is-regex": {
|
"is-regex": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
||||||
@@ -6492,6 +6497,18 @@
|
|||||||
"signal-exit": "^3.0.0"
|
"signal-exit": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lowdb": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.3",
|
||||||
|
"is-promise": "^2.1.0",
|
||||||
|
"lodash": "4",
|
||||||
|
"pify": "^3.0.0",
|
||||||
|
"steno": "^0.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lower-case": {
|
"lower-case": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
||||||
@@ -7876,8 +7893,7 @@
|
|||||||
"pify": {
|
"pify": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"pinkie": {
|
"pinkie": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
@@ -10215,6 +10231,14 @@
|
|||||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
|
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"steno": {
|
||||||
|
"version": "0.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz",
|
||||||
|
"integrity": "sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"stream-browserify": {
|
"stream-browserify": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
"http": "0.0.0",
|
"http": "0.0.0",
|
||||||
"key-file-storage": "^2.2.4",
|
"key-file-storage": "^2.2.4",
|
||||||
"log4js": "^4.4.0",
|
"log4js": "^4.4.0",
|
||||||
|
"lowdb": "^1.0.0",
|
||||||
"memfs": "^2.15.5",
|
"memfs": "^2.15.5",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
|
|||||||
+15
-138
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import * as Logger from 'log4js'
|
import * as Logger from 'log4js'
|
||||||
import { socketioRPC, ConfigLoader, Plugin } from 'frontblock-generic/Plugin';
|
import { socketioRPC, ConfigLoader, Plugin } from 'frontblock-generic/Plugin';
|
||||||
import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types';
|
import { ErrorResponse, SuccessResponse, SubscriptionResponse } from 'frontblock-generic/Types';
|
||||||
import express = require('express');
|
import express = require('express');
|
||||||
import http = require('http');
|
import http = require('http');
|
||||||
import bsock = require('bsock');
|
import bsock = require('bsock');
|
||||||
@@ -10,21 +10,22 @@ import { FrontblockCherryPicker } from "git-cherrypicker"
|
|||||||
import { promises as fs } from "fs"
|
import { promises as fs } from "fs"
|
||||||
import { GitUpdater, RepoFolderStatus, } from "./GitUpdater";
|
import { GitUpdater, RepoFolderStatus, } from "./GitUpdater";
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
|
import { UpdateManager } from './UpdateManger';
|
||||||
|
|
||||||
const kfs = require("key-file-storage").default('kfs')
|
const kfs = require("key-file-storage").default('kfs')
|
||||||
|
|
||||||
Logger.configure({
|
Logger.configure({
|
||||||
appenders:
|
appenders:
|
||||||
{
|
{
|
||||||
"frontblock-admin": { type: 'stdout' },
|
"admin": { type: 'stdout' },
|
||||||
//app: { type: 'file', filename: 'application.log' }
|
//app: { type: 'file', filename: 'application.log' }
|
||||||
},
|
},
|
||||||
categories:
|
categories:
|
||||||
{
|
{
|
||||||
default: { appenders: [ 'frontblock-admin' ], level: 'debug' }
|
default: { appenders: [ 'admin' ], level: 'debug' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const logger = Logger.getLogger("frontblock-admin")
|
const logger = Logger.getLogger("admin")
|
||||||
|
|
||||||
type hookRPC =
|
type hookRPC =
|
||||||
{
|
{
|
||||||
@@ -70,12 +71,7 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
private httpServer
|
private httpServer
|
||||||
private io = bsock.createServer()
|
private io = bsock.createServer()
|
||||||
private wsServer = http.createServer()
|
private wsServer = http.createServer()
|
||||||
|
private updateManager:UpdateManager = new UpdateManager()
|
||||||
private dashboardUpdater:GitUpdater
|
|
||||||
private adminUpdater:GitUpdater
|
|
||||||
private pluginUpdaters:{[name in string]:GitUpdater} = {}
|
|
||||||
private loadedPlugins:{[name in string]:Plugin} = {}
|
|
||||||
|
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super("FrontblockAdmin")
|
super("FrontblockAdmin")
|
||||||
@@ -87,83 +83,10 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
return {httpPort: 8080}
|
return {httpPort: 8080}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateFrontblockLib(){
|
|
||||||
logger.warn("Picking FrontblockLib...")
|
|
||||||
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateDashboard():Promise<RepoFolderStatus>{
|
|
||||||
logger.warn("Cloning dashboard...")
|
|
||||||
this.dashboardUpdater = new GitUpdater("./static")
|
|
||||||
const status = await this.dashboardUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", true)
|
|
||||||
return(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async installPlugin(name: string):Promise<RepoFolderStatus>{
|
|
||||||
logger.warn("Cloning "+name+"...")
|
|
||||||
this.pluginUpdaters[name] = new GitUpdater("./plugins/"+name)
|
|
||||||
const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", true)
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
|
|
||||||
private async startPlugin(name:string):Promise<boolean>{
|
|
||||||
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(this.loadedPlugins[name]){
|
|
||||||
logger.error("Plugin", name, "is already started")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let str = "../plugins/"+name+"/Plugin"
|
|
||||||
const pluginClass = await import(str)
|
|
||||||
const pluginObj = new pluginClass.default()
|
|
||||||
await pluginObj.start()
|
|
||||||
this.loadedPlugins[name] = pluginObj
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updatePlugin(name:string):Promise<boolean>{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setPluginVersion(pluginName:string, tag:string):Promise<RepoFolderStatus>{
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async initialize(){
|
private async initialize(){
|
||||||
await this.updateDashboard()
|
await this.updateManager.updateAdmin()
|
||||||
await this.updateFrontblockLib()
|
await this.updateManager.updateDashboard()
|
||||||
await this.installPlugin("PluginManager")
|
await this.updateManager.updateFrontblockLib()
|
||||||
//await this.updatePluginmanager()
|
|
||||||
|
|
||||||
this.startWebsocket()
|
this.startWebsocket()
|
||||||
this.startWebserver()
|
this.startWebserver()
|
||||||
@@ -188,61 +111,15 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
type:'call',
|
type:'call',
|
||||||
fn: () => { return rpcInfos }
|
fn: () => { return rpcInfos }
|
||||||
}
|
}
|
||||||
},{
|
|
||||||
owner: 'Admin',
|
|
||||||
name: 'installPlugin',
|
|
||||||
args: 'name',
|
|
||||||
info: {
|
|
||||||
type: 'call',
|
|
||||||
fn: async (name:string) => {
|
|
||||||
return await this.installPlugin(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
owner: 'Admin',
|
|
||||||
name: 'startPlugin',
|
|
||||||
args: 'name',
|
|
||||||
info: {
|
|
||||||
type: 'call',
|
|
||||||
fn: async (name:string) => {
|
|
||||||
return await this.startPlugin(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
owner: 'PluginManager',
|
|
||||||
name: 'getLoadedPluginNames',
|
|
||||||
args: '',
|
|
||||||
info: {
|
|
||||||
type: 'call',
|
|
||||||
fn: () => Object.keys(this.loadedPlugins)
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
owner: 'Admin',
|
|
||||||
name: 'updatePlugin',
|
|
||||||
args: 'name',
|
|
||||||
info: {
|
|
||||||
type: 'call',
|
|
||||||
fn: async (name) => {return await this.updatePlugin(name)}
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
owner: 'Admin',
|
|
||||||
name: 'setPluginVersion',
|
|
||||||
args: 'name, tag',
|
|
||||||
info: {
|
|
||||||
type: 'call',
|
|
||||||
fn: async (name, tag) => {return await this.setPluginVersion(name, tag)}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
//translate RPCs to socket-bound function metadata
|
//translate RPCs to socket-bound function metadata
|
||||||
const loadedPlugins = this.loadedPlugins
|
const loadedPlugins:Plugin[] = [this.updateManager, ...this.updateManager.getLoadedPlugins()]
|
||||||
for(const name in loadedPlugins){
|
loadedPlugins.forEach(plugin => plugin.exportRPCs().forEach(rpc => {
|
||||||
loadedPlugins[name].exportRPCs().forEach(rpc => {
|
const info = this.rpcToRpcInfo(plugin.name, rpc)
|
||||||
const info = this.rpcToRpcInfo(name, rpc)
|
rpcInfos.push(info)
|
||||||
rpcInfos.push(info)
|
}))
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//Hook up all the functions
|
//Hook up all the functions
|
||||||
for(const api of rpcInfos){
|
for(const api of rpcInfos){
|
||||||
@@ -405,7 +282,7 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
*
|
*
|
||||||
* Note callbacks *need* to accept a singular argument and they have to be the last parameter!
|
* Note callbacks *need* to accept a singular argument and they have to be the last parameter!
|
||||||
*/
|
*/
|
||||||
hookGenerator = (rpc:socketioRPC) => {
|
hookGenerator = (rpc:socketioRPC): (socket)=>(...args:any[])=>Promise<SubscriptionResponse> => {
|
||||||
const argsArr = this.extractArgs(rpc.rpc).split(',')
|
const argsArr = this.extractArgs(rpc.rpc).split(',')
|
||||||
argsArr.pop()
|
argsArr.pop()
|
||||||
const args = argsArr.join(',')
|
const args = argsArr.join(',')
|
||||||
|
|||||||
+31
-25
@@ -1,10 +1,23 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
import { assert } from "bsert"
|
|
||||||
import * as git from "simple-git/promise"
|
import * as git from "simple-git/promise"
|
||||||
import * as gyt from "git-describe"
|
import * as gyt from "git-describe"
|
||||||
import { promises as fs, mkdirSync } from "fs"
|
import { promises as fs, mkdirSync } from "fs"
|
||||||
import * as rimraf from "rimraf"
|
import * as rimraf from "rimraf"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
|
import * as Logger from 'log4js'
|
||||||
|
Logger.configure({
|
||||||
|
appenders:
|
||||||
|
{
|
||||||
|
"admin/gitupdater": { type: 'stdout' },
|
||||||
|
//app: { type: 'file', filename: 'application.log' }
|
||||||
|
},
|
||||||
|
categories:
|
||||||
|
{
|
||||||
|
default: { appenders: [ 'admin/gitupdater' ], level: 'debug' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const logger = Logger.getLogger("admin/gitupdater")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const rmrf = (path:string, options = {}) => {
|
const rmrf = (path:string, options = {}) => {
|
||||||
@@ -17,6 +30,7 @@ export type RepoFolderStatus = {
|
|||||||
currentTag?: string
|
currentTag?: string
|
||||||
tags?: string[]
|
tags?: string[]
|
||||||
latestTag?: string
|
latestTag?: string
|
||||||
|
remote?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitUpdater{
|
export class GitUpdater{
|
||||||
@@ -41,6 +55,11 @@ export class GitUpdater{
|
|||||||
await this.repo.fetch("origin", "master", {
|
await this.repo.fetch("origin", "master", {
|
||||||
"--tags": null
|
"--tags": null
|
||||||
});
|
});
|
||||||
|
const remoteInfo = await this.repo.getRemotes(true)
|
||||||
|
let remoteURL
|
||||||
|
if(remoteInfo.length != 0){
|
||||||
|
remoteURL = remoteInfo.find(i => i.name === "origin").refs.fetch
|
||||||
|
}
|
||||||
const remoteTags = await this.repo.tags();
|
const remoteTags = await this.repo.tags();
|
||||||
const desc = await gyt.gitDescribe(this.folderPath, { match: "*" });
|
const desc = await gyt.gitDescribe(this.folderPath, { match: "*" });
|
||||||
return {
|
return {
|
||||||
@@ -48,19 +67,22 @@ export class GitUpdater{
|
|||||||
empty: empty,
|
empty: empty,
|
||||||
currentTag: !desc.tag?null:desc.tag,
|
currentTag: !desc.tag?null:desc.tag,
|
||||||
tags: !remoteTags.all?[]:remoteTags.all,
|
tags: !remoteTags.all?[]:remoteTags.all,
|
||||||
latestTag: remoteTags.latest
|
latestTag: remoteTags.latest,
|
||||||
|
remote: remoteURL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneRepo(from:string, force:boolean = false):Promise<RepoFolderStatus> {
|
async cloneRepo(from:string, force:boolean = false):Promise<RepoFolderStatus> {
|
||||||
if(this.folderPath === "." && force)
|
|
||||||
throw new Error("refusing to `rm -rf .`: \ncloneRepo(from: "+from+", force: "+force+")")
|
|
||||||
if(force){
|
if(force){
|
||||||
await rmrf(this.folderPath)
|
await rmrf(this.folderPath)
|
||||||
await fs.mkdir(this.folderPath, { recursive: true });
|
await fs.mkdir(this.folderPath, { recursive: true });
|
||||||
}
|
}
|
||||||
const status = await this.getStatus()
|
const status = await this.getStatus()
|
||||||
assert(status.exists && status.empty)
|
if(!status.exists || !status.empty){
|
||||||
|
logger.error("The folder "+this.folderPath+" doesn't exist or is not empty. Not cloning! Pass the force parameter to override this check")
|
||||||
|
logger.error(status)
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
await git(this.folderPath).clone(from, path.resolve(this.folderPath));
|
await git(this.folderPath).clone(from, path.resolve(this.folderPath));
|
||||||
return await this.getStatus();
|
return await this.getStatus();
|
||||||
@@ -68,27 +90,11 @@ export class GitUpdater{
|
|||||||
|
|
||||||
async checkoutTag(tag:string):Promise<RepoFolderStatus> {
|
async checkoutTag(tag:string):Promise<RepoFolderStatus> {
|
||||||
const status = await this.getStatus()
|
const status = await this.getStatus()
|
||||||
assert(status.exists && status.tags && status.tags.length !== 0)
|
if(!status.exists || !status.tags || status.tags.length === 0){
|
||||||
|
logger.error("Unable to check out tag", tag, status)
|
||||||
|
return status
|
||||||
|
}
|
||||||
await this.repo.checkout(tag);
|
await this.repo.checkout(tag);
|
||||||
return await this.getStatus();
|
return await this.getStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
(async () => {
|
|
||||||
const staticPath = path.join(__dirname, "..", "static")
|
|
||||||
|
|
||||||
const gl = new GitUpdater(staticPath)
|
|
||||||
let status = await gl.getStatus()
|
|
||||||
console.log(status)
|
|
||||||
|
|
||||||
if(status.empty){
|
|
||||||
status = await gl.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git")
|
|
||||||
console.log(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
status = await gl.checkoutTag(status.latestTag!)
|
|
||||||
console.log(status)
|
|
||||||
})()
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import { Plugin, socketioRPC } from "frontblock-generic/Plugin";
|
||||||
|
import { GitUpdater, RepoFolderStatus } from "./GitUpdater";
|
||||||
|
import { FrontblockCherryPicker } from "git-cherrypicker";
|
||||||
|
import * as Logger from 'log4js'
|
||||||
|
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 implements Plugin{
|
||||||
|
name: string = "UpdateManager"
|
||||||
|
private loadedPlugins:{[name in string]:Plugin} = {}
|
||||||
|
private dashboardUpdater:GitUpdater
|
||||||
|
private adminUpdater:GitUpdater
|
||||||
|
private pluginUpdaters:{[name in string]:GitUpdater} = {}
|
||||||
|
|
||||||
|
getDefaultConfig(): void {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exportRPCs(): socketioRPC[] {
|
||||||
|
return [{
|
||||||
|
name: 'installPlugin',
|
||||||
|
rpc: async (name:string) => {return await this.installPlugin(name)},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
},{
|
||||||
|
name: 'startPlugin',
|
||||||
|
rpc: async (name:string) => {return await this.startPlugin(name)},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
},{
|
||||||
|
name: 'updatePlugin',
|
||||||
|
rpc: async (name) => {return await this.updatePlugin(name)},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
},{
|
||||||
|
name: 'setPluginVersion',
|
||||||
|
rpc: async (name, tag) => {return await this.setPluginVersion(name, tag)},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
},{
|
||||||
|
name: 'updateDashboard',
|
||||||
|
rpc: async () => {return await this.updateDashboard()},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
},{
|
||||||
|
name: 'getLoadedPluginNames',
|
||||||
|
rpc: async () => {return await this.getLoadedPluginNames()},
|
||||||
|
type: 'call',
|
||||||
|
visibility: 'private'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAdmin(force:boolean = false){
|
||||||
|
this.adminUpdater = new GitUpdater("./dist")
|
||||||
|
let status = await this.adminUpdater.getStatus()
|
||||||
|
if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){
|
||||||
|
logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":""))
|
||||||
|
status = await this.adminUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/admin.git", force)
|
||||||
|
}
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFrontblockLib(){
|
||||||
|
logger.warn("Picking FrontblockLib...")
|
||||||
|
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDashboard(force:boolean = false):Promise<RepoFolderStatus>{
|
||||||
|
this.dashboardUpdater = new GitUpdater("./static")
|
||||||
|
let status = await this.dashboardUpdater.getStatus()
|
||||||
|
if(force || !status.exists || status.empty || !status.currentTag){
|
||||||
|
logger.warn("Cloning fb-dist/dashboard into ./static ..."+(force?" USING FORCE!":""))
|
||||||
|
status = await this.dashboardUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", force)
|
||||||
|
}
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
async installPlugin(name: string, force:boolean = false):Promise<RepoFolderStatus>{
|
||||||
|
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<boolean>{
|
||||||
|
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(this.loadedPlugins[name]){
|
||||||
|
logger.error("Plugin", name, "is already started")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let str = "../plugins/"+name+"/Plugin"
|
||||||
|
const pluginClass = await import(str)
|
||||||
|
const pluginObj = new pluginClass.default()
|
||||||
|
await pluginObj.start()
|
||||||
|
this.loadedPlugins[name] = pluginObj
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePlugin(name:string):Promise<boolean>{
|
||||||
|
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<RepoFolderStatus>{
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
start(): void | Promise<void> {
|
||||||
|
throw new Error("Method not implemented (on purpose)");
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(): void | Promise<void> {
|
||||||
|
throw new Error("Method not implemented (on purpose)");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user