Compare commits

...

9 Commits

Author SHA1 Message Date
wyx2685
7d52a8932d test: update go 1.25.0 2025-08-13 21:37:42 +09:00
wyx2685
06441afa79 fix: 流量判断阈值去除=号 2025-08-07 15:46:12 +09:00
wyx2685
f7b588fb45 test: 增加MinReportTraffic最低流量上报阈值 2025-08-07 14:18:12 +09:00
wyx2685
9be082ede6 update xray 25.8.3 & sing-box 1.12.0 2025-08-05 00:28:47 +09:00
wyx2685
dce3ec1079 fix: update xray-core 25.7.24 2025-07-24 11:52:31 +09:00
wyx2685
2990999f7b 发布临时修复版本 2025-07-24 02:10:57 +09:00
wyx2685
fe003fcb19 回滚等待xray修复 2025-07-24 01:04:15 +09:00
wyx2685
ea26985d7c fix: hy2和tuic处理错误 2025-07-24 00:07:44 +09:00
wyx2685
32437f5e48 fix: 缺少mldsa65参数导致无法启动 2025-07-24 00:07:19 +09:00
29 changed files with 321 additions and 203 deletions

View File

@@ -109,7 +109,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24.5'
go-version: '1.25.0'
- name: Get project dependencies
run: |
@@ -126,13 +126,13 @@ jobs:
run: |
echo "version: $version"
mkdir -p build_assets
go build -v -o build_assets/V2bX -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
GOEXPERIMENT=jsonv2 go build -v -o build_assets/V2bX -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
- name: Build Mips softfloat V2bX
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: |
echo "version: $version"
GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
GOEXPERIMENT=jsonv2 GOMIPS=softfloat go build -v -o build_assets/V2bX_softfloat -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor" -trimpath -ldflags "-X 'github.com/InazumaV/V2bX/cmd.version=$version' -s -w -buildid="
- name: Rename Windows V2bX
if: matrix.goos == 'windows'
run: |

View File

@@ -1,10 +1,10 @@
# Build go
FROM golang:1.24.5-alpine AS builder
FROM golang:1.25.0-alpine AS builder
WORKDIR /app
COPY . .
ENV CGO_ENABLED=0
RUN go mod download
RUN go build -v -o V2bX -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor"
RUN GOEXPERIMENT=jsonv2 go mod download
RUN GOEXPERIMENT=jsonv2 go build -v -o V2bX -tags "sing xray hysteria2 with_quic with_grpc with_utls with_wireguard with_acme with_gvisor"
# Release
FROM alpine

View File

@@ -9,7 +9,7 @@ import (
"strings"
"time"
"github.com/goccy/go-json"
"encoding/json"
)
// Security type
@@ -80,6 +80,7 @@ type TlsSettings struct {
ServerPort string `json:"server_port"`
ShortId string `json:"short_id"`
PrivateKey string `json:"private_key"`
Mldsa65Seed string `json:"mldsa65Seed"`
Xver uint64 `json:"xver,string"`
}

View File

@@ -2,10 +2,11 @@ package panel
import (
"fmt"
"io"
"strings"
"github.com/goccy/go-json"
"encoding/json/jsontext"
"encoding/json/v2"
"github.com/vmihailenco/msgpack/v5"
)
@@ -56,12 +57,33 @@ func (c *Client) GetUserList() ([]UserInfo, error) {
return nil, fmt.Errorf("decode user list error: %w", err)
}
} else {
bodyBytes, err := io.ReadAll(r.RawResponse.Body)
dec := jsontext.NewDecoder(r.RawResponse.Body)
for {
tok, err := dec.ReadToken()
if err != nil {
return nil, fmt.Errorf("read response body error: %w", err)
return nil, fmt.Errorf("decode user list error: %w", err)
}
if err := json.Unmarshal(bodyBytes, userlist); err != nil {
return nil, fmt.Errorf("unmarshal user list error: %w", err)
if tok.Kind() == '"' && tok.String() == "users" {
break
}
}
tok, err := dec.ReadToken()
if err != nil {
return nil, fmt.Errorf("decode user list error: %w", err)
}
if tok.Kind() != '[' {
return nil, fmt.Errorf(`decode user list error: expected "users" array`)
}
for dec.PeekKind() != ']' {
val, err := dec.ReadValue()
if err != nil {
return nil, fmt.Errorf("decode user list error: read user object: %w", err)
}
var u UserInfo
if err := json.Unmarshal(val, &u); err != nil {
return nil, fmt.Errorf("decode user list error: unmarshal user error: %w", err)
}
userlist.Users = append(userlist.Users, u)
}
}
c.userEtag = r.Header().Get("ETag")

View File

@@ -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))
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/InazumaV/V2bX/common/json5"
"github.com/goccy/go-json"
"encoding/json/v2"
)
type Conf struct {

View File

@@ -7,8 +7,9 @@ import (
"os"
"strings"
"encoding/json"
"github.com/InazumaV/V2bX/common/json5"
"github.com/goccy/go-json"
)
type NodeConfig struct {
@@ -109,6 +110,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"`

View File

@@ -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) {

View File

@@ -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,
},
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -10,9 +10,10 @@ import (
"strings"
"time"
"encoding/json"
"github.com/InazumaV/V2bX/api/panel"
"github.com/InazumaV/V2bX/conf"
"github.com/goccy/go-json"
"github.com/sagernet/sing-box/option"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
@@ -394,6 +395,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

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -7,8 +7,9 @@ import (
"strconv"
"strings"
"encoding/json"
"github.com/InazumaV/V2bX/api/panel"
"github.com/goccy/go-json"
log "github.com/sirupsen/logrus"
coreConf "github.com/xtls/xray-core/infra/conf"
)

View File

@@ -8,9 +8,10 @@ import (
"fmt"
"time"
"encoding/json"
"github.com/InazumaV/V2bX/api/panel"
"github.com/InazumaV/V2bX/conf"
"github.com/goccy/go-json"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core"
coreConf "github.com/xtls/xray-core/infra/conf"
@@ -133,12 +134,14 @@ func buildInbound(option *conf.Options, nodeInfo *panel.NodeInfo, tag string) (*
in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{
Dest: d,
Xver: xver,
Show: false,
ServerNames: []string{v.TlsSettings.ServerName},
PrivateKey: v.TlsSettings.PrivateKey,
MinClientVer: v.RealityConfig.MinClientVer,
MaxClientVer: v.RealityConfig.MaxClientVer,
MaxTimeDiff: uint64(mtd.Microseconds()),
ShortIds: []string{v.TlsSettings.ShortId},
Mldsa65Seed: v.TlsSettings.Mldsa65Seed,
}
default:
break

View File

@@ -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)

View File

@@ -3,8 +3,9 @@ package xray
import (
"fmt"
"encoding/json"
conf2 "github.com/InazumaV/V2bX/conf"
"github.com/goccy/go-json"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
)

View File

@@ -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)

View File

@@ -5,11 +5,12 @@ import (
"os"
"sync"
"encoding/json/v2"
"github.com/InazumaV/V2bX/conf"
vCore "github.com/InazumaV/V2bX/core"
"github.com/InazumaV/V2bX/core/xray/app/dispatcher"
_ "github.com/InazumaV/V2bX/core/xray/distro/all"
"github.com/goccy/go-json"
log "github.com/sirupsen/logrus"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/stats"
@@ -36,10 +37,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) {

View File

@@ -29,6 +29,7 @@
"ListenIP": "0.0.0.0",
"SendIP": "0.0.0.0",
"DeviceOnlineMinTraffic": 200,
"MinReportTraffic": 0,
"TCPFastOpen": false,
"SniffEnabled": true,
"CertConfig": {

18
go.mod
View File

@@ -1,8 +1,8 @@
module github.com/InazumaV/V2bX
go 1.24
go 1.25
toolchain go1.24.5
toolchain go1.25.0
require (
github.com/apernet/hysteria/core/v2 v2.6.2
@@ -12,16 +12,15 @@ require (
github.com/fsnotify/fsnotify v1.8.0
github.com/go-acme/lego/v4 v4.21.1-0.20241220151055-ee7a9e4fa04f
github.com/go-resty/resty/v2 v2.16.2
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.20250723105259-dbd912568602
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
@@ -119,6 +118,7 @@ require (
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/goccy/go-json v0.10.4 // indirect
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gofrs/uuid/v5 v5.3.2 // indirect
@@ -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-20250723115123-fadd8146daab // 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
replace github.com/sagernet/sing-box v1.12.0 => github.com/wyx2685/sing-box_mod v1.12.0

52
go.sum
View File

@@ -23,8 +23,6 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
@@ -98,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=
@@ -341,8 +337,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -928,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=
@@ -940,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=
@@ -1097,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 h1:hpJF4KOm9TKibKwYvdYeAFPF5ziIUXAybnI3AkaehzQ=
github.com/wyx2685/sing-box_mod v1.12.0-rc.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=
@@ -1112,12 +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-20250723115123-fadd8146daab h1:5XUQ93jvYKvsjKjaTYZYA1Ass/lu957fWhcBtSOvwmE=
github.com/xtls/reality v0.0.0-20250723115123-fadd8146daab/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0=
github.com/xtls/xray-core v1.250608.1-0.20250721045543-eed05549fc99 h1:6m0/4VtaaFUtyvaXbbmf58K926dQ9q1uW88m2/A3ZIk=
github.com/xtls/xray-core v1.250608.1-0.20250721045543-eed05549fc99/go.mod h1:htCOAodkfaxNGZ7w2M+eLleQet8dpj57h4aXcaRxf0o=
github.com/xtls/xray-core v1.250608.1-0.20250723105259-dbd912568602 h1:BLpqdPT4mLlecwyJfkixGNWlcMH00UsnPp0LcNm0m2s=
github.com/xtls/xray-core v1.250608.1-0.20250723105259-dbd912568602/go.mod h1:B0PIQPbYMQ4ESJ+K3ifR4zIMl5GS5vWYE2EVZnZj4ts=
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=
@@ -1152,22 +1144,14 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
@@ -1333,8 +1317,6 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1601,12 +1583,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM=
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1626,8 +1604,6 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=

View File

@@ -13,11 +13,12 @@ import (
"strings"
"time"
"encoding/json"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge/http01"
"github.com/go-acme/lego/v4/providers/dns"
"github.com/go-acme/lego/v4/registration"
"github.com/goccy/go-json"
"github.com/InazumaV/V2bX/common/file"
"github.com/InazumaV/V2bX/conf"

View File

@@ -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 {