platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
122
selective-vpn-api/app/trafficmode/normalize.go
Normal file
122
selective-vpn-api/app/trafficmode/normalize.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package trafficmode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TokenizeList(raw []string) []string {
|
||||
repl := strings.NewReplacer(",", " ", ";", " ", "\n", " ", "\t", " ")
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, line := range raw {
|
||||
for _, tok := range strings.Fields(repl.Replace(line)) {
|
||||
val := strings.TrimSpace(tok)
|
||||
if val != "" {
|
||||
out = append(out, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func NormalizeSubnetList(raw []string) []string {
|
||||
seen := map[string]struct{}{}
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, tok := range TokenizeList(raw) {
|
||||
var cidr string
|
||||
if strings.Contains(tok, "/") {
|
||||
pfx, err := netip.ParsePrefix(tok)
|
||||
if err != nil || !pfx.Addr().Is4() {
|
||||
continue
|
||||
}
|
||||
cidr = pfx.Masked().String()
|
||||
} else {
|
||||
ip, err := netip.ParseAddr(tok)
|
||||
if err != nil || !ip.Is4() {
|
||||
continue
|
||||
}
|
||||
cidr = netip.PrefixFrom(ip, 32).String()
|
||||
}
|
||||
if _, ok := seen[cidr]; ok {
|
||||
continue
|
||||
}
|
||||
seen[cidr] = struct{}{}
|
||||
out = append(out, cidr)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func NormalizeUIDToken(tok string) (string, bool) {
|
||||
t := strings.TrimSpace(tok)
|
||||
if t == "" {
|
||||
return "", false
|
||||
}
|
||||
parseOne := func(s string) (uint64, bool) {
|
||||
n, err := strconv.ParseUint(strings.TrimSpace(s), 10, 32)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
if strings.Contains(t, "-") {
|
||||
parts := strings.SplitN(t, "-", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", false
|
||||
}
|
||||
start, okA := parseOne(parts[0])
|
||||
end, okB := parseOne(parts[1])
|
||||
if !okA || !okB || end < start {
|
||||
return "", false
|
||||
}
|
||||
return fmt.Sprintf("%d-%d", start, end), true
|
||||
}
|
||||
n, ok := parseOne(t)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return fmt.Sprintf("%d-%d", n, n), true
|
||||
}
|
||||
|
||||
func NormalizeUIDList(raw []string) []string {
|
||||
seen := map[string]struct{}{}
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, tok := range TokenizeList(raw) {
|
||||
v, ok := NormalizeUIDToken(tok)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[v]; exists {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func NormalizeCgroupList(raw []string) []string {
|
||||
seen := map[string]struct{}{}
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, tok := range TokenizeList(raw) {
|
||||
v := strings.TrimSpace(tok)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
v = strings.TrimSuffix(v, "/")
|
||||
if v == "" {
|
||||
v = "/"
|
||||
}
|
||||
if _, exists := seen[v]; exists {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user