Files
elmprodvpn/selective-vpn-api/app/routes_cache_helpers_nft.go

74 lines
1.6 KiB
Go

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
}