Files
lmvpn_client/internal/stats/stats.go
T
2026-07-06 16:21:06 +08:00

86 lines
2.2 KiB
Go

// Package stats provides atomic counters for VPN session statistics.
package stats
import (
"sync/atomic"
"time"
)
// State represents the current VPN session state.
type State string
const (
StateDisconnected State = "disconnected"
StateConnecting State = "connecting"
StateConnected State = "connected"
StateReconnecting State = "reconnecting"
StateError State = "error"
)
// Stats holds live session statistics. Counters are atomic for
// lock-free reads from the UI/IPC layer.
type Stats struct {
RxBytes atomic.Int64
TxBytes atomic.Int64
ConnectedAt atomic.Int64 // unix timestamp, 0 = not connected
state atomic.Value // State
assignedIP atomic.Value // string
}
// New creates a Stats instance initialised to the disconnected state.
func New() *Stats {
s := &Stats{}
s.state.Store(StateDisconnected)
s.assignedIP.Store("")
return s
}
// SetState updates the current state atomically.
func (s *Stats) SetState(st State) { s.state.Store(st) }
// State returns the current state.
func (s *Stats) State() State { return s.state.Load().(State) }
// SetConnected marks the session as connected, recording the time and IP.
func (s *Stats) SetConnected(ip string) {
s.ConnectedAt.Store(time.Now().Unix())
s.assignedIP.Store(ip)
s.state.Store(StateConnected)
}
// SetDisconnected clears the connection metadata.
func (s *Stats) SetDisconnected() {
s.ConnectedAt.Store(0)
s.assignedIP.Store("")
s.state.Store(StateDisconnected)
}
// AssignedIP returns the server-assigned tunnel IP.
func (s *Stats) AssignedIP() string { return s.assignedIP.Load().(string) }
// Snapshot returns a point-in-time copy of all counters.
type Snapshot struct {
RxBytes int64
TxBytes int64
ConnectedAt time.Time
AssignedIP string
State State
Uptime time.Duration
}
// Snapshot returns a point-in-time copy of the statistics.
func (s *Stats) Snapshot() Snapshot {
snap := Snapshot{
RxBytes: s.RxBytes.Load(),
TxBytes: s.TxBytes.Load(),
AssignedIP: s.AssignedIP(),
State: s.State(),
}
ts := s.ConnectedAt.Load()
if ts > 0 {
snap.ConnectedAt = time.Unix(ts, 0)
snap.Uptime = time.Since(snap.ConnectedAt)
}
return snap
}