Files
silo-server/internal/plugins/service_admin_config.go
T

65 lines
1.8 KiB
Go

package plugins
import (
"context"
"errors"
"fmt"
"strings"
"github.com/Silo-Server/silo-server/internal/pluginhost"
)
// ConfigValidationError indicates that the caller supplied an invalid key or
// a value that did not match the plugin's manifest global_config_schema.
// Callers (the admin HTTP handler) should map this to a 400-equivalent
// response.
type ConfigValidationError struct {
Message string
Cause error
}
func (e *ConfigValidationError) Error() string { return e.Message }
func (e *ConfigValidationError) Unwrap() error { return e.Cause }
// SetGlobalConfig validates a single global-config entry against the plugin's
// manifest schema, persists it, and stops the running plugin so the next
// invocation rebinds with the new configuration. Used by the admin HTTP
// handler at PUT /api/admin/plugins/installations/{id}/config.
func (s *Service) SetGlobalConfig(
ctx context.Context,
installationID int,
key string,
value map[string]any,
) error {
key = strings.TrimSpace(key)
if key == "" {
return &ConfigValidationError{Message: "config key is required"}
}
if s.configs == nil {
return fmt.Errorf("plugin config store not configured")
}
_, manifest, err := s.ensureInstallationCache(ctx, installationID, false)
if err != nil {
return err
}
if value == nil {
value = map[string]any{}
}
if err := ValidateGlobalConfigValue(manifest, key, value); err != nil {
return &ConfigValidationError{Message: err.Error(), Cause: err}
}
if err := s.configs.PutGlobalConfig(ctx, installationID, key, value); err != nil {
return fmt.Errorf("persist plugin config: %w", err)
}
if s.host != nil {
if err := s.host.Stop(installationID); err != nil && !errors.Is(err, pluginhost.ErrClientNotFound) {
return fmt.Errorf("reload plugin after config update: %w", err)
}
}
return nil
}