baseline: api+gui traffic mode + candidates picker
Snapshot before app-launcher (cgroup/mark) work; ignore binaries/backups.
This commit is contained in:
72
selective-vpn-api/app/shell.go
Normal file
72
selective-vpn-api/app/shell.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// низкоуровневые helpers
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// EN: Low-level command execution adapters with timeout handling and small
|
||||
// EN: policy-route verification helper used by higher-level handlers.
|
||||
// RU: Низкоуровневые адаптеры запуска команд с таймаутами и вспомогательной
|
||||
// RU: проверкой policy-route, используемой верхнеуровневыми обработчиками.
|
||||
|
||||
func runCommand(name string, args ...string) (string, string, int, error) {
|
||||
return runCommandTimeout(60*time.Second, name, args...)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// policy route check
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
func checkPolicyRoute(iface, table string) (bool, error) {
|
||||
stdout, _, exitCode, err := runCommand("ip", "route", "show", "table", table)
|
||||
if exitCode != 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("ip route show exited with %d", exitCode)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
want := fmt.Sprintf("default dev %s", iface)
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, want) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// command timeout helper
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
func runCommandTimeout(timeout time.Duration, name string, args ...string) (string, string, int, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, name, args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
stdout := string(out)
|
||||
stderr := stdout
|
||||
|
||||
exitCode := 0
|
||||
if err != nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
exitCode = ee.ExitCode()
|
||||
} else if errors.Is(err, context.DeadlineExceeded) {
|
||||
exitCode = -1
|
||||
err = fmt.Errorf("command timeout: %w", err)
|
||||
} else {
|
||||
exitCode = -1
|
||||
}
|
||||
}
|
||||
return stdout, stderr, exitCode, err
|
||||
}
|
||||
Reference in New Issue
Block a user