platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
210
selective-vpn-api/app/transportcfg/runtime_helpers.go
Normal file
210
selective-vpn-api/app/transportcfg/runtime_helpers.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package transportcfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
KindSingBox = "singbox"
|
||||
KindDNSTT = "dnstt"
|
||||
KindPhoenix = "phoenix"
|
||||
|
||||
defaultSingBoxUnitTemplate = "singbox@.service"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
ID string
|
||||
Kind string
|
||||
Config map[string]any
|
||||
}
|
||||
|
||||
func BackendUnit(client Client) string {
|
||||
kind := strings.ToLower(strings.TrimSpace(client.Kind))
|
||||
unit := strings.TrimSpace(ConfigString(client.Config, "unit"))
|
||||
if kind == KindSingBox {
|
||||
return resolveSingBoxBackendUnit(client.ID, unit)
|
||||
}
|
||||
if unit != "" {
|
||||
return unit
|
||||
}
|
||||
return DefaultBackendUnit(kind)
|
||||
}
|
||||
|
||||
func DefaultBackendUnit(kind string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(kind)) {
|
||||
case KindSingBox:
|
||||
return defaultSingBoxUnitTemplate
|
||||
case KindDNSTT:
|
||||
return "dnstt-client.service"
|
||||
case KindPhoenix:
|
||||
return "phoenix.service"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func resolveSingBoxBackendUnit(clientID, configuredUnit string) string {
|
||||
unit := strings.TrimSpace(configuredUnit)
|
||||
if unit == "" {
|
||||
unit = defaultSingBoxUnitTemplate
|
||||
}
|
||||
if strings.HasSuffix(unit, "@.service") {
|
||||
instance := sanitizeSystemdInstanceID(clientID)
|
||||
if instance == "" {
|
||||
instance = "client"
|
||||
}
|
||||
return strings.TrimSuffix(unit, "@.service") + "@" + instance + ".service"
|
||||
}
|
||||
return unit
|
||||
}
|
||||
|
||||
func sanitizeSystemdInstanceID(in string) string {
|
||||
s := strings.ToLower(strings.TrimSpace(in))
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
var b strings.Builder
|
||||
b.Grow(len(s))
|
||||
lastDash := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
ch := s[i]
|
||||
if (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
|
||||
b.WriteByte(ch)
|
||||
lastDash = false
|
||||
continue
|
||||
}
|
||||
if ch == '-' {
|
||||
if lastDash {
|
||||
continue
|
||||
}
|
||||
b.WriteByte('-')
|
||||
lastDash = true
|
||||
continue
|
||||
}
|
||||
if !lastDash {
|
||||
b.WriteByte('-')
|
||||
lastDash = true
|
||||
}
|
||||
}
|
||||
return strings.Trim(b.String(), "-")
|
||||
}
|
||||
|
||||
func DNSTTSSHTunnelEnabled(client Client) bool {
|
||||
if strings.ToLower(strings.TrimSpace(client.Kind)) != KindDNSTT {
|
||||
return false
|
||||
}
|
||||
return ConfigBool(client.Config, "ssh_tunnel") || ConfigBool(client.Config, "ssh_overlay")
|
||||
}
|
||||
|
||||
func DNSTTSSHUnit(client Client) string {
|
||||
unit := strings.TrimSpace(ConfigString(client.Config, "ssh_unit"))
|
||||
if unit != "" {
|
||||
return unit
|
||||
}
|
||||
return "dnstt-ssh-tunnel.service"
|
||||
}
|
||||
|
||||
func RuntimeMode(cfg map[string]any) string {
|
||||
mode := strings.ToLower(strings.TrimSpace(ConfigString(cfg, "runtime_mode")))
|
||||
switch mode {
|
||||
case "", "exec", "external", "companion":
|
||||
return "exec"
|
||||
case "embedded":
|
||||
return "embedded"
|
||||
case "sidecar":
|
||||
return "sidecar"
|
||||
default:
|
||||
return mode
|
||||
}
|
||||
}
|
||||
|
||||
func SystemdActionUnits(client Client, action string) ([]string, string, string) {
|
||||
unit := BackendUnit(client)
|
||||
if unit == "" {
|
||||
return nil, "TRANSPORT_BACKEND_UNIT_REQUIRED", "systemd unit is required"
|
||||
}
|
||||
if !DNSTTSSHTunnelEnabled(client) {
|
||||
return []string{unit}, "", ""
|
||||
}
|
||||
sshUnit := DNSTTSSHUnit(client)
|
||||
if strings.TrimSpace(sshUnit) == "" {
|
||||
return nil, "TRANSPORT_BACKEND_UNIT_REQUIRED", "dnstt ssh tunnel unit is required"
|
||||
}
|
||||
switch action {
|
||||
case "stop":
|
||||
return []string{unit, sshUnit}, "", ""
|
||||
default:
|
||||
return []string{sshUnit, unit}, "", ""
|
||||
}
|
||||
}
|
||||
|
||||
func SystemdHealthUnits(client Client) ([]string, string, string) {
|
||||
unit := BackendUnit(client)
|
||||
if unit == "" {
|
||||
return nil, "TRANSPORT_BACKEND_UNIT_REQUIRED", "systemd unit is required"
|
||||
}
|
||||
units := []string{unit}
|
||||
if DNSTTSSHTunnelEnabled(client) {
|
||||
sshUnit := DNSTTSSHUnit(client)
|
||||
if strings.TrimSpace(sshUnit) == "" {
|
||||
return nil, "TRANSPORT_BACKEND_UNIT_REQUIRED", "dnstt ssh tunnel unit is required"
|
||||
}
|
||||
units = append(units, sshUnit)
|
||||
}
|
||||
return units, "", ""
|
||||
}
|
||||
|
||||
func ConfigString(cfg map[string]any, key string) string {
|
||||
if cfg == nil {
|
||||
return ""
|
||||
}
|
||||
raw, ok := cfg[key]
|
||||
if !ok || raw == nil {
|
||||
return ""
|
||||
}
|
||||
switch v := raw.(type) {
|
||||
case string:
|
||||
return strings.TrimSpace(v)
|
||||
default:
|
||||
return strings.TrimSpace(fmt.Sprint(v))
|
||||
}
|
||||
}
|
||||
|
||||
func ConfigBool(cfg map[string]any, key string) bool {
|
||||
if cfg == nil {
|
||||
return false
|
||||
}
|
||||
raw, ok := cfg[key]
|
||||
if !ok || raw == nil {
|
||||
return false
|
||||
}
|
||||
switch v := raw.(type) {
|
||||
case bool:
|
||||
return v
|
||||
case string:
|
||||
s := strings.ToLower(strings.TrimSpace(v))
|
||||
return s == "1" || s == "true" || s == "yes" || s == "on"
|
||||
case float64:
|
||||
return v != 0
|
||||
case int:
|
||||
return v != 0
|
||||
default:
|
||||
s := strings.ToLower(strings.TrimSpace(fmt.Sprint(v)))
|
||||
return s == "1" || s == "true" || s == "yes" || s == "on"
|
||||
}
|
||||
}
|
||||
|
||||
func ConfigHasKey(cfg map[string]any, key string) bool {
|
||||
if cfg == nil {
|
||||
return false
|
||||
}
|
||||
raw, ok := cfg[key]
|
||||
if !ok || raw == nil {
|
||||
return false
|
||||
}
|
||||
if s, ok := raw.(string); ok {
|
||||
return strings.TrimSpace(s) != ""
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user