mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Verify plugin config before starting plugin
Fix issue with SLF4J in plugins
This commit is contained in:
@@ -39,6 +39,7 @@ export default function PluginManagement() {
|
||||
<div className="flex flex-row flex-grow justify-between my-8">
|
||||
<h2 className="text-xl font-bold">Notifications</h2>
|
||||
</div>
|
||||
<p>Notification plugins not yet supported.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react";
|
||||
import {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@nextui-org/react";
|
||||
import {toast} from "sonner";
|
||||
import {Form, Formik} from "formik";
|
||||
import {PluginConfigEndpoint} from "Frontend/generated/endpoints";
|
||||
import {PluginConfigEndpoint, PluginManagementEndpoint} from "Frontend/generated/endpoints";
|
||||
import PluginDto from "Frontend/generated/de/grimsi/gameyfin/core/plugins/management/PluginDto";
|
||||
import PluginConfigElement from "Frontend/generated/de/grimsi/gameyfin/pluginapi/core/PluginConfigElement";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
@@ -12,9 +12,10 @@ interface PluginDetailsModalProps {
|
||||
plugin: PluginDto;
|
||||
isOpen: boolean;
|
||||
onOpenChange: () => void;
|
||||
updatePlugin: (plugin: PluginDto) => void;
|
||||
}
|
||||
|
||||
export default function PluginDetailsModal({plugin, isOpen, onOpenChange}: PluginDetailsModalProps) {
|
||||
export default function PluginDetailsModal({plugin, isOpen, onOpenChange, updatePlugin}: PluginDetailsModalProps) {
|
||||
const [pluginConfigMeta, setPluginConfigMeta] = useState<(PluginConfigElement)[]>();
|
||||
const [pluginConfig, setPluginConfig] = useState<Record<string, string>>();
|
||||
|
||||
@@ -32,6 +33,9 @@ export default function PluginDetailsModal({plugin, isOpen, onOpenChange}: Plugi
|
||||
async function saveConfig(values: Record<string, string>) {
|
||||
await PluginConfigEndpoint.setConfigEntries(plugin.id, values);
|
||||
toast.success(`Configuration for ${plugin.name} saved!`);
|
||||
let updatedPlugin = await PluginManagementEndpoint.getPlugin(plugin.id);
|
||||
if (updatedPlugin === undefined) return;
|
||||
updatePlugin(updatedPlugin);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -18,11 +18,7 @@ export function PluginManagementCard({plugin, updatePlugin}: {
|
||||
if (response === undefined) return;
|
||||
setConfigValid(response);
|
||||
});
|
||||
}, []);
|
||||
|
||||
function iconColor(state: PluginState | undefined): "white" | "default" {
|
||||
return "default";
|
||||
}
|
||||
}, [pluginDetailsModal.isOpen]);
|
||||
|
||||
function borderColor(state: PluginState | undefined): "success" | "warning" | "danger" | "default" {
|
||||
if (isDisabled(state)) return "warning";
|
||||
@@ -37,7 +33,7 @@ export function PluginManagementCard({plugin, updatePlugin}: {
|
||||
return "success";
|
||||
case PluginState.DISABLED:
|
||||
return "warning";
|
||||
case PluginState.STOPPED:
|
||||
case PluginState.FAILED:
|
||||
return "danger";
|
||||
default:
|
||||
return "default";
|
||||
@@ -101,6 +97,7 @@ export function PluginManagementCard({plugin, updatePlugin}: {
|
||||
<PluginDetailsModal plugin={plugin}
|
||||
isOpen={pluginDetailsModal.isOpen}
|
||||
onOpenChange={pluginDetailsModal.onOpenChange}
|
||||
updatePlugin={updatePlugin}
|
||||
/>
|
||||
</>
|
||||
|
||||
|
||||
+8
-2
@@ -10,8 +10,14 @@ class DatabasePluginStatusProvider(
|
||||
) : PluginStatusProvider {
|
||||
|
||||
override fun isPluginDisabled(pluginId: String): Boolean {
|
||||
val pluginManagement = pluginManagementRepository.findByIdOrNull(pluginId)
|
||||
return pluginManagement?.enabled != true
|
||||
var pluginManagement = pluginManagementRepository.findByIdOrNull(pluginId)
|
||||
|
||||
// If the plugin is unknown, persist it as enabled
|
||||
if(pluginManagement == null) {
|
||||
pluginManagement = pluginManagementRepository.save(PluginManagementEntry(pluginId = pluginId, enabled = true))
|
||||
}
|
||||
|
||||
return pluginManagement.enabled != true
|
||||
}
|
||||
|
||||
override fun disablePlugin(pluginId: String) {
|
||||
|
||||
+53
-2
@@ -63,11 +63,62 @@ class GameyfinPluginManager(
|
||||
return pluginWrapper
|
||||
}
|
||||
|
||||
override fun startPlugin(pluginId: String?): PluginState? {
|
||||
if(pluginId == null) return PluginState.FAILED
|
||||
|
||||
// Validate config before starting the plugin
|
||||
if (!validatePluginConfig(pluginId)) {
|
||||
log.error { "Plugin $pluginId has invalid configuration" }
|
||||
|
||||
val pluginWrapper = getPlugin(pluginId)
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
this.firePluginStateEvent(PluginStateEvent(this, pluginWrapper, pluginWrapper.pluginState));
|
||||
return pluginWrapper.pluginState
|
||||
}
|
||||
|
||||
return super.startPlugin(pluginId)
|
||||
}
|
||||
|
||||
override fun startPlugins() {
|
||||
for (pluginWrapper in resolvedPlugins) {
|
||||
val pluginState = pluginWrapper.pluginState
|
||||
if (!pluginState.isDisabled && !pluginState.isStarted) {
|
||||
|
||||
// Validate config before starting the plugin
|
||||
if (!validatePluginConfig(pluginWrapper.pluginId)) {
|
||||
log.error { "Plugin ${pluginWrapper.pluginId} has invalid configuration" }
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
|
||||
firePluginStateEvent(PluginStateEvent(this, pluginWrapper, pluginState))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
log.info { "${"Start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)}"}
|
||||
pluginWrapper.plugin.start()
|
||||
pluginWrapper.pluginState = PluginState.STARTED
|
||||
pluginWrapper.failedException = null
|
||||
startedPlugins.add(pluginWrapper)
|
||||
} catch (e: LinkageError) {
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
pluginWrapper.failedException = e
|
||||
log.error { "${"Unable to start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)} $e"}
|
||||
} catch (e: Exception) {
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
pluginWrapper.failedException = e
|
||||
log.error { "${"Unable to start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)} $e"}
|
||||
} finally {
|
||||
firePluginStateEvent(PluginStateEvent(this, pluginWrapper, pluginState))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun restart(pluginId: String) {
|
||||
val plugin = getPlugin(pluginId)?.plugin ?: return
|
||||
plugin.stop()
|
||||
stopPlugin(pluginId)
|
||||
(plugin as GameyfinPlugin).loadConfig(getConfig(pluginId))
|
||||
plugin.start()
|
||||
startPlugin(pluginId)
|
||||
}
|
||||
|
||||
fun validatePluginConfig(pluginId: String): Boolean {
|
||||
|
||||
@@ -10,11 +10,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
// PF4J (shared)
|
||||
api("org.pf4j:pf4j:${rootProject.extra["pf4jVersion"]}") {
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
|
||||
api("org.slf4j:slf4j-api:2.0.16")
|
||||
api("org.pf4j:pf4j:${rootProject.extra["pf4jVersion"]}")
|
||||
|
||||
implementation(kotlin("stdlib"))
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import kotlinx.serialization.json.*
|
||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||
import org.pf4j.Extension
|
||||
import org.pf4j.PluginWrapper
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.time.Instant
|
||||
@@ -66,6 +68,8 @@ class SteamPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
|
||||
|
||||
@Extension
|
||||
class SteamMetadataProvider : GameMetadataProvider {
|
||||
val log: Logger = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
val client = HttpClient(CIO) {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
@@ -89,7 +93,7 @@ class SteamPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
|
||||
val searchResult: SteamSearchResult = client.get(url).body()
|
||||
searchResult.items
|
||||
} catch (e: Exception) {
|
||||
println(e.message)
|
||||
log.error("Failed to search Steam store: ${e.message}")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user