160 lines
5.0 KiB
Go
160 lines
5.0 KiB
Go
package extension_repo
|
|
|
|
import (
|
|
"fmt"
|
|
"seanime/internal/extension"
|
|
"seanime/internal/plugin"
|
|
"seanime/internal/util"
|
|
"seanime/internal/util/filecache"
|
|
"strings"
|
|
)
|
|
|
|
func getExtensionUserConfigBucketKey(extId string) string {
|
|
return fmt.Sprintf("ext_user_config_%s", extId)
|
|
}
|
|
|
|
var (
|
|
ErrMissingUserConfig = fmt.Errorf("extension: user config is missing")
|
|
ErrIncompatibleUserConfig = fmt.Errorf("extension: user config is incompatible")
|
|
)
|
|
|
|
// loadUserConfig loads the user config for the given extension by getting it from the cache and modifying the payload.
|
|
// This should be called before loading the extension.
|
|
// If the user config is absent OR the current user config is outdated, it will return an error.
|
|
// When an error is returned, the extension will not be loaded and the user will be prompted to update the extension on the frontend.
|
|
func (r *Repository) loadUserConfig(ext *extension.Extension) (err error) {
|
|
defer util.HandlePanicInModuleThen("extension_repo/loadUserConfig", func() {
|
|
err = nil
|
|
})
|
|
|
|
// If the extension doesn't define a user config, skip this step
|
|
if ext.UserConfig == nil {
|
|
return nil
|
|
}
|
|
|
|
bucket := filecache.NewPermanentBucket(getExtensionUserConfigBucketKey(ext.ID))
|
|
|
|
// Get the user config from the cache
|
|
var savedConfig extension.SavedUserConfig
|
|
found, _ := r.fileCacher.GetPerm(bucket, ext.ID, &savedConfig)
|
|
|
|
// No user config found but the extension requires it
|
|
if !found && ext.UserConfig.RequiresConfig {
|
|
return ErrMissingUserConfig
|
|
}
|
|
|
|
// If the user config is outdated, return an error
|
|
if found && savedConfig.Version != ext.UserConfig.Version {
|
|
return ErrIncompatibleUserConfig
|
|
}
|
|
|
|
// Store the user config so it's accessible inside the VMs
|
|
ext.SavedUserConfig = &savedConfig
|
|
if ext.SavedUserConfig.Values == nil {
|
|
ext.SavedUserConfig.Values = make(map[string]string)
|
|
}
|
|
ext.SavedUserConfig.Version = ext.UserConfig.Version
|
|
|
|
if found {
|
|
// Replace the placeholders in the payload with the saved values
|
|
for _, field := range ext.UserConfig.Fields {
|
|
savedValue, found := savedConfig.Values[field.Name]
|
|
if !found {
|
|
ext.Payload = strings.ReplaceAll(ext.Payload, fmt.Sprintf("{{%s}}", field.Name), field.Default)
|
|
ext.SavedUserConfig.Values[field.Name] = field.Default // Update saved config
|
|
} else {
|
|
ext.Payload = strings.ReplaceAll(ext.Payload, fmt.Sprintf("{{%s}}", field.Name), savedValue)
|
|
ext.SavedUserConfig.Values[field.Name] = savedValue // Update saved config
|
|
}
|
|
}
|
|
return nil
|
|
} else {
|
|
// If the user config is missing but isn't required, replace the placeholders with the default values
|
|
for _, field := range ext.UserConfig.Fields {
|
|
ext.Payload = strings.ReplaceAll(ext.Payload, fmt.Sprintf("{{%s}}", field.Name), field.Default)
|
|
ext.SavedUserConfig.Values[field.Name] = field.Default // Update saved config
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
type ExtensionUserConfig struct {
|
|
UserConfig *extension.UserConfig `json:"userConfig"`
|
|
SavedUserConfig *extension.SavedUserConfig `json:"savedUserConfig"`
|
|
}
|
|
|
|
func (r *Repository) GetExtensionUserConfig(id string) (ret *ExtensionUserConfig) {
|
|
ret = &ExtensionUserConfig{
|
|
UserConfig: nil,
|
|
SavedUserConfig: nil,
|
|
}
|
|
|
|
defer util.HandlePanicInModuleThen("extension_repo/GetExtensionUserConfig", func() {})
|
|
|
|
ext, found := r.extensionBank.Get(id)
|
|
if !found {
|
|
return
|
|
}
|
|
|
|
ret.UserConfig = ext.GetUserConfig()
|
|
|
|
bucket := filecache.NewPermanentBucket(getExtensionUserConfigBucketKey(id))
|
|
|
|
var savedConfig extension.SavedUserConfig
|
|
found, _ = r.fileCacher.GetPerm(bucket, id, &savedConfig)
|
|
|
|
if found {
|
|
ret.SavedUserConfig = &savedConfig
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (r *Repository) SaveExtensionUserConfig(id string, savedConfig *extension.SavedUserConfig) (err error) {
|
|
defer util.HandlePanicInModuleWithError("extension_repo/SaveExtensionUserConfig", &err)
|
|
|
|
// Save the config
|
|
bucket := filecache.NewPermanentBucket(getExtensionUserConfigBucketKey(id))
|
|
err = r.fileCacher.SetPerm(bucket, id, savedConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If the extension is built-in, reload it
|
|
builtinExt, isBuiltIn := r.builtinExtensions.Get(id)
|
|
if isBuiltIn {
|
|
r.reloadBuiltInExtension(builtinExt.Extension, builtinExt.provider)
|
|
return nil
|
|
}
|
|
|
|
// Reload the extension
|
|
r.reloadExtension(id)
|
|
|
|
return nil
|
|
}
|
|
|
|
// This should be called when the extension is uninstalled
|
|
func (r *Repository) deleteExtensionUserConfig(id string) (err error) {
|
|
defer util.HandlePanicInModuleWithError("extension_repo/deleteExtensionUserConfig", &err)
|
|
|
|
// Delete the config
|
|
bucket := filecache.NewPermanentBucket(getExtensionUserConfigBucketKey(id))
|
|
err = r.fileCacher.RemovePerm(bucket.Name())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// This should be called when the extension is uninstalled
|
|
func (r *Repository) deletePluginData(id string) {
|
|
defer util.HandlePanicInModuleThen("extension_repo/deletePluginData", func() {
|
|
})
|
|
|
|
plugin.GlobalAppContext.DropPluginData(id)
|
|
}
|