first commit
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
This commit is contained in:
183
internal/generator/provider.go
Normal file
183
internal/generator/provider.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProviderHealthDefinition captures optional health-check settings for providers.
|
||||
type ProviderHealthDefinition struct {
|
||||
Enable *bool
|
||||
URL string
|
||||
Interval *int
|
||||
Lazy *bool
|
||||
Tolerance *int
|
||||
Timeout *int
|
||||
Method string
|
||||
Headers string
|
||||
}
|
||||
|
||||
// ProviderDefinition represents a parsed proxy provider entry.
|
||||
type ProviderDefinition struct {
|
||||
Name string
|
||||
Type string
|
||||
URL string
|
||||
Path string
|
||||
Interval *int
|
||||
Flags map[string]bool
|
||||
Fields map[string]string
|
||||
Health *ProviderHealthDefinition
|
||||
}
|
||||
|
||||
// ParseProviderDefinition converts an encoded provider definition (query string style)
|
||||
// into a structured ProviderDefinition instance.
|
||||
func ParseProviderDefinition(definition string) (*ProviderDefinition, error) {
|
||||
values, err := url.ParseQuery(definition)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid provider definition: %v", err)
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(values.Get("name"))
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("custom provider missing name")
|
||||
}
|
||||
|
||||
providerType := strings.TrimSpace(values.Get("type"))
|
||||
if providerType == "" {
|
||||
providerType = "http"
|
||||
}
|
||||
|
||||
urlValue := strings.TrimSpace(values.Get("url"))
|
||||
if urlValue == "" {
|
||||
return nil, fmt.Errorf("custom provider %s missing url", name)
|
||||
}
|
||||
|
||||
pathValue := strings.TrimSpace(values.Get("path"))
|
||||
if pathValue == "" {
|
||||
return nil, fmt.Errorf("custom provider %s missing path", name)
|
||||
}
|
||||
|
||||
def := &ProviderDefinition{
|
||||
Name: name,
|
||||
Type: providerType,
|
||||
URL: urlValue,
|
||||
Path: pathValue,
|
||||
Flags: make(map[string]bool),
|
||||
Fields: make(map[string]string),
|
||||
}
|
||||
|
||||
if raw := strings.TrimSpace(values.Get("interval")); raw != "" {
|
||||
if n, err := strconv.Atoi(raw); err == nil && n >= 0 {
|
||||
def.Interval = &n
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid interval for provider %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
boolFields := []struct {
|
||||
Query string
|
||||
Key string
|
||||
}{
|
||||
{"lazy", "lazy"},
|
||||
{"skip_cert_verify", "skip-cert-verify"},
|
||||
{"override", "override"},
|
||||
{"failover", "failover"},
|
||||
}
|
||||
|
||||
for _, field := range boolFields {
|
||||
if raw := strings.TrimSpace(values.Get(field.Query)); raw != "" {
|
||||
val, err := strconv.ParseBool(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid %s for provider %s: %v", field.Query, name, err)
|
||||
}
|
||||
def.Flags[field.Key] = val
|
||||
}
|
||||
}
|
||||
|
||||
stringFields := []string{"header", "headers", "filter", "format", "path_backup"}
|
||||
for _, key := range stringFields {
|
||||
if raw := strings.TrimSpace(values.Get(key)); raw != "" {
|
||||
def.Fields[strings.ReplaceAll(key, "_", "-")] = raw
|
||||
}
|
||||
}
|
||||
|
||||
health := &ProviderHealthDefinition{}
|
||||
setHealth := false
|
||||
if raw := strings.TrimSpace(values.Get("health_enable")); raw != "" {
|
||||
val, err := strconv.ParseBool(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid health_enable for provider %s: %v", name, err)
|
||||
}
|
||||
health.Enable = &val
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_url")); raw != "" {
|
||||
health.URL = raw
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_interval")); raw != "" {
|
||||
if n, err := strconv.Atoi(raw); err == nil && n >= 0 {
|
||||
health.Interval = &n
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid health_interval for provider %s: %v", name, err)
|
||||
}
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_lazy")); raw != "" {
|
||||
val, err := strconv.ParseBool(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid health_lazy for provider %s: %v", name, err)
|
||||
}
|
||||
health.Lazy = &val
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_tolerance")); raw != "" {
|
||||
if n, err := strconv.Atoi(raw); err == nil && n >= 0 {
|
||||
health.Tolerance = &n
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid health_tolerance for provider %s: %v", name, err)
|
||||
}
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_timeout")); raw != "" {
|
||||
if n, err := strconv.Atoi(raw); err == nil && n >= 0 {
|
||||
health.Timeout = &n
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid health_timeout for provider %s: %v", name, err)
|
||||
}
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_method")); raw != "" {
|
||||
health.Method = raw
|
||||
setHealth = true
|
||||
}
|
||||
if raw := strings.TrimSpace(values.Get("health_headers")); raw != "" {
|
||||
health.Headers = raw
|
||||
setHealth = true
|
||||
}
|
||||
if setHealth {
|
||||
def.Health = health
|
||||
}
|
||||
|
||||
// Capture any remaining custom fields not explicitly handled.
|
||||
for key, vals := range values {
|
||||
if key == "name" || key == "type" || key == "url" || key == "path" || key == "interval" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(key, "health_") || key == "lazy" || key == "skip_cert_verify" || key == "override" || key == "failover" || key == "header" || key == "headers" || key == "filter" || key == "format" || key == "path_backup" {
|
||||
continue
|
||||
}
|
||||
if len(vals) == 0 {
|
||||
continue
|
||||
}
|
||||
value := strings.TrimSpace(vals[len(vals)-1])
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
def.Fields[strings.ReplaceAll(key, "_", "-")] = value
|
||||
}
|
||||
|
||||
return def, nil
|
||||
}
|
||||
Reference in New Issue
Block a user