|
|
@@ -1,19 +1,173 @@
|
|
1
|
1
|
import { RPCExporter } from "rpclibrary/js/src/Interfaces";
|
|
2
|
|
-import { Git, Types } from "upgiter"
|
|
|
2
|
+import { Git } from "upgiter"
|
|
|
3
|
+import { FolderStatus } from "upgiter/js/src/Types";
|
|
|
4
|
+import { Plugin } from "./Plugin";
|
|
|
5
|
+import { FrontworkAdmin } from "./Admin";
|
|
3
|
6
|
|
|
4
|
|
-export type GitUpdaterIfc = {
|
|
5
|
|
- cloneRepo: (force:boolean) => Promise<Types.FolderStatus>
|
|
6
|
|
- getStatus: () => Promise<Types.FolderStatus>
|
|
7
|
|
- checkoutTag: (tag:string) => Promise<Types.FolderStatus>
|
|
8
|
|
- isOutdated: () => Promise<boolean>
|
|
|
7
|
+export type PluginLoaderIfc = {
|
|
|
8
|
+ PluginLoader: {
|
|
|
9
|
+ installPlugin: (name:string, force:boolean) => Promise<FolderStatus>
|
|
|
10
|
+ startPlugin: (name:string) => Promise<boolean>
|
|
|
11
|
+ updatePlugin: (name:string) => Promise<boolean>
|
|
|
12
|
+ setPluginVersion: (name:string, tag:string) => Promise<FolderStatus>
|
|
|
13
|
+ getLoadedPluginNames: () => Promise<String[]>
|
|
|
14
|
+ selfUpdate: (force:boolean) => Promise<FolderStatus>
|
|
|
15
|
+ destroy: () => Promise<void>
|
|
|
16
|
+ }
|
|
9
|
17
|
}
|
|
10
|
18
|
|
|
11
|
|
-class RPCUpgiter
|
|
12
|
|
-extends Git.Updater
|
|
13
|
|
-implements RPCExporter<any, "PluginLoader">{
|
|
|
19
|
+class PluginLoader
|
|
|
20
|
+implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
|
|
|
21
|
+
|
|
14
|
22
|
name = "PluginLoader" as "PluginLoader";
|
|
|
23
|
+ private runningPlugins: Plugin[]
|
|
|
24
|
+ private pluginUpdaters:{[name in string]:Git.Updater} = {}
|
|
|
25
|
+
|
|
|
26
|
+ constructor(private admin:FrontworkAdmin){}
|
|
|
27
|
+
|
|
|
28
|
+ private async selfUpdate(force:boolean = false){
|
|
|
29
|
+ const updater = new Git.Updater({
|
|
|
30
|
+ schema: 'https',
|
|
|
31
|
+ localPath: './dist',
|
|
|
32
|
+ remoteHost: 'www.versioncontrol.me',
|
|
|
33
|
+ remotePath: 'frontwork-distribution',
|
|
|
34
|
+ repoName: 'admin'
|
|
|
35
|
+ })
|
|
|
36
|
+
|
|
|
37
|
+ let status = await updater.getStatus()
|
|
|
38
|
+ if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){
|
|
|
39
|
+ //logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":""))
|
|
|
40
|
+ status = await updater.cloneRepo(force)
|
|
|
41
|
+
|
|
|
42
|
+ //this.destroy()
|
|
|
43
|
+ const installer = eval("require")("./Installer").installAdmin
|
|
|
44
|
+ installer(this.getPlugins())
|
|
|
45
|
+ }
|
|
|
46
|
+ return status
|
|
|
47
|
+ }
|
|
|
48
|
+
|
|
|
49
|
+ async installPlugin(name: string, force:boolean = false):Promise<FolderStatus>{
|
|
|
50
|
+ //logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":""))
|
|
|
51
|
+ this.pluginUpdaters[name] = new Git.Updater({
|
|
|
52
|
+ schema: 'https',
|
|
|
53
|
+ localPath: './dist',
|
|
|
54
|
+ remoteHost: 'www.versioncontrol.me',
|
|
|
55
|
+ remotePath: 'frontwork-distribution',
|
|
|
56
|
+ repoName: name
|
|
|
57
|
+ })
|
|
|
58
|
+ //new GitUpdater("./plugins/"+name)
|
|
|
59
|
+ const status = await this.pluginUpdaters[name].cloneRepo(force)
|
|
|
60
|
+ return status
|
|
|
61
|
+ }
|
|
|
62
|
+
|
|
|
63
|
+ async startPlugin(name:string):Promise<boolean>{
|
|
|
64
|
+ if(!this.pluginUpdaters[name]) return false
|
|
|
65
|
+ const status = await this.pluginUpdaters[name].getStatus()
|
|
|
66
|
+ if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
|
|
67
|
+ if(status.currentTag && !status.latestTag){
|
|
|
68
|
+ //git glitches sometimes if you check immediately after clone
|
|
|
69
|
+ //logger.warn("re-fetching tag for "+name+"...")
|
|
|
70
|
+ return await this.startPlugin(name)
|
|
|
71
|
+ }
|
|
|
72
|
+ //logger.error("Bad repo status", name, status)
|
|
|
73
|
+ return false
|
|
|
74
|
+ }
|
|
|
75
|
+
|
|
|
76
|
+/* if(this.loadedPlugins[name]){
|
|
|
77
|
+ logger.error("Plugin", name, "is already started")
|
|
|
78
|
+ return false
|
|
|
79
|
+ }
|
|
|
80
|
+*/
|
|
|
81
|
+
|
|
|
82
|
+ let str = "../plugins/"+name+"/Plugin"
|
|
|
83
|
+ const pluginClass = await eval('require')(str)
|
|
|
84
|
+ const pluginObj = new pluginClass.default(this)
|
|
|
85
|
+ try{
|
|
|
86
|
+ if(pluginObj.start)
|
|
|
87
|
+ await pluginObj.start()
|
|
|
88
|
+ //this.pushNotification({message: "Started plugin "+pluginObj.name, severity: "Important", topic:"admin"})
|
|
|
89
|
+ this.addPlugin(pluginObj)
|
|
|
90
|
+ return true
|
|
|
91
|
+ }catch(e){
|
|
|
92
|
+ //logger.error(e)
|
|
|
93
|
+ //this.pushNotification({message: "Start of plugin "+pluginObj.name+" failed because of "+String(e), severity: "Error", topic:"admin"})
|
|
|
94
|
+ return false
|
|
|
95
|
+ }
|
|
|
96
|
+ }
|
|
|
97
|
+
|
|
|
98
|
+ async updatePlugin(name:string):Promise<boolean>{
|
|
|
99
|
+ if(!this.pluginUpdaters[name]) return false
|
|
|
100
|
+ const status = await this.pluginUpdaters[name].getStatus()
|
|
|
101
|
+ if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
|
|
102
|
+ //logger.error("Bad repo status", name, status)
|
|
|
103
|
+ return false
|
|
|
104
|
+ }
|
|
|
105
|
+ if(status.currentTag == status.latestTag){
|
|
|
106
|
+ //logger.warn(name, "already at latest tag")
|
|
|
107
|
+ return false
|
|
|
108
|
+ }
|
|
|
109
|
+
|
|
|
110
|
+ /*
|
|
|
111
|
+ if(this.loadedPlugins[name]){
|
|
|
112
|
+ logger.error("Plugin", name, "is running. Stop it first")
|
|
|
113
|
+ return false
|
|
|
114
|
+ }
|
|
|
115
|
+ */
|
|
|
116
|
+
|
|
|
117
|
+ this.pluginUpdaters[name].checkoutTag(status.latestTag!)
|
|
|
118
|
+ return true
|
|
|
119
|
+ }
|
|
|
120
|
+
|
|
|
121
|
+ async setPluginVersion(pluginName:string, tag:string):Promise<FolderStatus>{
|
|
|
122
|
+ const status = await this.pluginUpdaters[pluginName].getStatus()
|
|
|
123
|
+ if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){
|
|
|
124
|
+ //logger.error("Bad repo status", pluginName, status)
|
|
|
125
|
+ return status
|
|
|
126
|
+ }
|
|
|
127
|
+
|
|
|
128
|
+ return await this.pluginUpdaters[pluginName].checkoutTag(tag)
|
|
|
129
|
+ }
|
|
|
130
|
+
|
|
|
131
|
+ async addPlugin(plugin: Plugin){
|
|
|
132
|
+ this.runningPlugins.push(plugin)
|
|
|
133
|
+ if(plugin.getTableDefinitions().length != 0)
|
|
|
134
|
+ await this.admin.makeKnex()
|
|
|
135
|
+ }
|
|
|
136
|
+
|
|
|
137
|
+ removePlugin(plugin: Plugin){
|
|
|
138
|
+ this.runningPlugins = this.runningPlugins.filter(p => p.name !== plugin.name)
|
|
|
139
|
+ }
|
|
|
140
|
+
|
|
|
141
|
+ getPlugins():Plugin[]{
|
|
|
142
|
+ return [...this.runningPlugins]
|
|
|
143
|
+ }
|
|
|
144
|
+
|
|
|
145
|
+ private async destroy(){
|
|
|
146
|
+ return
|
|
|
147
|
+ }
|
|
15
|
148
|
|
|
16
|
149
|
exportRPCs(){
|
|
17
|
|
- return []
|
|
|
150
|
+ return [{
|
|
|
151
|
+ name: "installPlugin" as "installPlugin",
|
|
|
152
|
+ call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
|
|
|
153
|
+ },{
|
|
|
154
|
+ name: "startPlugin" as "startPlugin",
|
|
|
155
|
+ call: async (name:string) => {return await this.startPlugin(name)},
|
|
|
156
|
+ },{
|
|
|
157
|
+ name: "updatePlugin" as "updatePlugin",
|
|
|
158
|
+ call: async (name:string) => {return await this.updatePlugin(name)},
|
|
|
159
|
+ },{
|
|
|
160
|
+ name: "setPluginVersion" as "setPluginVersion",
|
|
|
161
|
+ call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
|
|
|
162
|
+ },{
|
|
|
163
|
+ name: "getLoadedPluginNames" as "getLoadedPluginNames",
|
|
|
164
|
+ call: async () => {return this.getPlugins().map(p => p.name)},
|
|
|
165
|
+ },{
|
|
|
166
|
+ name: "selfUpdate" as "selfUpdate",
|
|
|
167
|
+ call: async (force: boolean) => {return await this.selfUpdate(force)},
|
|
|
168
|
+ },{
|
|
|
169
|
+ name: "destroy" as "destroy",
|
|
|
170
|
+ call: async () => {return this.destroy()}
|
|
|
171
|
+ }]
|
|
18
|
172
|
}
|
|
19
|
173
|
}
|