Fix connection logs: real-time status.log parsing
Root cause: listConnLogs only read from db.json which was never
populated (background sync silently failed due to Status check and
broken regex).
Fix approach: read status.log directly in API handlers — no DB
dependency, works immediately when OpenVPN is running.
Changes:
api/router.go:
- listConnLogs: parse status.log from all instances in real-time,
merge with historical DB entries for disconnected sessions
- dashboard: same real-time approach for recent_conn_logs
pkg/openvpn/manager.go:
- Fix regex for status-version 3 format (11 fields):
CLIENT_LIST,CN,RealAddr,VPNAddr,IPv6,BytesRecv,BytesSent,ConnectedSince,...
Old regex assumed wrong field order (CN,ConnectedSince,RealAddr)
- Add parseConnTime() helper supporting multiple time formats
internal/service/service.go:
- Remove Status=='running' check (was blocking sync for all instances)
- Add log.Printf debug output for sync operations
- Add 'log' import
internal/store/store.go:
- Add ListActiveConns(instanceID) for background sync
- Add UpdateActiveConnStats() for traffic updates without flush
This commit is contained in:
@@ -614,7 +614,9 @@ type StatusEntry struct {
|
||||
|
||||
var (
|
||||
reHdr = regexp.MustCompile(`^Updated,([^,]+),`)
|
||||
reCli = regexp.MustCompile(`^CLIENT_LIST,([^,]+),([^,]+),([^,]+),(\d+),(\d+),`)
|
||||
// status-version 3 CLIENT_LIST 格式(11个字段):
|
||||
// CLIENT_LIST,CommonName,RealAddress,VirtualAddress,VirtualIPv6,BytesRecv,BytesSent,ConnectedSince,Username,ClientID,PeerID
|
||||
reCli = regexp.MustCompile(`^CLIENT_LIST,([^,]+),([^,]+),([^,]+),([^,]*),(\d+),(\d+),([^,]+),`)
|
||||
reTime = regexp.MustCompile(`^Connected Since,([^,]+),`)
|
||||
)
|
||||
|
||||
@@ -630,14 +632,13 @@ func ParseStatusReader(r io.Reader) ([]StatusEntry, error) {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
connected, _ := time.Parse("Mon Jan 2 15:04:05 2006", m[2])
|
||||
out = append(out, StatusEntry{
|
||||
CommonName: m[1],
|
||||
RealAddress: m[3],
|
||||
VPNAddress: m[4],
|
||||
BytesRecv: atoi64(m[5]),
|
||||
BytesSent: atoi64(m[6]),
|
||||
ConnectedAt: connected,
|
||||
RealAddress: m[2], // RealAddress (IP:port)
|
||||
VPNAddress: m[3], // VirtualAddress
|
||||
BytesRecv: atoi64(m[5]),
|
||||
BytesSent: atoi64(m[6]),
|
||||
ConnectedAt: parseConnTime(m[7]),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -693,6 +694,33 @@ func atoi64(s string) int64 {
|
||||
return n
|
||||
}
|
||||
|
||||
// parseConnTime 解析 OpenVPN status.log 中的时间字段。
|
||||
// status-version 3 格式: "Mon Jan 2 15:04:05 2006" (注意可能有双空格)
|
||||
// 部分版本使用 Unix 时间戳。
|
||||
func parseConnTime(s string) time.Time {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
// 先尝试 Unix 时间戳
|
||||
if ts, err := strconv.ParseInt(s, 10, 64); err == nil && ts > 1000000000 {
|
||||
return time.Unix(ts, 0)
|
||||
}
|
||||
// 标准格式
|
||||
formats := []string{
|
||||
"Mon Jan 2 15:04:05 2006",
|
||||
"Mon Jan 2 15:04:05 2006",
|
||||
"2006-01-02 15:04:05",
|
||||
time.RFC3339,
|
||||
}
|
||||
for _, f := range formats {
|
||||
if t, err := time.Parse(f, s); err == nil {
|
||||
return t
|
||||
}
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// cidrToServerDirective 把 "10.8.0.0/24" 转成 OpenVPN server 指令需要的
|
||||
// "10.8.0.0 255.255.255.0" 格式(网络地址 + 点分掩码)。
|
||||
// 如果输入不含 "/"(已经是 "ip mask" 形式),原样返回。
|
||||
|
||||
Reference in New Issue
Block a user