mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
API: Fix Online Map (#5732)
https://github.com/XTLS/Xray-core/pull/5732#pullrequestreview-3863990264
This commit is contained in:
@@ -183,12 +183,9 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
if p.Stats.UserOnline {
|
if p.Stats.UserOnline {
|
||||||
name := "user>>>" + user.Email + ">>>online"
|
name := "user>>>" + user.Email + ">>>online"
|
||||||
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
||||||
sessionInbounds := session.InboundFromContext(ctx)
|
userIP := sessionInbound.Source.Address.String()
|
||||||
userIP := sessionInbounds.Source.Address.String()
|
|
||||||
om.AddIP(userIP)
|
om.AddIP(userIP)
|
||||||
// log Online user with ips
|
context.AfterFunc(ctx, func() { om.RemoveIP(userIP) })
|
||||||
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,11 +222,9 @@ func WrapLink(ctx context.Context, policyManager policy.Manager, statsManager st
|
|||||||
if p.Stats.UserOnline {
|
if p.Stats.UserOnline {
|
||||||
name := "user>>>" + user.Email + ">>>online"
|
name := "user>>>" + user.Email + ">>>online"
|
||||||
if om, _ := stats.GetOrRegisterOnlineMap(statsManager, name); om != nil {
|
if om, _ := stats.GetOrRegisterOnlineMap(statsManager, name); om != nil {
|
||||||
sessionInbounds := session.InboundFromContext(ctx)
|
userIP := sessionInbound.Source.Address.String()
|
||||||
userIP := sessionInbounds.Source.Address.String()
|
|
||||||
om.AddIP(userIP)
|
om.AddIP(userIP)
|
||||||
// log Online user with ips
|
context.AfterFunc(ctx, func() { om.RemoveIP(userIP) })
|
||||||
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func (s *statsServer) GetStatsOnlineIpList(ctx context.Context, request *GetStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
ips := make(map[string]int64)
|
ips := make(map[string]int64)
|
||||||
for ip, t := range c.IpTimeMap() {
|
for ip, t := range c.IPTimeMap() {
|
||||||
ips[ip] = t.Unix()
|
ips[ip] = t.Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,84 +2,98 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnlineMap is an implementation of stats.OnlineMap.
|
const (
|
||||||
type OnlineMap struct {
|
localhostIPv4 = "127.0.0.1"
|
||||||
ipList map[string]time.Time
|
localhostIPv6 = "[::1]"
|
||||||
access sync.RWMutex
|
)
|
||||||
lastCleanup time.Time
|
|
||||||
cleanupPeriod time.Duration
|
type ipEntry struct {
|
||||||
|
refCount int
|
||||||
|
lastSeen time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOnlineMap creates a new instance of OnlineMap.
|
// OnlineMap is a refcount-based implementation of stats.OnlineMap.
|
||||||
|
// IPs are tracked by reference counting: AddIP increments, RemoveIP decrements.
|
||||||
|
// An IP is removed from the map when its reference count reaches zero.
|
||||||
|
type OnlineMap struct {
|
||||||
|
entries map[string]*ipEntry
|
||||||
|
access sync.Mutex
|
||||||
|
count atomic.Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOnlineMap creates a new OnlineMap instance.
|
||||||
func NewOnlineMap() *OnlineMap {
|
func NewOnlineMap() *OnlineMap {
|
||||||
return &OnlineMap{
|
return &OnlineMap{
|
||||||
ipList: make(map[string]time.Time),
|
entries: make(map[string]*ipEntry),
|
||||||
lastCleanup: time.Now(),
|
}
|
||||||
cleanupPeriod: 10 * time.Second,
|
}
|
||||||
|
|
||||||
|
// AddIP implements stats.OnlineMap.
|
||||||
|
func (om *OnlineMap) AddIP(ip string) {
|
||||||
|
if ip == localhostIPv4 || ip == localhostIPv6 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
om.access.Lock()
|
||||||
|
defer om.access.Unlock()
|
||||||
|
|
||||||
|
if e, ok := om.entries[ip]; ok {
|
||||||
|
e.refCount++
|
||||||
|
e.lastSeen = time.Now()
|
||||||
|
} else {
|
||||||
|
om.entries[ip] = &ipEntry{
|
||||||
|
refCount: 1,
|
||||||
|
lastSeen: time.Now(),
|
||||||
|
}
|
||||||
|
om.count.Add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveIP implements stats.OnlineMap.
|
||||||
|
func (om *OnlineMap) RemoveIP(ip string) {
|
||||||
|
om.access.Lock()
|
||||||
|
defer om.access.Unlock()
|
||||||
|
|
||||||
|
e, ok := om.entries[ip]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.refCount--
|
||||||
|
if e.refCount <= 0 {
|
||||||
|
delete(om.entries, ip)
|
||||||
|
om.count.Add(-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count implements stats.OnlineMap.
|
// Count implements stats.OnlineMap.
|
||||||
func (c *OnlineMap) Count() int {
|
func (om *OnlineMap) Count() int {
|
||||||
c.access.RLock()
|
return int(om.count.Load())
|
||||||
defer c.access.RUnlock()
|
|
||||||
|
|
||||||
return len(c.ipList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List implements stats.OnlineMap.
|
// List implements stats.OnlineMap.
|
||||||
func (c *OnlineMap) List() []string {
|
func (om *OnlineMap) List() []string {
|
||||||
return c.GetKeys()
|
om.access.Lock()
|
||||||
}
|
defer om.access.Unlock()
|
||||||
|
|
||||||
// AddIP implements stats.OnlineMap.
|
keys := make([]string, 0, len(om.entries))
|
||||||
func (c *OnlineMap) AddIP(ip string) {
|
for ip := range om.entries {
|
||||||
if ip == "127.0.0.1" {
|
keys = append(keys, ip)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.access.Lock()
|
|
||||||
c.ipList[ip] = time.Now()
|
|
||||||
c.access.Unlock()
|
|
||||||
|
|
||||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
|
||||||
c.RemoveExpiredIPs()
|
|
||||||
c.lastCleanup = time.Now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *OnlineMap) GetKeys() []string {
|
|
||||||
c.access.RLock()
|
|
||||||
defer c.access.RUnlock()
|
|
||||||
|
|
||||||
keys := []string{}
|
|
||||||
for k := range c.ipList {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
}
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OnlineMap) RemoveExpiredIPs() {
|
// IPTimeMap implements stats.OnlineMap.
|
||||||
c.access.Lock()
|
func (om *OnlineMap) IPTimeMap() map[string]time.Time {
|
||||||
defer c.access.Unlock()
|
om.access.Lock()
|
||||||
|
defer om.access.Unlock()
|
||||||
|
|
||||||
now := time.Now()
|
result := make(map[string]time.Time, len(om.entries))
|
||||||
for k, t := range c.ipList {
|
for ip, e := range om.entries {
|
||||||
diff := now.Sub(t)
|
result[ip] = e.lastSeen
|
||||||
if diff.Seconds() > 20 {
|
|
||||||
delete(c.ipList, k)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return result
|
||||||
|
|
||||||
func (c *OnlineMap) IpTimeMap() map[string]time.Time {
|
|
||||||
if time.Since(c.lastCleanup) > c.cleanupPeriod {
|
|
||||||
c.RemoveExpiredIPs()
|
|
||||||
c.lastCleanup = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.ipList
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,12 +163,12 @@ func (m *Manager) GetChannel(name string) stats.Channel {
|
|||||||
|
|
||||||
// GetAllOnlineUsers implements stats.Manager.
|
// GetAllOnlineUsers implements stats.Manager.
|
||||||
func (m *Manager) GetAllOnlineUsers() []string {
|
func (m *Manager) GetAllOnlineUsers() []string {
|
||||||
m.access.Lock()
|
m.access.RLock()
|
||||||
defer m.access.Unlock()
|
defer m.access.RUnlock()
|
||||||
|
|
||||||
usersOnline := make([]string, 0, len(m.onlineMap))
|
usersOnline := make([]string, 0, len(m.onlineMap))
|
||||||
for user, onlineMap := range m.onlineMap {
|
for user, onlineMap := range m.onlineMap {
|
||||||
if len(onlineMap.IpTimeMap()) > 0 {
|
if onlineMap.Count() > 0 {
|
||||||
usersOnline = append(usersOnline, user)
|
usersOnline = append(usersOnline, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,14 +25,16 @@ type Counter interface {
|
|||||||
//
|
//
|
||||||
// xray:api:stable
|
// xray:api:stable
|
||||||
type OnlineMap interface {
|
type OnlineMap interface {
|
||||||
// Count is the current value of the OnlineMap.
|
// Count returns the number of unique online IPs.
|
||||||
Count() int
|
Count() int
|
||||||
// AddIP adds a ip to the current OnlineMap.
|
// AddIP increments the reference count for the given IP.
|
||||||
AddIP(string)
|
AddIP(string)
|
||||||
// List is the current OnlineMap ip list.
|
// RemoveIP decrements the reference count for the given IP. Deletes at zero.
|
||||||
|
RemoveIP(string)
|
||||||
|
// List returns all currently online IPs.
|
||||||
List() []string
|
List() []string
|
||||||
// IpTimeMap return client ips and their last access time.
|
// IPTimeMap returns a snapshot copy of IPs to their last-seen times.
|
||||||
IpTimeMap() map[string]time.Time
|
IPTimeMap() map[string]time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel is the interface for stats channel.
|
// Channel is the interface for stats channel.
|
||||||
|
|||||||
Reference in New Issue
Block a user