platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
73
selective-vpn-api/app/routes_cache_helpers_nft.go
Normal file
73
selective-vpn-api/app/routes_cache_helpers_nft.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func snapshotNftSetToFile(setName, dst string) (int, error) {
|
||||
elems, err := readNftSetElements(setName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := writeLinesFile(dst, elems); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(elems), nil
|
||||
}
|
||||
|
||||
func readNftSetElements(setName string) ([]string, error) {
|
||||
out, stderr, code, err := runCommandTimeout(
|
||||
8*time.Second, "nft", "list", "set", "inet", "agvpn", setName,
|
||||
)
|
||||
if err != nil || code != 0 {
|
||||
msg := strings.ToLower(strings.TrimSpace(out + " " + stderr))
|
||||
if strings.Contains(msg, "no such file") ||
|
||||
strings.Contains(msg, "not found") ||
|
||||
strings.Contains(msg, "does not exist") {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("nft list set %s failed: %w", setName, err)
|
||||
}
|
||||
return nil, fmt.Errorf("nft list set %s failed: %s", setName, strings.TrimSpace(stderr))
|
||||
}
|
||||
return parseNftSetElementsText(out), nil
|
||||
}
|
||||
|
||||
func parseNftSetElementsText(raw string) []string {
|
||||
idx := strings.Index(raw, "elements =")
|
||||
if idx < 0 {
|
||||
return nil
|
||||
}
|
||||
chunk := raw[idx:]
|
||||
open := strings.Index(chunk, "{")
|
||||
if open < 0 {
|
||||
return nil
|
||||
}
|
||||
body := chunk[open+1:]
|
||||
closeIdx := strings.Index(body, "}")
|
||||
if closeIdx >= 0 {
|
||||
body = body[:closeIdx]
|
||||
}
|
||||
body = strings.ReplaceAll(body, "\r", " ")
|
||||
body = strings.ReplaceAll(body, "\n", " ")
|
||||
|
||||
seen := map[string]struct{}{}
|
||||
out := make([]string, 0, 1024)
|
||||
for _, tok := range strings.Split(body, ",") {
|
||||
val := strings.TrimSpace(tok)
|
||||
if val == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[val]; ok {
|
||||
continue
|
||||
}
|
||||
seen[val] = struct{}{}
|
||||
out = append(out, val)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user