mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 12:40:11 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06441afa79 | ||
|
|
f7b588fb45 | ||
|
|
9be082ede6 |
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type TrafficCounter struct {
|
||||
counters sync.Map
|
||||
Counters sync.Map
|
||||
}
|
||||
|
||||
type TrafficStorage struct {
|
||||
@@ -18,26 +18,26 @@ func NewTrafficCounter() *TrafficCounter {
|
||||
return &TrafficCounter{}
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) GetCounter(id string) *TrafficStorage {
|
||||
if cts, ok := c.counters.Load(id); ok {
|
||||
func (c *TrafficCounter) GetCounter(uuid string) *TrafficStorage {
|
||||
if cts, ok := c.Counters.Load(uuid); ok {
|
||||
return cts.(*TrafficStorage)
|
||||
}
|
||||
newStorage := &TrafficStorage{}
|
||||
if cts, loaded := c.counters.LoadOrStore(id, newStorage); loaded {
|
||||
if cts, loaded := c.Counters.LoadOrStore(uuid, newStorage); loaded {
|
||||
return cts.(*TrafficStorage)
|
||||
}
|
||||
return newStorage
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) GetUpCount(id string) int64 {
|
||||
if cts, ok := c.counters.Load(id); ok {
|
||||
func (c *TrafficCounter) GetUpCount(uuid string) int64 {
|
||||
if cts, ok := c.Counters.Load(uuid); ok {
|
||||
return cts.(*TrafficStorage).UpCounter.Load()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) GetDownCount(id string) int64 {
|
||||
if cts, ok := c.counters.Load(id); ok {
|
||||
func (c *TrafficCounter) GetDownCount(uuid string) int64 {
|
||||
if cts, ok := c.Counters.Load(uuid); ok {
|
||||
return cts.(*TrafficStorage).DownCounter.Load()
|
||||
}
|
||||
return 0
|
||||
@@ -45,30 +45,30 @@ func (c *TrafficCounter) GetDownCount(id string) int64 {
|
||||
|
||||
func (c *TrafficCounter) Len() int {
|
||||
length := 0
|
||||
c.counters.Range(func(_, _ interface{}) bool {
|
||||
c.Counters.Range(func(_, _ interface{}) bool {
|
||||
length++
|
||||
return true
|
||||
})
|
||||
return length
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) Reset(id string) {
|
||||
if cts, ok := c.counters.Load(id); ok {
|
||||
func (c *TrafficCounter) Reset(uuid string) {
|
||||
if cts, ok := c.Counters.Load(uuid); ok {
|
||||
cts.(*TrafficStorage).UpCounter.Store(0)
|
||||
cts.(*TrafficStorage).DownCounter.Store(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) Delete(id string) {
|
||||
c.counters.Delete(id)
|
||||
func (c *TrafficCounter) Delete(uuid string) {
|
||||
c.Counters.Delete(uuid)
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) Rx(id string, n int) {
|
||||
cts := c.GetCounter(id)
|
||||
func (c *TrafficCounter) Rx(uuid string, n int) {
|
||||
cts := c.GetCounter(uuid)
|
||||
cts.DownCounter.Add(int64(n))
|
||||
}
|
||||
|
||||
func (c *TrafficCounter) Tx(id string, n int) {
|
||||
cts := c.GetCounter(id)
|
||||
func (c *TrafficCounter) Tx(uuid string, n int) {
|
||||
cts := c.GetCounter(uuid)
|
||||
cts.UpCounter.Add(int64(n))
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ type Options struct {
|
||||
ListenIP string `json:"ListenIP"`
|
||||
SendIP string `json:"SendIP"`
|
||||
DeviceOnlineMinTraffic int64 `json:"DeviceOnlineMinTraffic"`
|
||||
ReportMinTraffic int64 `json:"ReportMinTraffic"`
|
||||
LimitConfig LimitConfig `json:"LimitConfig"`
|
||||
RawOptions json.RawMessage `json:"RawOptions"`
|
||||
XrayOptions *XrayOptions `json:"XrayOptions"`
|
||||
|
||||
@@ -17,6 +17,7 @@ type HookServer struct {
|
||||
Tag string
|
||||
logger *zap.Logger
|
||||
Counter sync.Map
|
||||
ReportMinTrafficBytes int64
|
||||
}
|
||||
|
||||
func (h *HookServer) TraceStream(stream quic.Stream, stats *server.StreamStats) {
|
||||
|
||||
@@ -42,6 +42,7 @@ func (h *Hysteria2) AddNode(tag string, info *panel.NodeInfo, config *conf.Optio
|
||||
TrafficLogger: &HookServer{
|
||||
Tag: tag,
|
||||
logger: h.Logger,
|
||||
ReportMinTrafficBytes: config.ReportMinTraffic * 1024,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ var _ server.Authenticator = &V2bX{}
|
||||
|
||||
type V2bX struct {
|
||||
usersMap map[string]int
|
||||
mutex sync.Mutex
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (v *V2bX) Authenticate(addr net.Addr, auth string, tx uint64) (ok bool, id string) {
|
||||
v.mutex.Lock()
|
||||
defer v.mutex.Unlock()
|
||||
v.mutex.RLock()
|
||||
defer v.mutex.RUnlock()
|
||||
if _, exists := v.usersMap[auth]; exists {
|
||||
return true, auth
|
||||
}
|
||||
@@ -56,15 +56,38 @@ func (h *Hysteria2) DelUsers(users []panel.UserInfo, tag string, _ *panel.NodeIn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hysteria2) GetUserTraffic(tag string, uuid string, reset bool) (up int64, down int64) {
|
||||
if v, ok := h.Hy2nodes[tag].TrafficLogger.(*HookServer).Counter.Load(tag); ok {
|
||||
func (h *Hysteria2) GetUserTrafficSlice(tag string, reset bool) ([]panel.UserTraffic, error) {
|
||||
trafficSlice := make([]panel.UserTraffic, 0)
|
||||
h.Auth.mutex.RLock()
|
||||
defer h.Auth.mutex.RUnlock()
|
||||
if _, ok := h.Hy2nodes[tag]; !ok {
|
||||
return nil, nil
|
||||
}
|
||||
hook := h.Hy2nodes[tag].TrafficLogger.(*HookServer)
|
||||
if v, ok := hook.Counter.Load(tag); ok {
|
||||
c := v.(*counter.TrafficCounter)
|
||||
up = c.GetUpCount(uuid)
|
||||
down = c.GetDownCount(uuid)
|
||||
c.Counters.Range(func(key, value interface{}) bool {
|
||||
uuid := key.(string)
|
||||
traffic := value.(*counter.TrafficStorage)
|
||||
up := traffic.UpCounter.Load()
|
||||
down := traffic.DownCounter.Load()
|
||||
if up+down > hook.ReportMinTrafficBytes {
|
||||
if reset {
|
||||
c.Reset(uuid)
|
||||
traffic.UpCounter.Store(0)
|
||||
traffic.DownCounter.Store(0)
|
||||
}
|
||||
return up, down
|
||||
trafficSlice = append(trafficSlice, panel.UserTraffic{
|
||||
UID: h.Auth.usersMap[uuid],
|
||||
Upload: up,
|
||||
Download: down,
|
||||
})
|
||||
}
|
||||
return 0, 0
|
||||
return true
|
||||
})
|
||||
if len(trafficSlice) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return trafficSlice, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ type Core interface {
|
||||
AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error
|
||||
DelNode(tag string) error
|
||||
AddUsers(p *AddUsersParams) (added int, err error)
|
||||
GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)
|
||||
GetUserTrafficSlice(tag string, reset bool) ([]panel.UserTraffic, error)
|
||||
DelUsers(users []panel.UserInfo, tag string, info *panel.NodeInfo) error
|
||||
Protocols() []string
|
||||
Type() string
|
||||
|
||||
@@ -128,12 +128,12 @@ func (s *Selector) AddUsers(p *AddUsersParams) (added int, err error) {
|
||||
return t.(Core).AddUsers(p)
|
||||
}
|
||||
|
||||
func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
|
||||
func (s *Selector) GetUserTrafficSlice(tag string, reset bool) ([]panel.UserTraffic, error) {
|
||||
t, e := s.nodes.Load(tag)
|
||||
if !e {
|
||||
return 0, 0
|
||||
return nil, errors.New("the node is not have")
|
||||
}
|
||||
return t.(Core).GetUserTraffic(tag, uuid, reset)
|
||||
return t.(Core).GetUserTrafficSlice(tag, reset)
|
||||
}
|
||||
|
||||
func (s *Selector) DelUsers(users []panel.UserInfo, tag string, info *panel.NodeInfo) error {
|
||||
|
||||
@@ -27,13 +27,6 @@ func (h *HookServer) ModeList() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHookServer() *HookServer {
|
||||
server := &HookServer{
|
||||
counter: sync.Map{},
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapter.InboundContext, _ adapter.Rule, _ adapter.Outbound) net.Conn {
|
||||
l, err := limiter.GetLimiter(m.Inbound)
|
||||
if err != nil {
|
||||
|
||||
@@ -394,6 +394,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
||||
}
|
||||
|
||||
func (b *Sing) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
|
||||
b.nodeReportMinTrafficBytes[tag] = config.ReportMinTraffic * 1024
|
||||
c, err := getInboundOptions(tag, info, config)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
@@ -29,6 +30,13 @@ type Sing struct {
|
||||
hookServer *HookServer
|
||||
router adapter.Router
|
||||
logFactory log.Factory
|
||||
users *UserMap
|
||||
nodeReportMinTrafficBytes map[string]int64
|
||||
}
|
||||
|
||||
type UserMap struct {
|
||||
uidMap map[string]int
|
||||
mapLock sync.RWMutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -71,7 +79,9 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hs := NewHookServer()
|
||||
hs := &HookServer{
|
||||
counter: sync.Map{},
|
||||
}
|
||||
b.Router().AppendTracker(hs)
|
||||
return &Sing{
|
||||
ctx: b.Router().GetCtx(),
|
||||
@@ -79,6 +89,10 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
|
||||
hookServer: hs,
|
||||
router: b.Router(),
|
||||
logFactory: b.LogFactory(),
|
||||
users: &UserMap{
|
||||
uidMap: make(map[string]int),
|
||||
},
|
||||
nodeReportMinTrafficBytes: make(map[string]int64),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ func (b *Sing) AddUsers(p *core.AddUsersParams) (added int, err error) {
|
||||
if !found {
|
||||
return 0, errors.New("the inbound not found")
|
||||
}
|
||||
b.users.mapLock.Lock()
|
||||
defer b.users.mapLock.Unlock()
|
||||
for i := range p.Users {
|
||||
b.users.uidMap[p.Users[i].Uuid] = p.Users[i].Id
|
||||
}
|
||||
switch p.NodeInfo.Type {
|
||||
case "vless":
|
||||
us := make([]option.VLESSUser, len(p.Users))
|
||||
@@ -129,6 +134,39 @@ func (b *Sing) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int6
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func (b *Sing) GetUserTrafficSlice(tag string, reset bool) ([]panel.UserTraffic, error) {
|
||||
trafficSlice := make([]panel.UserTraffic, 0)
|
||||
hook := b.hookServer
|
||||
b.users.mapLock.RLock()
|
||||
defer b.users.mapLock.RUnlock()
|
||||
if v, ok := hook.counter.Load(tag); ok {
|
||||
c := v.(*counter.TrafficCounter)
|
||||
c.Counters.Range(func(key, value interface{}) bool {
|
||||
uuid := key.(string)
|
||||
traffic := value.(*counter.TrafficStorage)
|
||||
up := traffic.UpCounter.Load()
|
||||
down := traffic.DownCounter.Load()
|
||||
if up+down > b.nodeReportMinTrafficBytes[tag] {
|
||||
if reset {
|
||||
traffic.UpCounter.Store(0)
|
||||
traffic.DownCounter.Store(0)
|
||||
}
|
||||
trafficSlice = append(trafficSlice, panel.UserTraffic{
|
||||
UID: b.users.uidMap[uuid],
|
||||
Upload: up,
|
||||
Download: down,
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
if len(trafficSlice) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return trafficSlice, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type UserDeleter interface {
|
||||
DelUsers(uuid []string) error
|
||||
}
|
||||
@@ -158,7 +196,10 @@ func (b *Sing) DelUsers(users []panel.UserInfo, tag string, info *panel.NodeInfo
|
||||
return errors.New("the inbound not found")
|
||||
}
|
||||
uuids := make([]string, len(users))
|
||||
b.users.mapLock.Lock()
|
||||
defer b.users.mapLock.Unlock()
|
||||
for i := range users {
|
||||
delete(b.users.uidMap, users[i].Uuid)
|
||||
uuids[i] = users[i].Uuid
|
||||
}
|
||||
err := del.DelUsers(uuids)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
"github.com/InazumaV/V2bX/common/rate"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
|
||||
@@ -104,6 +105,7 @@ type DefaultDispatcher struct {
|
||||
stats stats.Manager
|
||||
fdns dns.FakeDNSEngine
|
||||
Wm *WriterManager
|
||||
Counter sync.Map
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -204,26 +206,24 @@ func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network) (*
|
||||
inboundLink.Writer = rate.NewRateLimitWriter(inboundLink.Writer, w)
|
||||
outboundLink.Writer = rate.NewRateLimitWriter(outboundLink.Writer, w)
|
||||
}
|
||||
p := d.policy.ForLevel(user.Level)
|
||||
if p.Stats.UserUplink {
|
||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||
inboundLink.Writer = &SizeStatWriter{
|
||||
Counter: c,
|
||||
var t *counter.TrafficCounter
|
||||
if c, ok := d.Counter.Load(sessionInbound.Tag); !ok {
|
||||
t = counter.NewTrafficCounter()
|
||||
d.Counter.Store(sessionInbound.Tag, t)
|
||||
} else {
|
||||
t = c.(*counter.TrafficCounter)
|
||||
}
|
||||
|
||||
inboundLink.Writer = &UploadTrafficWriter{
|
||||
Counter: t.GetCounter(user.Email),
|
||||
Writer: inboundLink.Writer,
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.Stats.UserDownlink {
|
||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
||||
outboundLink.Writer = &SizeStatWriter{
|
||||
Counter: c,
|
||||
|
||||
outboundLink.Writer = &DownloadTrafficWriter{
|
||||
Counter: t.GetCounter(user.Email),
|
||||
Writer: outboundLink.Writer,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inboundLink, outboundLink, limit, nil
|
||||
}
|
||||
|
||||
@@ -1,25 +1,43 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
)
|
||||
|
||||
type SizeStatWriter struct {
|
||||
Counter stats.Counter
|
||||
type UploadTrafficWriter struct {
|
||||
Counter *counter.TrafficStorage
|
||||
Writer buf.Writer
|
||||
}
|
||||
|
||||
func (w *SizeStatWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
w.Counter.Add(int64(mb.Len()))
|
||||
type DownloadTrafficWriter struct {
|
||||
Counter *counter.TrafficStorage
|
||||
Writer buf.Writer
|
||||
}
|
||||
|
||||
func (w *UploadTrafficWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
w.Counter.UpCounter.Add(int64(mb.Len()))
|
||||
return w.Writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
|
||||
func (w *SizeStatWriter) Close() error {
|
||||
func (w *UploadTrafficWriter) Close() error {
|
||||
return common.Close(w.Writer)
|
||||
}
|
||||
|
||||
func (w *SizeStatWriter) Interrupt() {
|
||||
func (w *UploadTrafficWriter) Interrupt() {
|
||||
common.Interrupt(w.Writer)
|
||||
}
|
||||
|
||||
func (w *DownloadTrafficWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
w.Counter.DownCounter.Add(int64(mb.Len()))
|
||||
return w.Writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
|
||||
func (w *DownloadTrafficWriter) Close() error {
|
||||
return common.Close(w.Writer)
|
||||
}
|
||||
|
||||
func (w *DownloadTrafficWriter) Interrupt() {
|
||||
common.Interrupt(w.Writer)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type DNSConfig struct {
|
||||
}
|
||||
|
||||
func (c *Xray) AddNode(tag string, info *panel.NodeInfo, config *conf.Options) error {
|
||||
c.nodeReportMinTrafficBytes[tag] = config.ReportMinTraffic * 1024
|
||||
err := updateDNSConfig(info)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build dns error: %s", err)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
"github.com/InazumaV/V2bX/common/format"
|
||||
vCore "github.com/InazumaV/V2bX/core"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
@@ -32,47 +33,61 @@ func (c *Xray) DelUsers(users []panel.UserInfo, tag string, _ *panel.NodeInfo) e
|
||||
if err != nil {
|
||||
return fmt.Errorf("get user manager error: %s", err)
|
||||
}
|
||||
var up, down, user string
|
||||
var user string
|
||||
c.users.mapLock.Lock()
|
||||
defer c.users.mapLock.Unlock()
|
||||
for i := range users {
|
||||
user = format.UserTag(tag, users[i].Uuid)
|
||||
err = userManager.RemoveUser(context.Background(), user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
up = "user>>>" + user + ">>>traffic>>>uplink"
|
||||
down = "user>>>" + user + ">>>traffic>>>downlink"
|
||||
c.shm.UnregisterCounter(up)
|
||||
c.shm.UnregisterCounter(down)
|
||||
delete(c.users.uidMap, user)
|
||||
c.dispatcher.Counter.Delete(user)
|
||||
c.dispatcher.Wm.RemoveWritersForUser(user)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Xray) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
|
||||
upName := "user>>>" + format.UserTag(tag, uuid) + ">>>traffic>>>uplink"
|
||||
downName := "user>>>" + format.UserTag(tag, uuid) + ">>>traffic>>>downlink"
|
||||
upCounter := c.shm.GetCounter(upName)
|
||||
downCounter := c.shm.GetCounter(downName)
|
||||
func (x *Xray) GetUserTrafficSlice(tag string, reset bool) ([]panel.UserTraffic, error) {
|
||||
trafficSlice := make([]panel.UserTraffic, 0)
|
||||
x.users.mapLock.RLock()
|
||||
defer x.users.mapLock.RUnlock()
|
||||
if v, ok := x.dispatcher.Counter.Load(tag); ok {
|
||||
c := v.(*counter.TrafficCounter)
|
||||
c.Counters.Range(func(key, value interface{}) bool {
|
||||
email := key.(string)
|
||||
traffic := value.(*counter.TrafficStorage)
|
||||
up := traffic.UpCounter.Load()
|
||||
down := traffic.DownCounter.Load()
|
||||
if up+down > x.nodeReportMinTrafficBytes[tag] {
|
||||
if reset {
|
||||
if upCounter != nil {
|
||||
up = upCounter.Set(0)
|
||||
traffic.UpCounter.Store(0)
|
||||
traffic.DownCounter.Store(0)
|
||||
}
|
||||
if downCounter != nil {
|
||||
down = downCounter.Set(0)
|
||||
trafficSlice = append(trafficSlice, panel.UserTraffic{
|
||||
UID: x.users.uidMap[email],
|
||||
Upload: up,
|
||||
Download: down,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if upCounter != nil {
|
||||
up = upCounter.Value()
|
||||
return true
|
||||
})
|
||||
if len(trafficSlice) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if downCounter != nil {
|
||||
down = downCounter.Value()
|
||||
return trafficSlice, nil
|
||||
}
|
||||
}
|
||||
return up, down
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *Xray) AddUsers(p *vCore.AddUsersParams) (added int, err error) {
|
||||
users := make([]*protocol.User, 0, len(p.Users))
|
||||
c.users.mapLock.Lock()
|
||||
defer c.users.mapLock.Unlock()
|
||||
for i := range p.Users {
|
||||
c.users.uidMap[format.UserTag(p.Tag, p.Users[i].Uuid)] = p.Users[i].Id
|
||||
}
|
||||
var users []*protocol.User
|
||||
switch p.NodeInfo.Type {
|
||||
case "vmess":
|
||||
users = buildVmessUsers(p.Tag, p.Users)
|
||||
|
||||
@@ -36,10 +36,23 @@ type Xray struct {
|
||||
ohm outbound.Manager
|
||||
shm statsFeature.Manager
|
||||
dispatcher *dispatcher.DefaultDispatcher
|
||||
users *UserMap
|
||||
nodeReportMinTrafficBytes map[string]int64
|
||||
}
|
||||
|
||||
type UserMap struct {
|
||||
uidMap map[string]int
|
||||
mapLock sync.RWMutex
|
||||
}
|
||||
|
||||
func New(c *conf.CoreConfig) (vCore.Core, error) {
|
||||
return &Xray{Server: getCore(c.XrayConfig)}, nil
|
||||
return &Xray{
|
||||
Server: getCore(c.XrayConfig),
|
||||
users: &UserMap{
|
||||
uidMap: make(map[string]int),
|
||||
},
|
||||
nodeReportMinTrafficBytes: make(map[string]int64),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseConnectionConfig(c *conf.XrayConnectionConfig) (policy *coreConf.Policy) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"ListenIP": "0.0.0.0",
|
||||
"SendIP": "0.0.0.0",
|
||||
"DeviceOnlineMinTraffic": 200,
|
||||
"MinReportTraffic": 0,
|
||||
"TCPFastOpen": false,
|
||||
"SniffEnabled": true,
|
||||
"CertConfig": {
|
||||
|
||||
12
go.mod
12
go.mod
@@ -15,13 +15,13 @@ require (
|
||||
github.com/goccy/go-json v0.10.4
|
||||
github.com/hashicorp/go-multierror v1.1.2-0.20241119060415-613124da9385
|
||||
github.com/juju/ratelimit v1.0.2
|
||||
github.com/sagernet/sing v0.7.0-beta.1.0.20250722151551-64142925accb
|
||||
github.com/sagernet/sing v0.7.0-beta.2
|
||||
github.com/sagernet/sing-box v1.12.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/xtls/xray-core v1.250608.1-0.20250724020803-26de58933f04
|
||||
github.com/xtls/xray-core v1.250803.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/sys v0.34.0
|
||||
@@ -236,8 +236,8 @@ require (
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 // indirect
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250721014417-ebbe32588cfb // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.4 // indirect
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1 // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.6 // indirect
|
||||
github.com/sagernet/smux v1.5.34-mod.2 // indirect
|
||||
github.com/sagernet/tailscale v1.80.3-mod.5 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7 // indirect
|
||||
@@ -285,7 +285,7 @@ require (
|
||||
github.com/vultr/govultr/v3 v3.9.1 // indirect
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250723121437-95d5ab59ff92 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b // indirect
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 // indirect
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c // indirect
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20241220131134-2393e243c134 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
@@ -329,4 +329,4 @@ require (
|
||||
|
||||
//replace github.com/sagernet/sing-box v1.12.0 => ../sing-box_mod
|
||||
|
||||
replace github.com/sagernet/sing-box v1.12.0 => github.com/wyx2685/sing-box_mod v1.12.0-rc.2.2
|
||||
replace github.com/sagernet/sing-box v1.12.0 => github.com/wyx2685/sing-box_mod v1.12.0
|
||||
|
||||
26
go.sum
26
go.sum
@@ -96,8 +96,6 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||
@@ -924,8 +922,8 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.0-beta.1.0.20250722151551-64142925accb h1:9DU5JA9Cow/bUfdP1v1pYMbAkFiW17UbI4b/iEPjVnc=
|
||||
github.com/sagernet/sing v0.7.0-beta.1.0.20250722151551-64142925accb/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.0-beta.2 h1:UImAKtHGQX205lGYYXKA2qnEeVSml+hKS1oaOwvA14c=
|
||||
github.com/sagernet/sing v0.7.0-beta.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
||||
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.3 h1:X/acRNsqQNfDlmwE7SorHfaZiny5e67hqIzM/592ric=
|
||||
@@ -936,10 +934,10 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250721014417-ebbe32588cfb h1:cvHEzjk3sVy80UA9PFKX15MzSP0g1uKwUspOm2ds3no=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250721014417-ebbe32588cfb/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ=
|
||||
github.com/sagernet/sing-vmess v0.2.4 h1:wSg/SdxThELAvoRIN2yCZgu5xsmP1FWPBrP2ab2wq3A=
|
||||
github.com/sagernet/sing-vmess v0.2.4/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ=
|
||||
github.com/sagernet/sing-vmess v0.2.6 h1:1c4dGzeGy0kpBXXrT1sgiMZtHhdJylIT8eWrGhJYZec=
|
||||
github.com/sagernet/sing-vmess v0.2.6/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=
|
||||
@@ -1093,8 +1091,8 @@ github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4i
|
||||
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
|
||||
github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
|
||||
github.com/vultr/govultr/v3 v3.9.1/go.mod h1:Rd8ebpXm7jxH3MDmhnEs+zrlYW212ouhx+HeUMfHm2o=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-rc.2.2 h1:sh3nfHQ5+mD6JIJiG1vA+UHzHBufxj+N2LUPnZr9yjY=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-rc.2.2/go.mod h1:glHdsBt8/Qu1EtZfIuHqhm5dJwnNDG2v5we3o78kV/0=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0 h1:coAUA1NO3kd8SUIPEOlWUTN2zoXpGA8rDdWeTtx417Y=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0/go.mod h1:sRM3yvlp5byib0v0WVNeT/XpF1HUnPirMH1qZ9Sffc0=
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250723121437-95d5ab59ff92 h1:A5/G1mY1M3h+j6D3BgfRlngbsfTUGwE8S3UuyR9VfbU=
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250723121437-95d5ab59ff92/go.mod h1:ZvICtYzgNgbRy2fgKTVmG4o+6pP92dzY5GhwSlfya8Q=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
@@ -1108,10 +1106,10 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b h1:HOOsQYu7/EzvpegY7uHiaeI9H/6OsHAOkREnJthdUW8=
|
||||
github.com/xtls/reality v0.0.0-20250723121014-c6320729d93b/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/xtls/xray-core v1.250608.1-0.20250724020803-26de58933f04 h1:Q+NGF57sLx/eChdxNUNjZk+e9NToLjQVQrikwq1m9tU=
|
||||
github.com/xtls/xray-core v1.250608.1-0.20250724020803-26de58933f04/go.mod h1:dqSs+9mmzvOZRFxTaS0ktkQYG8TD9naApQPdnp/MUzA=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7 h1:Ript0vN+nSO33+Vj4n0mgNY5M+oOxFQJdrJ1VnwTBO0=
|
||||
github.com/xtls/reality v0.0.0-20250725142056-5b52a03d4fb7/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
|
||||
github.com/xtls/xray-core v1.250803.0 h1:sYdRC243UsujnePINH4IfM4MfHE4lj2p4wZFAfeE2GI=
|
||||
github.com/xtls/xray-core v1.250803.0/go.mod h1:z2vn2o30flYEgpSz1iEhdZP1I46UZ3+gXINZyohH3yE=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c h1:Rnr+lDYXVkP+3eT8/d68iq4G/UeIhyCQk+HKa8toTvg=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20241220131134-2393e243c134 h1:qmpz0Kvr9GAng8LAhRcKIpY71CEAcL3EBkftVlsP5Cw=
|
||||
|
||||
15
node/user.go
15
node/user.go
@@ -8,20 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func (c *Controller) reportUserTrafficTask() (err error) {
|
||||
// Get User traffic
|
||||
userTraffic := make([]panel.UserTraffic, 0)
|
||||
for i := range c.userList {
|
||||
up, down := c.server.GetUserTraffic(c.tag, c.userList[i].Uuid, true)
|
||||
if up > 0 || down > 0 {
|
||||
if c.LimitConfig.EnableDynamicSpeedLimit {
|
||||
c.traffic[c.userList[i].Uuid] += up + down
|
||||
}
|
||||
userTraffic = append(userTraffic, panel.UserTraffic{
|
||||
UID: (c.userList)[i].Id,
|
||||
Upload: up,
|
||||
Download: down})
|
||||
}
|
||||
}
|
||||
userTraffic, err := c.server.GetUserTrafficSlice(c.tag, true)
|
||||
if len(userTraffic) > 0 {
|
||||
err = c.apiClient.ReportUserTraffic(userTraffic)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user