Documentation
¶
Overview ¶
Package stats provides the engine-neutral per-user up/down byte counter and conn wrapper (Hinge B). It replaces xray-core's stats + SizeStatWriter with an atomic per-user counter built on sing's zero-copy-safe bufio.CounterConn, so that both ReadBuffer/WriteBuffer and Read/Write paths are accounted for.
Direction convention (doc/11 §7, doc/03 T2): Read = uplink (up), Write = downlink (down). The join key ("NodeTag|email|uid") is the map key.
Index ¶
- type Counter
- type Registry
- func (r *Registry) GetUserTraffic(key string, reset bool) (up, down int64)
- func (r *Registry) OnClose(conn net.Conn, fn func()) net.Conn
- func (r *Registry) TakeAndDelete(key string) (up, down int64)
- func (r *Registry) Wrap(key string, conn net.Conn) net.Conn
- func (r *Registry) WrapPacket(key string, conn N.PacketConn) N.PacketConn
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Counter ¶
type Counter struct {
// contains filtered or unexported fields
}
Counter holds a single user's cumulative up/down byte totals.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps a join key to its *Counter. The zero value is ready to use.
func (*Registry) GetUserTraffic ¶
GetUserTraffic returns the accumulated up/down bytes for key. When reset is true the counters are atomically read-and-cleared via Swap(0), giving the reset-then-report billing semantics: a period's bytes are consumed exactly once (losing a period beats double-billing). Returns 0,0 for an unknown key.
func (*Registry) OnClose ¶
OnClose wraps conn so that fn runs exactly once when the connection is closed, before the underlying Close. This is where connection-end accounting hangs — ConnLimiter decrement / flush (doc/11 §3.2 方式 B).
func (*Registry) TakeAndDelete ¶ added in v0.1.0
TakeAndDelete reads a key's bytes one last time and drops the entry.
Needed because reporting enumerates the node's CURRENT user set: the moment a user leaves it, nothing can reach their counter again, so whatever it holds is unbillable and the entry is unreclaimable (doc/14 C-07). Call it once the key is genuinely finished with.
A caveat worth knowing: a connection that is still open holds the *Counter POINTER it was wrapped with, so bytes it writes AFTER this call land on an object no longer in the map and are lost. That is why the caller keeps draining a departed user (GetUserTraffic with reset) while their sessions are still alive, and only calls this once they have gone quiet.
func (*Registry) Wrap ¶
Wrap returns conn wrapped so that every byte read (uplink) is added to the key's up counter and every byte written (downlink) to its down counter. It uses sing's bufio.CounterConn, which covers both the Read/Write and the zero-copy ReadBuffer/WriteBuffer paths — a hand-rolled Read/Write-only wrapper would undercount.
func (*Registry) WrapPacket ¶
func (r *Registry) WrapPacket(key string, conn N.PacketConn) N.PacketConn
WrapPacket is the N.PacketConn analogue of Wrap: ReadPacket bytes count as uplink (up), WritePacket bytes as downlink (down). Packet-count counters are unused (nil) — only byte totals feed billing.