Files
NexusGate/panel-go/presence.go

95 lines
2.2 KiB
Go

package main
// Presence & speed derivation — mirrors lib/presence.js. See that file
// for the signal model (per-server user counters, per-node inbound
// counters, AnyTLS observations; 3-minute window; server-level activity
// attributed to the customer's nodes on that server).
import "time"
const PresenceWindowMs = 180000
const SpeedStaleMs = 150000
func parseISOMsOr0(value *string) int64 {
if value == nil {
return 0
}
ms, ok := ParseISOMs(*value)
if !ok {
return 0
}
return ms
}
func CustomerOnline(customer *Customer, nowMs int64) bool {
ms := parseISOMsOr0(customer.LastOnlineAt)
return ms > 0 && nowMs-ms <= PresenceWindowMs
}
func CustomerSpeedBps(customer *Customer, nowMs int64) (float64, float64) {
var up, down float64
for _, slot := range customer.ServerUsage {
if slot == nil || slot.SpeedAt == nil {
continue
}
if nowMs-parseISOMsOr0(slot.SpeedAt) > SpeedStaleMs {
continue
}
if slot.SpeedUpBps != nil {
up += *slot.SpeedUpBps
}
if slot.SpeedDownBps != nil {
down += *slot.SpeedDownBps
}
}
return up, down
}
func NodeSpeedBps(node *Node, nowMs int64) (float64, float64) {
if node.SpeedAt == nil || nowMs-parseISOMsOr0(node.SpeedAt) > SpeedStaleMs {
return 0, 0
}
var up, down float64
if node.SpeedUpBps != nil {
up = *node.SpeedUpBps
}
if node.SpeedDownBps != nil {
down = *node.SpeedDownBps
}
return up, down
}
// NodeOnlineCustomerIds mirrors nodeOnlineCustomerIds in lib/presence.js.
func NodeOnlineCustomerIds(d *Data, node *Node, nowMs int64) []string {
out := []string{}
for _, nc := range d.NodeClients {
if nc.NodeID != node.ID || nc.Status != "active" {
continue
}
customer := findCustomer(d, nc.CustomerID)
if customer == nil {
continue
}
var ms int64
if slot := customer.ServerUsage["srv:"+node.ServerID]; slot != nil && slot.LastActiveAt != nil {
ms = parseISOMsOr0(slot.LastActiveAt)
} else {
ms = parseISOMsOr0(customer.LastOnlineAt)
}
if ms > 0 && nowMs-ms <= PresenceWindowMs {
out = append(out, customer.ID)
}
}
return out
}
func CountOnlineCustomers(d *Data, now time.Time) int {
count := 0
for _, customer := range d.Customers {
if CustomerOnline(customer, now.UnixMilli()) {
count++
}
}
return count
}