stats

package
v0.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: GPL-3.0 Imports: 5 Imported by: 0

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

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

func (r *Registry) GetUserTraffic(key string, reset bool) (up, down int64)

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

func (r *Registry) OnClose(conn net.Conn, fn func()) net.Conn

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

func (r *Registry) TakeAndDelete(key string) (up, down int64)

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

func (r *Registry) Wrap(key string, conn net.Conn) net.Conn

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL