platform: modularize api/gui, add docs-tests-web foundation, and refresh root config

This commit is contained in:
beckline
2026-03-26 22:40:54 +03:00
parent 0e2d7f61ea
commit 6a56d734c2
562 changed files with 70151 additions and 16423 deletions

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"log"
"os"
"regexp"
"strings"
"time"
)
@@ -44,28 +43,7 @@ func runAutoloop(iface, table string, mtu int, stateDirPath, defaultLoc string)
}
writeLoginState := func(state, email, msg string) {
ts := time.Now().Format(time.RFC3339)
payload := fmt.Sprintf(`{"ts":"%s","state":"%s","email":"%s","msg":"%s"}`, ts, escapeJSON(state), escapeJSON(email), escapeJSON(msg))
_ = os.WriteFile(loginStateFile, []byte(payload), 0o644)
}
getLocation := func() string {
if data, err := os.ReadFile(locFile); err == nil {
for _, ln := range strings.Split(string(data), "\n") {
t := strings.TrimSpace(ln)
if t != "" && !strings.HasPrefix(t, "#") {
return t
}
}
}
return defaultLoc
}
isConnected := func(out string) bool {
low := strings.ToLower(out)
return strings.Contains(low, "vpn is connected") ||
strings.Contains(low, "connected to") ||
strings.Contains(low, "after connect: connected")
writeAutoloopLoginState(loginStateFile, state, email, msg)
}
fixPolicy := func() {
@@ -83,45 +61,9 @@ func runAutoloop(iface, table string, mtu int, stateDirPath, defaultLoc string)
" mtu " + fmt.Sprintf("%d", mtu) + " OK")
}
}
var emailRe = regexp.MustCompile(`[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+`)
parseEmail := func(text string) string {
return emailRe.FindString(text)
}
isLoginRequired := func(t string) bool {
low := strings.ToLower(t)
return strings.Contains(low, "please log in") ||
strings.Contains(low, "not logged in") ||
strings.Contains(low, "login required") ||
strings.Contains(low, "sign in")
}
updateLoginStateFromText := func(text string) {
if isLoginRequired(text) {
writeLoginState("no_login", "", "NOT LOGGED IN")
logLine("login: NO (detected from output)")
return
}
if em := parseEmail(text); em != "" {
writeLoginState("ok", em, "logged in")
logLine("login: OK email=" + em)
return
}
low := strings.ToLower(text)
if strings.Contains(low, "not logged in") ||
strings.Contains(low, "expired") ||
strings.Contains(low, "no active license") {
writeLoginState("no_login", "", "NOT LOGGED IN (license)")
logLine("login: NO (license says not logged in)")
return
}
if strings.Contains(low, "license") &&
(strings.Contains(low, "active") || strings.Contains(low, "valid")) {
writeLoginState("ok", "", "logged in (license ok)")
logLine("login: OK (license ok, email not found)")
return
}
updateAutoloopLoginStateFromText(text, writeLoginState, logLine)
}
updateLicense := func() {
@@ -144,7 +86,7 @@ func runAutoloop(iface, table string, mtu int, stateDirPath, defaultLoc string)
if err != nil {
logLine(fmt.Sprintf("status: ERROR exit=%d err=%v raw=%q", exitCode, err, statusOut))
}
if isConnected(statusOut) {
if isAutoloopConnected(statusOut) {
logLine("status: CONNECTED; raw: " + statusOut)
fixPolicy()
updateLicense()
@@ -163,18 +105,30 @@ func runAutoloop(iface, table string, mtu int, stateDirPath, defaultLoc string)
})
updateLoginStateFromText(statusOut)
loc := getLocation()
logLine("reconnecting to " + loc)
loc := resolveAutoloopLocationSpec(locFile, defaultLoc)
primary := strings.TrimSpace(loc.Primary)
if primary == "" {
primary = strings.TrimSpace(defaultLoc)
}
logLine("reconnecting to " + primary)
_, _, _, _ = runCommandTimeout(disconnectTimeout, adgvpnCLI, "disconnect")
connectOut, _, _, _ := runCommandTimeout(connectTimeout, adgvpnCLI, "connect", "-l", loc, "--log-to-file")
connectOut, _, _, _ := runCommandTimeout(connectTimeout, adgvpnCLI, "connect", "-l", primary, "--log-to-file")
connectOut = stripANSI(connectOut)
logLine("connect raw: " + connectOut)
updateLoginStateFromText(connectOut)
if !isAutoloopConnected(connectOut) && loc.ISO != "" && !strings.EqualFold(loc.ISO, primary) {
logLine("connect fallback to ISO: " + loc.ISO)
fallbackOut, _, _, _ := runCommandTimeout(connectTimeout, adgvpnCLI, "connect", "-l", loc.ISO, "--log-to-file")
fallbackOut = stripANSI(fallbackOut)
logLine("connect fallback raw: " + fallbackOut)
updateLoginStateFromText(fallbackOut)
}
statusAfter, _, _, _ := runCommandTimeout(statusTimeout, adgvpnCLI, "status")
statusAfter = stripANSI(statusAfter)
if isConnected(statusAfter) {
if isAutoloopConnected(statusAfter) {
logLine("after connect: CONNECTED; raw: " + statusAfter)
fixPolicy()
updateLicense()
@@ -190,15 +144,3 @@ func runAutoloop(iface, table string, mtu int, stateDirPath, defaultLoc string)
time.Sleep(10 * time.Second)
}
}
// ---------------------------------------------------------------------
// autoloop helpers
// ---------------------------------------------------------------------
func escapeJSON(s string) string {
s = strings.ReplaceAll(s, `\`, `\\`)
s = strings.ReplaceAll(s, `"`, `\\"`)
s = strings.ReplaceAll(s, "\n", "\\n")
s = strings.ReplaceAll(s, "\r", "")
return s
}