Published source
Download source ZIP
CH-J Server Manager
Browse directories and files for a specific application release.
Source is provided under the CH-J Proprietary Software License 1.14. Its availability does not change the license terms or grant additional rights.
1
"use strict";3
const { compareVersions } = require("../../shared/version");5
class PluginService {6
constructor(options) {7
this.appVersion = options.appVersion;8
this.pluginApiVersion = options.pluginApiVersion;9
this.configStore = options.configStore;10
this.registry = options.registry;11
this.installer = options.installer;12
this.providerFactory = options.providerFactory;13
this.runtime = options.runtime;14
this.logger = options.logger;15
this.catalog = [];16
this.sourceBaseUrl = null;17
this.operation = null;18
}20
getState() {21
const installed = this.registry.listInstalled();22
return {23
status: this.operation || "idle",24
installed,25
windows: this.runtime.listWindows?.() || [],26
catalog: this.catalog.map((plugin) => {27
const current = installed.find((item) => item.id === plugin.id);28
const comparison = current ? compareVersions(plugin.version, current.version) : 1;29
const sameArtifact = Boolean(current?.installedSha512 && current.installedSha512 === plugin.sha512);30
return {31
...plugin,32
installedVersion: current?.version || null,33
installedReleaseId: current?.installedReleaseId || null,34
updateAvailable: Boolean(current && (comparison > 0 || (comparison === 0 && !sameArtifact))),35
installed: Boolean(current && (comparison < 0 || (comparison === 0 && sameArtifact)))36
};37
}),38
sourceBaseUrl: this.sourceBaseUrl39
};40
}42
async checkCatalog() {43
if (this.operation) throw new Error("Another plugin operation is already running.");44
this.operation = "checking";45
try {46
const config = this.configStore.get();47
const provider = this.providerFactory(config.updates);48
const result = await provider.list({ appVersion: this.appVersion, pluginApiVersion: this.pluginApiVersion, channel: config.plugins.channel });49
this.catalog = result.plugins;50
this.sourceBaseUrl = result.sourceBaseUrl;51
this.logger?.info("Plugin catalog checked.", { count: this.catalog.length, channel: config.plugins.channel, sourceBaseUrl: this.sourceBaseUrl });52
return this.getState();53
} finally {54
this.operation = null;55
}56
}58
async install(releaseId) {59
if (this.operation) throw new Error("Another plugin operation is already running.");60
const plugin = this.catalog.find((item) => item.releaseId === String(releaseId || ""));61
if (!plugin) throw new Error("Selected plugin release is not in the current catalog.");62
this.operation = "installing";63
try {64
const provider = this.providerFactory(this.configStore.get().updates);65
const verified = await provider.downloadAndVerify(plugin);66
const result = this.installer.install(verified.path, plugin);67
try {68
const cleanup = provider.removeDownloadedPackage?.(verified.path);69
this.logger?.info("Installed plugin package removed from download cache.", {70
pluginId: plugin.id,71
releaseId: plugin.releaseId,72
removed: cleanup?.removed === true73
});74
} catch (error) {75
this.logger?.warn("Installed plugin package could not be removed from download cache.", {76
pluginId: plugin.id,77
releaseId: plugin.releaseId,78
message: error?.message || String(error)79
});80
}81
return { ...this.getState(), installedPlugin: result.manifest, reused: result.reused };82
} finally {83
this.operation = null;84
}85
}87
cleanupDownloads() {88
const provider = this.providerFactory(this.configStore.get().updates);89
return provider.cleanupDownloads?.() || { cleaned: false };90
}92
open(pluginId) {93
return this.runtime.open(pluginId);94
}96
uninstall(pluginId) {97
if (this.operation) throw new Error("Another plugin operation is already running.");98
const id = String(pluginId || "");99
this.runtime.close(id);100
const result = this.registry.removeInstalled(id);101
return { ...this.getState(), removedPluginId: result.removed ? id : null };102
}103
}105
module.exports = { PluginService };SHA-256: 889727250c37b43889ca107d973d21969b8d91e6d640013451ee0d9a3c0bd8db
Archive SHA-256: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0