mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 12:40:11 +00:00
测试:尝试增加hysteria2协议,尝试增加设备数限制功能
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
package iprecoder
|
||||
|
||||
import (
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
)
|
||||
|
||||
type IpRecorder interface {
|
||||
SyncOnlineIp(Ips []limiter.UserIpList) ([]limiter.UserIpList, error)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package iprecoder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
type Recorder struct {
|
||||
client *resty.Client
|
||||
*conf.RecorderConfig
|
||||
}
|
||||
|
||||
func NewRecorder(c *conf.RecorderConfig) *Recorder {
|
||||
return &Recorder{
|
||||
client: resty.New().SetTimeout(time.Duration(c.Timeout) * time.Second),
|
||||
RecorderConfig: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Recorder) SyncOnlineIp(ips []limiter.UserIpList) ([]limiter.UserIpList, error) {
|
||||
rsp, err := r.client.R().
|
||||
SetBody(ips).
|
||||
Post(r.Url + "/api/v1/SyncOnlineIp?token=" + r.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rsp.StatusCode() != 200 {
|
||||
return nil, errors.New(rsp.String())
|
||||
}
|
||||
ips = []limiter.UserIpList{}
|
||||
err = json.Unmarshal(rsp.Body(), &ips)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package iprecoder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type Redis struct {
|
||||
*conf.RedisConfig
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewRedis(c *conf.RedisConfig) *Redis {
|
||||
return &Redis{
|
||||
RedisConfig: c,
|
||||
client: redis.NewClient(&redis.Options{
|
||||
Addr: c.Address,
|
||||
Password: c.Password,
|
||||
DB: c.Db,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Redis) SyncOnlineIp(Ips []limiter.UserIpList) ([]limiter.UserIpList, error) {
|
||||
ctx := context.Background()
|
||||
for i := range Ips {
|
||||
err := r.client.SAdd(ctx, "UserList", Ips[i].Uid).Err()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("add user failed: %s", err)
|
||||
}
|
||||
r.client.Expire(ctx, "UserList", time.Second*time.Duration(r.Expiry))
|
||||
for _, ip := range Ips[i].IpList {
|
||||
err := r.client.SAdd(ctx, strconv.Itoa(Ips[i].Uid), ip).Err()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("add ip failed: %s", err)
|
||||
}
|
||||
r.client.Expire(ctx, strconv.Itoa(Ips[i].Uid), time.Second*time.Duration(r.Expiry))
|
||||
}
|
||||
}
|
||||
c := r.client.SMembers(ctx, "UserList")
|
||||
if c.Err() != nil {
|
||||
return nil, fmt.Errorf("get user list failed: %s", c.Err())
|
||||
}
|
||||
Ips = make([]limiter.UserIpList, 0, len(c.Val()))
|
||||
for _, uid := range c.Val() {
|
||||
uidInt, err := strconv.Atoi(uid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("convert uid failed: %s", err)
|
||||
}
|
||||
ips := r.client.SMembers(ctx, uid)
|
||||
if ips.Err() != nil {
|
||||
return nil, fmt.Errorf("get ip list failed: %s", ips.Err())
|
||||
}
|
||||
Ips = append(Ips, limiter.UserIpList{
|
||||
Uid: uidInt,
|
||||
IpList: ips.Val(),
|
||||
})
|
||||
}
|
||||
return Ips, nil
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package iprecoder
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
)
|
||||
|
||||
func TestRedis_SyncOnlineIp(t *testing.T) {
|
||||
r := NewRedis(&conf.RedisConfig{
|
||||
Address: "127.0.0.1:6379",
|
||||
Password: "",
|
||||
Db: 0,
|
||||
})
|
||||
users, err := r.SyncOnlineIp([]limiter.UserIpList{
|
||||
{1, []string{"5.5.5.5", "4.4.4.4"}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
log.Println(users)
|
||||
}
|
||||
@@ -33,6 +33,7 @@ type NodeInfo struct {
|
||||
Shadowsocks *ShadowsocksNode
|
||||
Trojan *TrojanNode
|
||||
Hysteria *HysteriaNode
|
||||
Hysteria2 *Hysteria2Node
|
||||
Common *CommonNode
|
||||
}
|
||||
|
||||
@@ -100,6 +101,14 @@ type HysteriaNode struct {
|
||||
Obfs string `json:"obfs"`
|
||||
}
|
||||
|
||||
type Hysteria2Node struct {
|
||||
CommonNode
|
||||
UpMbps int `json:"up_mbps"`
|
||||
DownMbps int `json:"down_mbps"`
|
||||
ObfsType string `json:"obfs"`
|
||||
ObfsPassword string `json:"obfs-password"`
|
||||
}
|
||||
|
||||
type RawDNS struct {
|
||||
DNSMap map[string]map[string]interface{}
|
||||
DNSJson []byte
|
||||
@@ -166,7 +175,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
rsp := &ShadowsocksNode{}
|
||||
err = json.Unmarshal(r.Body(), rsp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode v2ray params error: %s", err)
|
||||
return nil, fmt.Errorf("decode shadowsocks params error: %s", err)
|
||||
}
|
||||
cm = &rsp.CommonNode
|
||||
node.Shadowsocks = rsp
|
||||
@@ -175,7 +184,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
rsp := &TrojanNode{}
|
||||
err = json.Unmarshal(r.Body(), rsp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode v2ray params error: %s", err)
|
||||
return nil, fmt.Errorf("decode trojan params error: %s", err)
|
||||
}
|
||||
cm = (*CommonNode)(rsp)
|
||||
node.Trojan = rsp
|
||||
@@ -184,11 +193,20 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
rsp := &HysteriaNode{}
|
||||
err = json.Unmarshal(r.Body(), rsp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode v2ray params error: %s", err)
|
||||
return nil, fmt.Errorf("decode hysteria params error: %s", err)
|
||||
}
|
||||
cm = &rsp.CommonNode
|
||||
node.Hysteria = rsp
|
||||
node.Security = Tls
|
||||
case "hysteria2":
|
||||
rsp := &Hysteria2Node{}
|
||||
err = json.Unmarshal(r.Body(), rsp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode hysteria2 params error: %s", err)
|
||||
}
|
||||
cm = &rsp.CommonNode
|
||||
node.Hysteria2 = rsp
|
||||
node.Security = Tls
|
||||
}
|
||||
|
||||
// parse rules and dns
|
||||
|
||||
@@ -16,13 +16,14 @@ import (
|
||||
// Panel is the interface for different panel's api.
|
||||
|
||||
type Client struct {
|
||||
client *resty.Client
|
||||
APIHost string
|
||||
Token string
|
||||
NodeType string
|
||||
NodeId int
|
||||
nodeEtag string
|
||||
userEtag string
|
||||
client *resty.Client
|
||||
APIHost string
|
||||
Token string
|
||||
NodeType string
|
||||
NodeId int
|
||||
nodeEtag string
|
||||
userEtag string
|
||||
LastReportOnline map[int]int
|
||||
}
|
||||
|
||||
func New(c *conf.ApiConfig) (*Client, error) {
|
||||
@@ -52,6 +53,7 @@ func New(c *conf.ApiConfig) (*Client, error) {
|
||||
"trojan",
|
||||
"shadowsocks",
|
||||
"hysteria",
|
||||
"hysteria2",
|
||||
"vless":
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
|
||||
|
||||
@@ -2,6 +2,7 @@ package panel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
@@ -11,9 +12,11 @@ type OnlineUser struct {
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
Id int `json:"id"`
|
||||
Uuid string `json:"uuid"`
|
||||
SpeedLimit int `json:"speed_limit"`
|
||||
Id int `json:"id"`
|
||||
Uuid string `json:"uuid"`
|
||||
SpeedLimit int `json:"speed_limit"`
|
||||
DeviceLimit int `json:"device_limit"`
|
||||
AliveIp int `json:"alive_ip"`
|
||||
}
|
||||
|
||||
type UserListBody struct {
|
||||
@@ -31,7 +34,7 @@ func (c *Client) GetUserList() (UserList []UserInfo, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.checkResponse(r, path, err)
|
||||
|
||||
if r.StatusCode() == 304 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -41,7 +44,30 @@ func (c *Client) GetUserList() (UserList []UserInfo, err error) {
|
||||
return nil, fmt.Errorf("unmarshal userlist error: %s", err)
|
||||
}
|
||||
c.userEtag = r.Header().Get("ETag")
|
||||
return userList.Users, nil
|
||||
|
||||
var userinfos []UserInfo
|
||||
var localDeviceLimit int = 0
|
||||
for _, user := range userList.Users {
|
||||
// If there is still device available, add the user
|
||||
if user.DeviceLimit > 0 && user.AliveIp > 0 {
|
||||
lastOnline := 0
|
||||
if v, ok := c.LastReportOnline[user.Id]; ok {
|
||||
lastOnline = v
|
||||
}
|
||||
// If there are any available device.
|
||||
localDeviceLimit = user.DeviceLimit - user.AliveIp + lastOnline
|
||||
if localDeviceLimit > 0 {
|
||||
|
||||
} else if lastOnline > 0 {
|
||||
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
userinfos = append(userinfos, user)
|
||||
}
|
||||
|
||||
return userinfos, nil
|
||||
}
|
||||
|
||||
type UserTraffic struct {
|
||||
@@ -67,3 +93,19 @@ func (c *Client) ReportUserTraffic(userTraffic []UserTraffic) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) ReportNodeOnlineUsers(data *map[int][]string, reportOnline *map[int]int) error {
|
||||
c.LastReportOnline = *reportOnline
|
||||
const path = "/api/v1/server/UniProxy/alive"
|
||||
r, err := c.client.R().
|
||||
SetBody(data).
|
||||
ForceContentType("application/json").
|
||||
Post(path)
|
||||
err = c.checkResponse(r, path, err)
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user