platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
116
selective-vpn-api/app/smartdns_runtime_config.go
Normal file
116
selective-vpn-api/app/smartdns_runtime_config.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func smartDNSRuntimeEnabledFromConfig() (bool, error) {
|
||||
data, err := os.ReadFile(smartdnsMainConfig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, raw := range strings.Split(string(data), "\n") {
|
||||
trimmed := strings.TrimSpace(raw)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(trimmed, "nftset") &&
|
||||
strings.Contains(trimmed, "domain-set:agvpn_wild") &&
|
||||
strings.Contains(trimmed, "agvpn_dyn4") {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func normalizeSmartDNSMainConfig(content string, enabled bool) string {
|
||||
normalized := strings.ReplaceAll(content, "\r\n", "\n")
|
||||
lines := strings.Split(normalized, "\n")
|
||||
out := make([]string, 0, len(lines)+4)
|
||||
|
||||
seenDomain := false
|
||||
seenNftset := false
|
||||
|
||||
isDomainLine := func(raw string) bool {
|
||||
t := strings.TrimSpace(raw)
|
||||
if strings.HasPrefix(t, "#") {
|
||||
t = strings.TrimSpace(strings.TrimPrefix(t, "#"))
|
||||
}
|
||||
return strings.HasPrefix(t, "domain-set ") &&
|
||||
strings.Contains(t, "-name agvpn_wild") &&
|
||||
strings.Contains(t, "/etc/selective-vpn/smartdns.conf")
|
||||
}
|
||||
isNftsetLine := func(raw string) bool {
|
||||
t := strings.TrimSpace(raw)
|
||||
if strings.HasPrefix(t, "#") {
|
||||
t = strings.TrimSpace(strings.TrimPrefix(t, "#"))
|
||||
}
|
||||
return strings.HasPrefix(t, "nftset ") &&
|
||||
strings.Contains(t, "domain-set:agvpn_wild") &&
|
||||
strings.Contains(t, "agvpn_dyn4")
|
||||
}
|
||||
|
||||
for _, raw := range lines {
|
||||
switch {
|
||||
case isDomainLine(raw):
|
||||
if !seenDomain {
|
||||
if enabled {
|
||||
out = append(out, smartdnsRuntimeDomainSetLine)
|
||||
} else {
|
||||
out = append(out, "# "+smartdnsRuntimeDomainSetLine)
|
||||
}
|
||||
seenDomain = true
|
||||
}
|
||||
case isNftsetLine(raw):
|
||||
if !seenNftset {
|
||||
if enabled {
|
||||
out = append(out, smartdnsRuntimeNftsetLine)
|
||||
} else {
|
||||
out = append(out, "# "+smartdnsRuntimeNftsetLine)
|
||||
}
|
||||
seenNftset = true
|
||||
}
|
||||
default:
|
||||
out = append(out, raw)
|
||||
}
|
||||
}
|
||||
|
||||
if enabled && (!seenDomain || !seenNftset) {
|
||||
if len(out) > 0 && strings.TrimSpace(out[len(out)-1]) != "" {
|
||||
out = append(out, "")
|
||||
}
|
||||
if !seenDomain {
|
||||
out = append(out, smartdnsRuntimeDomainSetLine)
|
||||
}
|
||||
if !seenNftset {
|
||||
out = append(out, smartdnsRuntimeNftsetLine)
|
||||
}
|
||||
}
|
||||
|
||||
rendered := strings.Join(out, "\n")
|
||||
if !strings.HasSuffix(rendered, "\n") {
|
||||
rendered += "\n"
|
||||
}
|
||||
return rendered
|
||||
}
|
||||
|
||||
func applySmartDNSRuntimeConfig(enabled bool) (bool, error) {
|
||||
data, err := os.ReadFile(smartdnsMainConfig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
current := strings.ReplaceAll(string(data), "\r\n", "\n")
|
||||
next := normalizeSmartDNSMainConfig(current, enabled)
|
||||
if next == current {
|
||||
return false, nil
|
||||
}
|
||||
tmp := smartdnsMainConfig + ".tmp"
|
||||
if err := os.WriteFile(tmp, []byte(next), 0o644); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := os.Rename(tmp, smartdnsMainConfig); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user