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

166 lines
4.5 KiB
Go

package app
import (
"os"
"sort"
"strings"
)
// ---------------------------------------------------------------------
// EN: `loadList` loads list from storage or config.
// RU: `loadList` - загружает list из хранилища или конфига.
// ---------------------------------------------------------------------
func loadList(path string) []string {
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var out []string
for _, ln := range strings.Split(string(data), "\n") {
ln = strings.TrimSpace(strings.SplitN(ln, "#", 2)[0])
if ln == "" {
continue
}
out = append(out, ln)
}
return out
}
// ---------------------------------------------------------------------
// EN: `loadSmartDNSWildcardDomains` loads SmartDNS wildcard domains from canonical API state.
// RU: `loadSmartDNSWildcardDomains` - загружает wildcard-домены SmartDNS из каноничного API-состояния.
// ---------------------------------------------------------------------
func loadSmartDNSWildcardDomains(logf func(string, ...any)) []string {
out, source := loadSmartDNSWildcardDomainsState(logf)
sort.Strings(out)
if logf != nil {
logf("smartdns wildcards loaded: source=%s count=%d", source, len(out))
}
return out
}
// ---------------------------------------------------------------------
// EN: `isGoogleLike` checks whether google like is true.
// RU: `isGoogleLike` - проверяет, является ли google like истинным условием.
// ---------------------------------------------------------------------
func isGoogleLike(d string) bool {
low := strings.ToLower(d)
for _, base := range googleLikeDomains {
if low == base || strings.HasSuffix(low, "."+base) {
return true
}
}
return false
}
// ---------------------------------------------------------------------
// EN: `readNonEmptyLines` reads non empty lines from input data.
// RU: `readNonEmptyLines` - читает non empty lines из входных данных.
// ---------------------------------------------------------------------
func readNonEmptyLines(path string) []string {
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var out []string
for _, ln := range strings.Split(string(data), "\n") {
ln = strings.TrimSpace(ln)
if ln != "" {
out = append(out, ln)
}
}
return out
}
func writeLines(path string, lines []string) error {
if len(lines) == 0 {
return os.WriteFile(path, []byte{}, 0o644)
}
return os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o644)
}
func writeMapPairs(path string, pairs [][2]string) error {
if len(pairs) == 0 {
return os.WriteFile(path, []byte{}, 0o644)
}
lines := make([]string, 0, len(pairs))
for _, p := range pairs {
lines = append(lines, p[0]+"\t"+p[1])
}
return os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o644)
}
func countDomainsFromPairs(pairs [][2]string) int {
seen := make(map[string]struct{})
for _, p := range pairs {
if len(p) < 2 {
continue
}
d := strings.TrimSpace(p[1])
if d == "" || strings.HasPrefix(d, "[") {
continue
}
seen[d] = struct{}{}
}
return len(seen)
}
func wildcardHostIPMap(pairs [][2]string) map[string][]string {
hostToIPs := make(map[string]map[string]struct{})
for _, p := range pairs {
if len(p) < 2 {
continue
}
ip := strings.TrimSpace(p[0])
host := strings.TrimSpace(p[1])
if ip == "" || host == "" || strings.HasPrefix(host, "[") {
continue
}
ips := hostToIPs[host]
if ips == nil {
ips = map[string]struct{}{}
hostToIPs[host] = ips
}
ips[ip] = struct{}{}
}
out := make(map[string][]string, len(hostToIPs))
for host, ipset := range hostToIPs {
ips := make([]string, 0, len(ipset))
for ip := range ipset {
ips = append(ips, ip)
}
sort.Strings(ips)
out[host] = ips
}
return out
}
// ---------------------------------------------------------------------
// EN: `countDomainsFromMap` counts items for domains from map.
// RU: `countDomainsFromMap` - считает элементы для domains from map.
// ---------------------------------------------------------------------
func countDomainsFromMap(path string) int {
data, err := os.ReadFile(path)
if err != nil {
return 0
}
seen := make(map[string]struct{})
for _, ln := range strings.Split(string(data), "\n") {
ln = strings.TrimSpace(ln)
if ln == "" {
continue
}
fields := strings.Fields(ln)
if len(fields) < 2 {
continue
}
d := fields[1]
if strings.HasPrefix(d, "[") {
continue
}
seen[d] = struct{}{}
}
return len(seen)
}