From 584cc765cbf775ad2c40ca262ae60533e5bf8eb8 Mon Sep 17 00:00:00 2001 From: grimsi <9295182+grimsi@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:36:39 +0100 Subject: [PATCH] Implement PluginManagementService --- .../DatabasePluginStatusProvider.kt | 32 ++++++++++++ .../management/GameyfinPluginManager.kt | 51 +++++++++++++++++-- .../management/PluginManagementEndpoint.kt | 4 ++ .../management/PluginManagementEntry.kt | 19 +++++++ .../management/PluginManagementRepository.kt | 5 ++ .../management/PluginManagementService.kt | 8 +++ .../plugins/management/PluginManagerConfig.kt | 23 ++++----- 7 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/DatabasePluginStatusProvider.kt create mode 100644 gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEntry.kt create mode 100644 gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementRepository.kt diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/DatabasePluginStatusProvider.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/DatabasePluginStatusProvider.kt new file mode 100644 index 0000000..172731e --- /dev/null +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/DatabasePluginStatusProvider.kt @@ -0,0 +1,32 @@ +package de.grimsi.gameyfin.core.plugins.management + +import org.pf4j.PluginStatusProvider +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Component + +@Component +class DatabasePluginStatusProvider( + private val pluginManagementRepository: PluginManagementRepository +) : PluginStatusProvider { + + override fun isPluginDisabled(pluginId: String): Boolean { + val pluginManagement = pluginManagementRepository.findByIdOrNull(pluginId) + return pluginManagement?.enabled != true + } + + override fun disablePlugin(pluginId: String) { + val pluginManagement = pluginManagementRepository.findByIdOrNull(pluginId) + if (pluginManagement != null) { + pluginManagement.enabled = true + pluginManagementRepository.save(pluginManagement) + } + } + + override fun enablePlugin(pluginId: String) { + val pluginManagement = pluginManagementRepository.findByIdOrNull(pluginId) + if (pluginManagement != null) { + pluginManagement.enabled = false + pluginManagementRepository.save(pluginManagement) + } + } +} \ No newline at end of file diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/GameyfinPluginManager.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/GameyfinPluginManager.kt index bbebf1d..8c60873 100644 --- a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/GameyfinPluginManager.kt +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/GameyfinPluginManager.kt @@ -3,26 +3,41 @@ package de.grimsi.gameyfin.core.plugins.management import de.grimsi.gameyfin.core.plugins.config.PluginConfigRepository import de.grimsi.gameyfin.pluginapi.core.GameyfinPlugin import io.github.oshai.kotlinlogging.KotlinLogging +import org.pf4j.AbstractPluginManager +import org.pf4j.CompoundPluginDescriptorFinder import org.pf4j.CompoundPluginLoader import org.pf4j.CompoundPluginRepository +import org.pf4j.DefaultExtensionFactory +import org.pf4j.DefaultExtensionFinder +import org.pf4j.DefaultPluginFactory import org.pf4j.DefaultPluginLoader -import org.pf4j.DefaultPluginManager import org.pf4j.DefaultPluginRepository +import org.pf4j.DefaultVersionManager import org.pf4j.DevelopmentPluginRepository +import org.pf4j.ExtensionFactory +import org.pf4j.ExtensionFinder import org.pf4j.JarPluginLoader import org.pf4j.JarPluginRepository +import org.pf4j.ManifestPluginDescriptorFinder +import org.pf4j.PluginDescriptorFinder +import org.pf4j.PluginFactory import org.pf4j.PluginLoader import org.pf4j.PluginRepository +import org.pf4j.PluginStatusProvider import org.pf4j.PluginWrapper +import org.pf4j.PropertiesPluginDescriptorFinder +import org.pf4j.VersionManager +import org.springframework.stereotype.Component import java.nio.file.Path /** * @see https://stackoverflow.com/questions/73654174/my-application-cant-find-the-extension-with-pf4j */ +@Component class GameyfinPluginManager( - path: Path, - private val pluginConfigRepository: PluginConfigRepository -) : DefaultPluginManager(path) { + private val pluginConfigRepository: PluginConfigRepository, + private val pluginStatusProvider: DatabasePluginStatusProvider +) : AbstractPluginManager() { private val log = KotlinLogging.logger {} @@ -33,6 +48,26 @@ class GameyfinPluginManager( .add(DefaultPluginRepository(pluginsRoots), this::isNotDevelopment) } + override fun createPluginFactory(): PluginFactory { + return DefaultPluginFactory() + } + + override fun createExtensionFactory(): ExtensionFactory { + return DefaultExtensionFactory() + } + + override fun createPluginDescriptorFinder(): PluginDescriptorFinder { + return CompoundPluginDescriptorFinder() + .add(PropertiesPluginDescriptorFinder()) + .add(ManifestPluginDescriptorFinder()) + } + + override fun createExtensionFinder(): ExtensionFinder { + val extensionFinder = DefaultExtensionFinder(this) + addPluginStateListener(extensionFinder) + return extensionFinder + } + override fun createPluginLoader(): PluginLoader { val compoundPluginLoader = CompoundPluginLoader() val developmentPluginLoader = GameyfinPluginLoader(this, javaClass.classLoader) @@ -45,6 +80,14 @@ class GameyfinPluginManager( .add(defaultPluginLoader, this::isNotDevelopment) } + override fun createVersionManager(): VersionManager? { + return DefaultVersionManager() + } + + override fun createPluginStatusProvider(): PluginStatusProvider { + return pluginStatusProvider + } + override fun loadPluginFromPath(pluginPath: Path?): PluginWrapper? { val pluginWrapper = super.loadPluginFromPath(pluginPath) diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEndpoint.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEndpoint.kt index be5c478..86dcf0d 100644 --- a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEndpoint.kt +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEndpoint.kt @@ -16,4 +16,8 @@ class PluginManagementEndpoint( fun stopPlugin(pluginId: String) = pluginManagementService.stopPlugin(pluginId) fun restartPlugin(pluginId: String) = pluginManagementService.restartPlugin(pluginId) + + fun enablePlugin(pluginId: String) = pluginManagementService.enablePlugin(pluginId) + + fun disablePlugin(pluginId: String) = pluginManagementService.disablePlugin(pluginId) } \ No newline at end of file diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEntry.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEntry.kt new file mode 100644 index 0000000..39d5410 --- /dev/null +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementEntry.kt @@ -0,0 +1,19 @@ +package de.grimsi.gameyfin.core.plugins.management + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import jakarta.validation.constraints.NotNull + +@Entity +@Table(name = "plugin_management") +data class PluginManagementEntry( + @Id + @Column(name = "plugin_id") + val pluginId: String, + + @NotNull + @Column(name = "enabled") + var enabled: Boolean = true +) \ No newline at end of file diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementRepository.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementRepository.kt new file mode 100644 index 0000000..12ab46c --- /dev/null +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementRepository.kt @@ -0,0 +1,5 @@ +package de.grimsi.gameyfin.core.plugins.management + +import org.springframework.data.jpa.repository.JpaRepository + +interface PluginManagementRepository : JpaRepository \ No newline at end of file diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementService.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementService.kt index 2d4582a..38cf7f9 100644 --- a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementService.kt +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagementService.kt @@ -29,4 +29,12 @@ class PluginManagementService( fun restartPlugin(pluginId: String) { pluginManager.restart(pluginId) } + + fun enablePlugin(pluginId: String) { + pluginManager.enablePlugin(pluginId) + } + + fun disablePlugin(pluginId: String) { + pluginManager.disablePlugin(pluginId) + } } \ No newline at end of file diff --git a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagerConfig.kt b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagerConfig.kt index af383c2..93eea09 100644 --- a/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagerConfig.kt +++ b/gameyfin/src/main/kotlin/de/grimsi/gameyfin/core/plugins/management/PluginManagerConfig.kt @@ -2,26 +2,25 @@ package de.grimsi.gameyfin.core.plugins.management import de.grimsi.gameyfin.core.plugins.config.PluginConfigRepository import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.context.event.EventListener -import java.nio.file.Path @Configuration class PluginManagerConfig( - private val pluginConfigRepository: PluginConfigRepository + private val pluginConfigRepository: PluginConfigRepository, + private val dbPluginStatusProvider: DatabasePluginStatusProvider ) { private val log = KotlinLogging.logger {} - private val pluginPath = System.getProperty("pf4j.pluginsDir", "plugins") @Bean - fun pluginManager() = GameyfinPluginManager(Path.of(pluginPath), pluginConfigRepository) - - @EventListener(ApplicationReadyEvent::class) - fun loadPlugins() { - pluginManager().loadPlugins() - pluginManager().startPlugins() - log.info { "Loaded plugins: ${pluginManager().plugins.map { it.pluginId }}" } + fun gameyfinPluginManager(): GameyfinPluginManager { + return GameyfinPluginManager(pluginConfigRepository, dbPluginStatusProvider) } + + /*@EventListener(ApplicationReadyEvent::class) + fun loadPlugins() { + gameyfinPluginManager().loadPlugins() + gameyfinPluginManager().startPlugins() + log.info { "Loaded plugins: ${gameyfinPluginManager().plugins.map { it.pluginId }}" } + }*/ } \ No newline at end of file