platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
165
selective-vpn-api/app/routes_update_helpers_lists.go
Normal file
165
selective-vpn-api/app/routes_update_helpers_lists.go
Normal file
@@ -0,0 +1,165 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user