platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
121
selective-vpn-api/app/routes_cache_restore.go
Normal file
121
selective-vpn-api/app/routes_cache_restore.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func restoreRoutesFromCache() cmdResult {
|
||||
return withRoutesOpLock("routes restore", restoreRoutesFromCacheUnlocked)
|
||||
}
|
||||
|
||||
func restoreRoutesFromCacheUnlocked() cmdResult {
|
||||
meta, err := loadRoutesClearCacheMeta()
|
||||
if err != nil {
|
||||
return cmdResult{
|
||||
OK: false,
|
||||
Message: fmt.Sprintf("routes cache missing: %v", err),
|
||||
}
|
||||
}
|
||||
|
||||
ips := readNonEmptyLines(routesCacheIPs)
|
||||
dynIPs := readNonEmptyLines(routesCacheDyn)
|
||||
routeLines, _ := readLinesFile(routesCacheRT)
|
||||
|
||||
ensureRoutesTableEntry()
|
||||
removeTrafficRulesForTable()
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "ip", "route", "flush", "table", routesTableName())
|
||||
|
||||
ignoredRoutes := 0
|
||||
for _, ln := range routeLines {
|
||||
if err := restoreRouteLine(ln); err != nil {
|
||||
if shouldIgnoreRestoreRouteError(ln, err) {
|
||||
ignoredRoutes++
|
||||
appendTraceLine("routes", fmt.Sprintf("restore route skipped (%q): %v", ln, err))
|
||||
continue
|
||||
}
|
||||
return cmdResult{
|
||||
OK: false,
|
||||
Message: fmt.Sprintf("restore route failed (%q): %v", ln, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
if ignoredRoutes > 0 {
|
||||
appendTraceLine("routes", fmt.Sprintf("restore route: skipped non-critical routes=%d", ignoredRoutes))
|
||||
}
|
||||
|
||||
if len(routeLines) == 0 && strings.TrimSpace(meta.Iface) != "" {
|
||||
_, _, _, _ = runCommandTimeout(
|
||||
5*time.Second,
|
||||
"ip", "-4", "route", "replace",
|
||||
"default", "dev", meta.Iface,
|
||||
"table", routesTableName(),
|
||||
"mtu", policyRouteMTU,
|
||||
)
|
||||
}
|
||||
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "nft", "add", "table", "inet", "agvpn")
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "nft", "add", "set", "inet", "agvpn", "agvpn4", "{", "type", "ipv4_addr", ";", "flags", "interval", ";", "}")
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "nft", "add", "set", "inet", "agvpn", "agvpn_dyn4", "{", "type", "ipv4_addr", ";", "flags", "interval", ";", "}")
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "nft", "flush", "set", "inet", "agvpn", "agvpn4")
|
||||
_, _, _, _ = runCommandTimeout(5*time.Second, "nft", "flush", "set", "inet", "agvpn", "agvpn_dyn4")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
if len(ips) > 0 {
|
||||
if err := nftUpdateSetIPsSmart(ctx, "agvpn4", ips, nil); err != nil {
|
||||
return cmdResult{
|
||||
OK: false,
|
||||
Message: fmt.Sprintf("restore nft cache failed for agvpn4: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(dynIPs) > 0 {
|
||||
if err := nftUpdateSetIPsSmart(ctx, "agvpn_dyn4", dynIPs, nil); err != nil {
|
||||
return cmdResult{
|
||||
OK: false,
|
||||
Message: fmt.Sprintf("restore nft cache failed for agvpn_dyn4: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traffic := loadTrafficModeState()
|
||||
iface := strings.TrimSpace(meta.Iface)
|
||||
if iface == "" {
|
||||
iface = detectIfaceFromRoutes(routeLines)
|
||||
}
|
||||
if iface == "" {
|
||||
iface, _ = resolveTrafficIface(traffic.PreferredIface)
|
||||
}
|
||||
if iface != "" {
|
||||
if err := applyTrafficMode(traffic, iface); err != nil {
|
||||
return cmdResult{
|
||||
OK: false,
|
||||
Message: fmt.Sprintf("cache restored, but traffic mode apply failed: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ = cacheCopyOrEmpty(routesCacheIPs, stateDir+"/last-ips.txt")
|
||||
if fileExists(routesCacheMap) {
|
||||
_ = cacheCopyOrEmpty(routesCacheMap, stateDir+"/last-ips-map.txt")
|
||||
}
|
||||
if fileExists(routesCacheMapD) {
|
||||
_ = cacheCopyOrEmpty(routesCacheMapD, lastIPsMapDirect)
|
||||
}
|
||||
if fileExists(routesCacheMapW) {
|
||||
_ = cacheCopyOrEmpty(routesCacheMapW, lastIPsMapDyn)
|
||||
}
|
||||
_ = writeStatusSnapshot(len(ips)+len(dynIPs), iface)
|
||||
|
||||
return cmdResult{
|
||||
OK: true,
|
||||
Message: fmt.Sprintf(
|
||||
"routes restored from cache: agvpn4=%d agvpn_dyn4=%d routes=%d iface=%s",
|
||||
len(ips), len(dynIPs), len(routeLines), ifaceOrDash(iface),
|
||||
),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user