Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
229
backend/internal/pluginhost/config.go
Normal file
229
backend/internal/pluginhost/config.go
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
package pluginhost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/config"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var defaultRuntimeConfigYAML = []byte("enabled: false\npriority: 0\n")
|
||||
|
||||
type runtimeConfig struct {
|
||||
Enabled bool
|
||||
Dir string
|
||||
Items map[string]runtimeItemConfig
|
||||
}
|
||||
|
||||
type runtimeItemConfig struct {
|
||||
ID string
|
||||
Enabled bool
|
||||
Priority int
|
||||
Version string
|
||||
ConfigYAML []byte
|
||||
}
|
||||
|
||||
func runtimeConfigFromConfig(cfg *config.Config) (runtimeConfig, error) {
|
||||
out := runtimeConfig{
|
||||
Dir: "plugins",
|
||||
Items: make(map[string]runtimeItemConfig),
|
||||
}
|
||||
if cfg == nil {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
out.Enabled = cfg.Plugins.Enabled
|
||||
if !out.Enabled {
|
||||
return out, nil
|
||||
}
|
||||
pluginsDir, errResolvePluginsDir := config.ResolvePluginsDir(cfg.Plugins.Dir)
|
||||
if errResolvePluginsDir != nil {
|
||||
return runtimeConfig{}, errResolvePluginsDir
|
||||
}
|
||||
out.Dir = pluginsDir
|
||||
|
||||
ids := make([]string, 0, len(cfg.Plugins.Configs))
|
||||
for id := range cfg.Plugins.Configs {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Strings(ids)
|
||||
|
||||
for _, id := range ids {
|
||||
item := cfg.Plugins.Configs[id]
|
||||
enabled := false
|
||||
if item.Enabled != nil {
|
||||
enabled = *item.Enabled
|
||||
}
|
||||
|
||||
out.Items[id] = runtimeItemConfig{
|
||||
ID: id,
|
||||
Enabled: enabled,
|
||||
Priority: item.Priority,
|
||||
Version: pluginConfigDesiredVersion(item),
|
||||
ConfigYAML: runtimeConfigYAML(item, enabled),
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func defaultRuntimeItemConfig(id string) runtimeItemConfig {
|
||||
return runtimeItemConfig{
|
||||
ID: id,
|
||||
Enabled: false,
|
||||
Priority: 0,
|
||||
ConfigYAML: append([]byte(nil), defaultRuntimeConfigYAML...),
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeConfigYAML(item config.PluginInstanceConfig, enabled bool) []byte {
|
||||
rawNode := normalizedConfigNode(item, enabled)
|
||||
rawYAML := bytes.TrimSpace(mustMarshalYAML(rawNode))
|
||||
if len(rawYAML) == 0 {
|
||||
return append([]byte(nil), defaultRuntimeConfigYAML...)
|
||||
}
|
||||
return append(append([]byte(nil), rawYAML...), '\n')
|
||||
}
|
||||
|
||||
func desiredPluginVersions(items map[string]runtimeItemConfig) map[string]string {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]string, len(items))
|
||||
for id, item := range items {
|
||||
id = strings.TrimSpace(id)
|
||||
version := strings.TrimSpace(item.Version)
|
||||
if id == "" || version == "" {
|
||||
continue
|
||||
}
|
||||
out[id] = version
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func pluginConfigDesiredVersion(item config.PluginInstanceConfig) string {
|
||||
storeNode := yamlMappingValue(&item.Raw, "store")
|
||||
if storeNode == nil {
|
||||
return ""
|
||||
}
|
||||
if version := normalizePluginDesiredVersion(yamlScalarString(yamlMappingValue(storeNode, "version"))); version != "" {
|
||||
return version
|
||||
}
|
||||
return normalizePluginDesiredVersion(yamlScalarString(yamlMappingValue(storeNode, "release-tag")))
|
||||
}
|
||||
|
||||
func normalizePluginDesiredVersion(version string) string {
|
||||
version = strings.TrimSpace(version)
|
||||
if len(version) > 1 && (version[0] == 'v' || version[0] == 'V') {
|
||||
version = version[1:]
|
||||
}
|
||||
if !validPluginVersion(version) {
|
||||
return ""
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func yamlScalarString(node *yaml.Node) string {
|
||||
if node == nil || node.Kind == 0 {
|
||||
return ""
|
||||
}
|
||||
if node.Kind == yaml.ScalarNode {
|
||||
return strings.TrimSpace(node.Value)
|
||||
}
|
||||
var value string
|
||||
if errDecode := node.Decode(&value); errDecode != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
|
||||
func yamlMappingValue(node *yaml.Node, key string) *yaml.Node {
|
||||
if node == nil || node.Kind != yaml.MappingNode {
|
||||
return nil
|
||||
}
|
||||
for index := 0; index+1 < len(node.Content); index += 2 {
|
||||
if node.Content[index] != nil && node.Content[index].Value == key {
|
||||
return node.Content[index+1]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizedConfigNode(item config.PluginInstanceConfig, enabled bool) *yaml.Node {
|
||||
if item.Raw.Kind == 0 {
|
||||
return defaultRuntimeConfigNode(enabled, item.Priority)
|
||||
}
|
||||
node := deepCopyYAMLNode(&item.Raw)
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return node
|
||||
}
|
||||
ensureMappingScalar(node, "enabled", boolYAMLValue(enabled), "!!bool")
|
||||
ensureMappingScalar(node, "priority", intYAMLValue(item.Priority), "!!int")
|
||||
return node
|
||||
}
|
||||
|
||||
func defaultRuntimeConfigNode(enabled bool, priority int) *yaml.Node {
|
||||
return &yaml.Node{
|
||||
Kind: yaml.MappingNode,
|
||||
Tag: "!!map",
|
||||
Content: []*yaml.Node{
|
||||
{Kind: yaml.ScalarNode, Tag: "!!str", Value: "enabled"},
|
||||
{Kind: yaml.ScalarNode, Tag: "!!bool", Value: boolYAMLValue(enabled)},
|
||||
{Kind: yaml.ScalarNode, Tag: "!!str", Value: "priority"},
|
||||
{Kind: yaml.ScalarNode, Tag: "!!int", Value: intYAMLValue(priority)},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ensureMappingScalar(node *yaml.Node, key, value, tag string) {
|
||||
if node == nil || node.Kind != yaml.MappingNode {
|
||||
return
|
||||
}
|
||||
for i := 0; i+1 < len(node.Content); i += 2 {
|
||||
if node.Content[i] != nil && node.Content[i].Value == key {
|
||||
return
|
||||
}
|
||||
}
|
||||
node.Content = append(node.Content,
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: key},
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Tag: tag, Value: value},
|
||||
)
|
||||
}
|
||||
|
||||
func boolYAMLValue(v bool) string {
|
||||
if v {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
|
||||
func intYAMLValue(v int) string {
|
||||
return strconv.Itoa(v)
|
||||
}
|
||||
|
||||
func deepCopyYAMLNode(node *yaml.Node) *yaml.Node {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
copyNode := *node
|
||||
if len(node.Content) > 0 {
|
||||
copyNode.Content = make([]*yaml.Node, 0, len(node.Content))
|
||||
for _, child := range node.Content {
|
||||
copyNode.Content = append(copyNode.Content, deepCopyYAMLNode(child))
|
||||
}
|
||||
}
|
||||
return ©Node
|
||||
}
|
||||
|
||||
func mustMarshalYAML(v any) []byte {
|
||||
raw, errMarshal := yaml.Marshal(v)
|
||||
if errMarshal != nil {
|
||||
return append([]byte(nil), defaultRuntimeConfigYAML...)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
Loading…
Reference in a new issue