19c0b190ea
ConnLogs were never populated because AppendConnLog was never called. Added StartStatusSync() goroutine that runs every 10 seconds: 1. Iterates all running instances 2. Reads status.log via ParseStatus (status-version 3) 3. For each CLIENT_LIST entry: - If no active ConnLog exists → AppendConnLog (new connection) - If active ConnLog exists → UpdateActiveConnStats (traffic) 4. For active ConnLogs with no matching CLIENT_LIST → CloseActiveConn Store additions: ListActiveConns(instanceID) — returns all unclosed connections UpdateActiveConnStats() — updates bytes in/out without flush StartStatusSync is called from main.go right after Service creation. UpdateActiveConnStats deliberately skips flush() to avoid writing db.json every 10 seconds; stats are persisted on disconnect.
90 lines
2.0 KiB
Go
90 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"openvpn-manager/internal/api"
|
|
"openvpn-manager/internal/config"
|
|
"openvpn-manager/internal/service"
|
|
"openvpn-manager/internal/store"
|
|
"openvpn-manager/pkg/openvpn"
|
|
)
|
|
|
|
func main() {
|
|
dataDir := flag.String("data", "", "data directory (default $OVPNMGR_DATA or ./data)")
|
|
distDir := flag.String("dist", "", "frontend dist directory (default $OVPNMGR_DIST or ./dist)")
|
|
flag.Parse()
|
|
|
|
if *dataDir == "" {
|
|
*dataDir = os.Getenv("OVPNMGR_DATA")
|
|
}
|
|
if *dataDir == "" {
|
|
*dataDir = "./data"
|
|
}
|
|
if *distDir == "" {
|
|
*distDir = os.Getenv("OVPNMGR_DIST")
|
|
}
|
|
if *distDir == "" {
|
|
*distDir = "./dist"
|
|
}
|
|
abs, _ := filepath.Abs(*dataDir)
|
|
cfg := config.Load(abs)
|
|
|
|
if err := os.MkdirAll(cfg.PKIDir(), 0o700); err != nil {
|
|
log.Fatalf("mkdir pki: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.InstancesDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir instances: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.ClientsDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir clients: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.BackupsDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir backups: %v", err)
|
|
}
|
|
|
|
st, err := store.Open(cfg.DBFile())
|
|
if err != nil {
|
|
log.Fatalf("open store: %v", err)
|
|
}
|
|
ovm := openvpn.NewManager(cfg.OpenVPNBin, cfg.DataDir)
|
|
ovm.SetPort(cfg.Port) // 让 verify.sh 知道回调哪个端口
|
|
if err := ovm.EnsureCA(); err != nil {
|
|
log.Printf("warn: ensure CA: %v", err)
|
|
}
|
|
svc := service.New(cfg, st, ovm)
|
|
svc.StartStatusSync() // 后台定时同步连接日志
|
|
|
|
addr := cfg.Host + ":" + itoa(cfg.Port)
|
|
log.Printf("openvpn-manager listening on %s, data=%s, dist=%s", addr, cfg.DataDir, *distDir)
|
|
srv := api.NewServer(cfg, svc)
|
|
if err := srv.Router(*distDir).Run(addr); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func itoa(n int) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
neg := false
|
|
if n < 0 {
|
|
neg = true
|
|
n = -n
|
|
}
|
|
var buf [20]byte
|
|
i := len(buf)
|
|
for n > 0 {
|
|
i--
|
|
buf[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
buf[i] = '-'
|
|
}
|
|
return string(buf[i:])
|
|
} |