Compare commits

...

2 Commits

Author SHA1 Message Date
wyx2685
8d225f811b fix: 用户限速信息不能同步更新BUG 2025-07-13 09:23:06 +09:00
wyx2685
f6b587b275 prefer msgpack for userlist 2025-07-04 11:37:23 +09:00
4 changed files with 34 additions and 12 deletions

View File

@@ -2,8 +2,11 @@ package panel
import ( import (
"fmt" "fmt"
"io"
"strings"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/vmihailenco/msgpack"
) )
type OnlineUser struct { type OnlineUser struct {
@@ -12,15 +15,14 @@ type OnlineUser struct {
} }
type UserInfo struct { type UserInfo struct {
Id int `json:"id"` Id int `json:"id" msgpack:"id"`
Uuid string `json:"uuid"` Uuid string `json:"uuid" msgpack:"uuid"`
SpeedLimit int `json:"speed_limit"` SpeedLimit int `json:"speed_limit" msgpack:"speed_limit"`
DeviceLimit int `json:"device_limit"` DeviceLimit int `json:"device_limit" msgpack:"device_limit"`
} }
type UserListBody struct { type UserListBody struct {
//Msg string `json:"msg"` Users []UserInfo `json:"users" msgpack:"users"`
Users []UserInfo `json:"users"`
} }
type AliveMap struct { type AliveMap struct {
@@ -32,7 +34,8 @@ func (c *Client) GetUserList() ([]UserInfo, error) {
const path = "/api/v1/server/UniProxy/user" const path = "/api/v1/server/UniProxy/user"
r, err := c.client.R(). r, err := c.client.R().
SetHeader("If-None-Match", c.userEtag). SetHeader("If-None-Match", c.userEtag).
ForceContentType("application/json"). SetHeader("X-Response-Format", "msgpack").
SetDoNotParseResponse(true).
Get(path) Get(path)
if r == nil || r.RawResponse == nil { if r == nil || r.RawResponse == nil {
return nil, fmt.Errorf("received nil response or raw response") return nil, fmt.Errorf("received nil response or raw response")
@@ -47,9 +50,20 @@ func (c *Client) GetUserList() ([]UserInfo, error) {
return nil, err return nil, err
} }
userlist := &UserListBody{} userlist := &UserListBody{}
if err := json.Unmarshal(r.Body(), userlist); err != nil { if strings.Contains(r.Header().Get("Content-Type"), "application/x-msgpack") {
decoder := msgpack.NewDecoder(r.RawResponse.Body)
if err := decoder.Decode(userlist); err != nil {
return nil, fmt.Errorf("decode user list error: %w", err)
}
} else {
bodyBytes, err := io.ReadAll(r.RawResponse.Body)
if err != nil {
return nil, fmt.Errorf("read response body error: %w", err)
}
if err := json.Unmarshal(bodyBytes, userlist); err != nil {
return nil, fmt.Errorf("unmarshal user list error: %w", err) return nil, fmt.Errorf("unmarshal user list error: %w", err)
} }
}
c.userEtag = r.Header().Get("ETag") c.userEtag = r.Header().Get("ETag")
return userlist.Users, nil return userlist.Users, nil
} }

3
go.mod
View File

@@ -20,6 +20,7 @@ require (
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
github.com/vmihailenco/msgpack v4.0.4+incompatible
github.com/xtls/xray-core v1.250516.1-0.20250608135303-fbae89d017ae github.com/xtls/xray-core v1.250516.1-0.20250608135303-fbae89d017ae
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
golang.org/x/crypto v0.39.0 golang.org/x/crypto v0.39.0
@@ -124,6 +125,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
@@ -314,6 +316,7 @@ require (
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/api v0.214.0 // indirect google.golang.org/api v0.214.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect

4
go.sum
View File

@@ -1086,6 +1086,8 @@ github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5J
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60= github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE= 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 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
@@ -1548,6 +1550,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=

View File

@@ -24,11 +24,11 @@ type Limiter struct {
DomainRules []*regexp.Regexp DomainRules []*regexp.Regexp
ProtocolRules []string ProtocolRules []string
SpeedLimit int SpeedLimit int
UserOnlineIP *sync.Map // Key: Name, value: {Key: Ip, value: Uid} UserOnlineIP *sync.Map // Key: TagUUID, value: {Key: Ip, value: Uid}
OldUserOnline *sync.Map // Key: Ip, value: Uid OldUserOnline *sync.Map // Key: Ip, value: Uid
UUIDtoUID map[string]int // Key: UUID, value: Uid UUIDtoUID map[string]int // Key: UUID, value: Uid
UserLimitInfo *sync.Map // Key: Uid value: UserLimitInfo UserLimitInfo *sync.Map // Key: TagUUID value: UserLimitInfo
SpeedLimiter *sync.Map // key: Uid, value: *ratelimit.Bucket SpeedLimiter *sync.Map // key: TagUUID, value: *ratelimit.Bucket
AliveList map[int]int // Key: Uid, value: alive_ip AliveList map[int]int // Key: Uid, value: alive_ip
} }
@@ -91,6 +91,7 @@ func (l *Limiter) UpdateUser(tag string, added []panel.UserInfo, deleted []panel
for i := range deleted { for i := range deleted {
l.UserLimitInfo.Delete(format.UserTag(tag, deleted[i].Uuid)) l.UserLimitInfo.Delete(format.UserTag(tag, deleted[i].Uuid))
l.UserOnlineIP.Delete(format.UserTag(tag, deleted[i].Uuid)) l.UserOnlineIP.Delete(format.UserTag(tag, deleted[i].Uuid))
l.SpeedLimiter.Delete(format.UserTag(tag, deleted[i].Uuid))
delete(l.UUIDtoUID, deleted[i].Uuid) delete(l.UUIDtoUID, deleted[i].Uuid)
delete(l.AliveList, deleted[i].Id) delete(l.AliveList, deleted[i].Id)
} }