mirror of
https://github.com/XrayR-project/XrayR.git
synced 2025-06-08 13:29:54 +00:00
Optimize and upgrade docking parameters (#696)
This commit is contained in:
parent
34726d1659
commit
63c1a18a7d
@ -2,92 +2,71 @@ package gov2panel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
"github.com/XrayR-project/XrayR/api"
|
||||||
|
"github.com/gogf/gf/v2/encoding/gjson"
|
||||||
"github.com/bitly/go-simplejson"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/gogf/gf/v2/net/gclient"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/infra/conf"
|
"github.com/xtls/xray-core/infra/conf"
|
||||||
|
|
||||||
"github.com/XrayR-project/XrayR/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIClient create an api client to the panel.
|
// APIClient API config
|
||||||
type APIClient struct {
|
type APIClient struct {
|
||||||
client *resty.Client
|
ctx context.Context
|
||||||
APIHost string
|
APIHost string
|
||||||
NodeID int
|
NodeID int
|
||||||
Key string
|
Key string
|
||||||
NodeType string
|
NodeType string
|
||||||
EnableVless bool
|
EnableVless bool
|
||||||
VlessFlow string
|
VlessFlow string
|
||||||
|
Timeout int
|
||||||
SpeedLimit float64
|
SpeedLimit float64
|
||||||
DeviceLimit int
|
DeviceLimit int
|
||||||
|
RuleListPath string
|
||||||
|
DisableCustomConfig bool
|
||||||
|
|
||||||
LocalRuleList []api.DetectRule
|
LocalRuleList []api.DetectRule
|
||||||
resp atomic.Value
|
|
||||||
eTags map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New create an api instance
|
// New create an api instance
|
||||||
func New(apiConfig *api.Config) *APIClient {
|
func New(apiConfig *api.Config) *APIClient {
|
||||||
client := resty.New()
|
|
||||||
client.SetRetryCount(3)
|
//https://goframe.org/pages/viewpage.action?pageId=1114381
|
||||||
if apiConfig.Timeout > 0 {
|
|
||||||
client.SetTimeout(time.Duration(apiConfig.Timeout) * time.Second)
|
|
||||||
} else {
|
|
||||||
client.SetTimeout(5 * time.Second)
|
|
||||||
}
|
|
||||||
client.OnError(func(req *resty.Request, err error) {
|
|
||||||
if v, ok := err.(*resty.ResponseError); ok {
|
|
||||||
// v.Response contains the last response from the server
|
|
||||||
// v.Err contains the original error
|
|
||||||
log.Print(v.Err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
client.SetBaseURL(apiConfig.APIHost)
|
|
||||||
// Create Key for each requests
|
|
||||||
client.SetQueryParams(map[string]string{
|
|
||||||
"node_id": strconv.Itoa(apiConfig.NodeID),
|
|
||||||
"node_type": strings.ToLower(apiConfig.NodeType),
|
|
||||||
"token": apiConfig.Key,
|
|
||||||
})
|
|
||||||
// Read local rule list
|
|
||||||
localRuleList := readLocalRuleList(apiConfig.RuleListPath)
|
|
||||||
apiClient := &APIClient{
|
apiClient := &APIClient{
|
||||||
client: client,
|
ctx: context.Background(),
|
||||||
|
APIHost: apiConfig.APIHost,
|
||||||
NodeID: apiConfig.NodeID,
|
NodeID: apiConfig.NodeID,
|
||||||
Key: apiConfig.Key,
|
Key: apiConfig.Key,
|
||||||
APIHost: apiConfig.APIHost,
|
|
||||||
NodeType: apiConfig.NodeType,
|
NodeType: apiConfig.NodeType,
|
||||||
EnableVless: apiConfig.EnableVless,
|
EnableVless: apiConfig.EnableVless,
|
||||||
VlessFlow: apiConfig.VlessFlow,
|
VlessFlow: apiConfig.VlessFlow,
|
||||||
SpeedLimit: apiConfig.SpeedLimit,
|
Timeout: apiConfig.Timeout,
|
||||||
DeviceLimit: apiConfig.DeviceLimit,
|
DeviceLimit: apiConfig.DeviceLimit,
|
||||||
LocalRuleList: localRuleList,
|
RuleListPath: apiConfig.RuleListPath,
|
||||||
eTags: make(map[string]string),
|
DisableCustomConfig: apiConfig.DisableCustomConfig,
|
||||||
|
|
||||||
|
LocalRuleList: readLocalRuleList(apiConfig.RuleListPath), //加载本地路由规则
|
||||||
}
|
}
|
||||||
return apiClient
|
return apiClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// readLocalRuleList reads the local rule list file
|
// readLocalRuleList reads the local rule list file
|
||||||
func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
|
func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
|
||||||
LocalRuleList = make([]api.DetectRule, 0)
|
|
||||||
|
|
||||||
|
LocalRuleList = make([]api.DetectRule, 0)
|
||||||
if path != "" {
|
if path != "" {
|
||||||
// open the file
|
// open the file
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
defer file.Close()
|
|
||||||
// handle errors while opening
|
// handle errors while opening
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error when opening file: %s", err)
|
log.Printf("Error when opening file: %s", err)
|
||||||
@ -108,96 +87,77 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
|
|||||||
log.Fatalf("Error while reading file: %s", err)
|
log.Fatalf("Error while reading file: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
return LocalRuleList
|
return LocalRuleList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe return a description of the client
|
|
||||||
func (c *APIClient) Describe() api.ClientInfo {
|
|
||||||
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: c.Key, NodeType: c.NodeType}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug set the client debug for client
|
|
||||||
func (c *APIClient) Debug() {
|
|
||||||
c.client.SetDebug(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *APIClient) assembleURL(path string) string {
|
|
||||||
return c.APIHost + path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (*simplejson.Json, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("request %s failed: %v", c.assembleURL(path), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode() > 399 {
|
|
||||||
return nil, fmt.Errorf("request %s failed: %s, %v", c.assembleURL(path), res.String(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rtn, err := simplejson.NewJson(res.Body())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("ret %s invalid", res.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNodeInfo will pull NodeInfo Config from panel
|
|
||||||
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
|
func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
|
||||||
server := new(serverConfig)
|
|
||||||
path := "/api/server/config"
|
|
||||||
|
|
||||||
res, err := c.client.R().
|
apiPath := "/api/server/config"
|
||||||
SetHeader("If-None-Match", c.eTags["node"]).
|
reslutJson, err := c.sendRequest(
|
||||||
ForceContentType("application/json").
|
nil,
|
||||||
Get(path)
|
"POST",
|
||||||
|
apiPath,
|
||||||
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
|
g.Map{})
|
||||||
if res.StatusCode() == 304 {
|
|
||||||
return nil, errors.New(api.NodeNotModified)
|
|
||||||
}
|
|
||||||
// update etag
|
|
||||||
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["node"] {
|
|
||||||
c.eTags["node"] = res.Header().Get("Etag")
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeInfoResp, err := c.parseResponse(res, path, err)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b, _ := nodeInfoResp.Encode()
|
|
||||||
json.Unmarshal(b, server)
|
|
||||||
|
|
||||||
if gconv.Uint32(server.Port) == 0 {
|
if reslutJson.Get("data").String() == "" {
|
||||||
|
return nil, errors.New("gov2panel node config data is null")
|
||||||
|
}
|
||||||
|
|
||||||
|
if reslutJson.Get("data.port").Int() == 0 {
|
||||||
return nil, errors.New("server port must > 0")
|
return nil, errors.New("server port must > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.resp.Store(server)
|
nodeInfo = new(api.NodeInfo)
|
||||||
|
err = reslutJson.Get("data").Scan(nodeInfo)
|
||||||
switch c.NodeType {
|
|
||||||
case "V2ray", "Vmess", "Vless":
|
|
||||||
nodeInfo, err = c.parseV2rayNodeResponse(server)
|
|
||||||
case "Trojan":
|
|
||||||
nodeInfo, err = c.parseTrojanNodeResponse(server)
|
|
||||||
case "Shadowsocks":
|
|
||||||
nodeInfo, err = c.parseSSNodeResponse(server)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse node info failed: %s, \nError: %v", res.String(), err)
|
return nil, fmt.Errorf("parse node info failed: \nError: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
routes := make([]route, 0)
|
||||||
|
err = reslutJson.Get("data.routes").Scan(&routes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parse node routes failed: \nError: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeInfo.NodeType = c.NodeType
|
||||||
|
nodeInfo.NodeID = c.NodeID
|
||||||
|
nodeInfo.EnableVless = c.EnableVless
|
||||||
|
nodeInfo.VlessFlow = c.VlessFlow
|
||||||
|
|
||||||
|
nodeInfo.AlterID = 0
|
||||||
|
|
||||||
|
nodeInfo.NameServerConfig = parseDNSConfig(routes)
|
||||||
|
|
||||||
return nodeInfo, nil
|
return nodeInfo, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDNSConfig(routes []route) (nameServerList []*conf.NameServerConfig) {
|
||||||
|
|
||||||
|
nameServerList = make([]*conf.NameServerConfig, 0)
|
||||||
|
for i := range routes {
|
||||||
|
if routes[i].Action == "dns" {
|
||||||
|
nameServerList = append(nameServerList, &conf.NameServerConfig{
|
||||||
|
Address: &conf.Address{Address: net.ParseAddress(routes[i].ActionValue)},
|
||||||
|
Domains: routes[i].Match,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserList will pull user form panel
|
// GetUserList will pull user form panel
|
||||||
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
||||||
var users []*user
|
|
||||||
path := "/api/server/user"
|
apiPath := "/api/server/user"
|
||||||
|
|
||||||
switch c.NodeType {
|
switch c.NodeType {
|
||||||
case "V2ray", "Trojan", "Shadowsocks", "Vmess", "Vless":
|
case "V2ray", "Trojan", "Shadowsocks", "Vmess", "Vless":
|
||||||
@ -206,29 +166,17 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
|||||||
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
|
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := c.client.R().
|
reslutJson, err := c.sendRequest(
|
||||||
SetHeader("If-None-Match", c.eTags["users"]).
|
nil,
|
||||||
ForceContentType("application/json").
|
"GET",
|
||||||
Get(path)
|
apiPath,
|
||||||
|
g.Map{})
|
||||||
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
|
|
||||||
if res.StatusCode() == 304 {
|
|
||||||
return nil, errors.New(api.UserNotModified)
|
|
||||||
}
|
|
||||||
// update etag
|
|
||||||
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["users"] {
|
|
||||||
c.eTags["users"] = res.Header().Get("Etag")
|
|
||||||
}
|
|
||||||
|
|
||||||
usersResp, err := c.parseResponse(res, path, err)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b, _ := usersResp.Get("users").Encode()
|
|
||||||
json.Unmarshal(b, &users)
|
var users []*user
|
||||||
if len(users) == 0 {
|
reslutJson.Get("data.users").Scan(&users)
|
||||||
return nil, errors.New("users is null")
|
|
||||||
}
|
|
||||||
|
|
||||||
userList := make([]api.UserInfo, len(users))
|
userList := make([]api.UserInfo, len(users))
|
||||||
for i := 0; i < len(users); i++ {
|
for i := 0; i < len(users); i++ {
|
||||||
@ -255,148 +203,126 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
|||||||
return &userList, nil
|
return &userList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportUserTraffic reports the user traffic
|
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
||||||
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
|
return
|
||||||
path := "/api/server/push"
|
}
|
||||||
|
|
||||||
res, err := c.client.R().SetBody(userTraffic).ForceContentType("application/json").Post(path)
|
func (c *APIClient) ReportNodeOnlineUsers(onlineUser *[]api.OnlineUser) (err error) {
|
||||||
_, err = c.parseResponse(res, path, err)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportUserTraffic reports the user traffic
|
||||||
|
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) (err error) {
|
||||||
|
apiPath := "/api/server/push"
|
||||||
|
reslutJson, err := c.sendRequest(
|
||||||
|
nil,
|
||||||
|
"POST",
|
||||||
|
apiPath,
|
||||||
|
g.Map{
|
||||||
|
"data": userTraffic,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if reslutJson.Get("code").Int() != 0 {
|
||||||
}
|
return errors.New(reslutJson.Get("message").String())
|
||||||
|
}
|
||||||
// GetNodeRule implements the API interface
|
|
||||||
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
|
return
|
||||||
routes := c.resp.Load().(*serverConfig).Routes
|
}
|
||||||
|
|
||||||
ruleList := c.LocalRuleList
|
func (c *APIClient) Describe() api.ClientInfo {
|
||||||
|
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: c.Key, NodeType: c.NodeType}
|
||||||
for i := range routes {
|
}
|
||||||
if routes[i].Action == "block" {
|
|
||||||
|
// GetNodeRule implements the API interface
|
||||||
ruleList = append(ruleList, api.DetectRule{
|
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
|
||||||
ID: i,
|
ruleList := c.LocalRuleList
|
||||||
Pattern: regexp.MustCompile(strings.Join(routes[i].Match, "|")),
|
|
||||||
})
|
apiPath := "/api/server/config"
|
||||||
}
|
reslutJson, err := c.sendRequest(
|
||||||
}
|
nil,
|
||||||
|
"POST",
|
||||||
return &ruleList, nil
|
apiPath,
|
||||||
}
|
g.Map{})
|
||||||
|
if err != nil {
|
||||||
// ReportNodeStatus implements the API interface
|
return nil, err
|
||||||
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
}
|
||||||
return nil
|
|
||||||
}
|
routes := make([]route, 0)
|
||||||
|
err = reslutJson.Get("data.routes").Scan(&routes)
|
||||||
// ReportNodeOnlineUsers implements the API interface
|
if err != nil {
|
||||||
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error {
|
return nil, fmt.Errorf("parse node routes failed: \nError: %v", err)
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
for i := range routes {
|
||||||
// ReportIllegal implements the API interface
|
if routes[i].Action == "block" {
|
||||||
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
|
for _, v := range routes[i].Match {
|
||||||
return nil
|
ruleList = append(ruleList, api.DetectRule{
|
||||||
}
|
ID: i,
|
||||||
|
Pattern: regexp.MustCompile(v),
|
||||||
// parseTrojanNodeResponse parse the response for the given nodeInfo format
|
})
|
||||||
func (c *APIClient) parseTrojanNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
|
}
|
||||||
// Create GeneralNodeInfo
|
|
||||||
nodeInfo := &api.NodeInfo{
|
}
|
||||||
NodeType: c.NodeType,
|
}
|
||||||
NodeID: c.NodeID,
|
|
||||||
Port: gconv.Uint32(s.Port),
|
return &ruleList, nil
|
||||||
TransportProtocol: "tcp",
|
|
||||||
EnableTLS: true,
|
}
|
||||||
Host: s.Host,
|
|
||||||
ServiceName: s.Sni,
|
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) (err error) {
|
||||||
NameServerConfig: s.parseDNSConfig(),
|
return
|
||||||
}
|
}
|
||||||
return nodeInfo, nil
|
|
||||||
}
|
func (c *APIClient) Debug() {
|
||||||
|
|
||||||
// parseSSNodeResponse parse the response for the given nodeInfo format
|
}
|
||||||
func (c *APIClient) parseSSNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
|
|
||||||
var header json.RawMessage
|
// request 统一请求接口
|
||||||
|
func (c *APIClient) sendRequest(headerM map[string]string, method string, url string, data g.Map) (reslutJson *gjson.Json, err error) {
|
||||||
if s.Obfs == "http" {
|
url = c.APIHost + url
|
||||||
path := "/"
|
|
||||||
if p := s.ObfsSettings.Path; p != "" {
|
client := gclient.New()
|
||||||
if strings.HasPrefix(p, "/") {
|
|
||||||
path = p
|
var gResponse *gclient.Response
|
||||||
} else {
|
|
||||||
path += p
|
if c.Timeout > 0 {
|
||||||
}
|
client.SetTimeout(time.Duration(c.Timeout) * time.Second) //方法用于设置当前请求超时时间
|
||||||
}
|
} else {
|
||||||
h := simplejson.New()
|
client.SetTimeout(5 * time.Second)
|
||||||
h.Set("type", "http")
|
}
|
||||||
h.SetPath([]string{"request", "path"}, path)
|
client.Retry(3, 10*time.Second) //方法用于设置请求失败时重连次数和重连间隔。
|
||||||
header, _ = h.Encode()
|
|
||||||
}
|
client.SetHeaderMap(headerM)
|
||||||
// Create GeneralNodeInfo
|
client.SetHeader("Content-Type", "application/json")
|
||||||
return &api.NodeInfo{
|
|
||||||
NodeType: c.NodeType,
|
data["token"] = c.Key
|
||||||
NodeID: c.NodeID,
|
data["node_id"] = c.NodeID
|
||||||
Port: gconv.Uint32(s.Port),
|
|
||||||
TransportProtocol: "tcp",
|
switch method {
|
||||||
CypherMethod: s.Encryption,
|
case "GET":
|
||||||
ServerKey: s.ServerKey, // shadowsocks2022 share key
|
gResponse, err = client.Get(c.ctx, url, data)
|
||||||
NameServerConfig: s.parseDNSConfig(),
|
case "POST":
|
||||||
Header: header,
|
gResponse, err = client.Post(c.ctx, url, data)
|
||||||
}, nil
|
default:
|
||||||
}
|
err = fmt.Errorf("unsupported method: %s", method)
|
||||||
|
return
|
||||||
// parseV2rayNodeResponse parse the response for the given nodeInfo format
|
}
|
||||||
func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
|
|
||||||
var (
|
if err != nil {
|
||||||
header json.RawMessage
|
return
|
||||||
enableTLS bool
|
}
|
||||||
)
|
defer gResponse.Close()
|
||||||
|
|
||||||
switch s.Net {
|
reslutJson = gjson.New(gResponse.ReadAllString())
|
||||||
case "tcp":
|
if reslutJson == nil {
|
||||||
if s.Header != nil {
|
err = fmt.Errorf("http reslut to json, err : %s", gResponse.ReadAllString())
|
||||||
if httpHeader, err := s.Header.MarshalJSON(); err != nil {
|
}
|
||||||
return nil, err
|
if reslutJson.Get("code").Int() != 0 {
|
||||||
} else {
|
err = errors.New(reslutJson.Get("message").String())
|
||||||
header = httpHeader
|
return
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.TLS == "tls" {
|
|
||||||
enableTLS = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create GeneralNodeInfo
|
|
||||||
return &api.NodeInfo{
|
|
||||||
NodeType: c.NodeType,
|
|
||||||
NodeID: c.NodeID,
|
|
||||||
Port: gconv.Uint32(s.Port),
|
|
||||||
AlterID: 0,
|
|
||||||
TransportProtocol: s.Net,
|
|
||||||
EnableTLS: enableTLS,
|
|
||||||
Path: s.Path,
|
|
||||||
Host: s.Host,
|
|
||||||
EnableVless: c.EnableVless,
|
|
||||||
VlessFlow: c.VlessFlow,
|
|
||||||
ServiceName: s.Sni,
|
|
||||||
Header: header,
|
|
||||||
NameServerConfig: s.parseDNSConfig(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serverConfig) parseDNSConfig() (nameServerList []*conf.NameServerConfig) {
|
|
||||||
for i := range s.Routes {
|
|
||||||
if s.Routes[i].Action == "dns" {
|
|
||||||
nameServerList = append(nameServerList, &conf.NameServerConfig{
|
|
||||||
Address: &conf.Address{Address: net.ParseAddress(s.Routes[i].ActionValue)},
|
|
||||||
Domains: s.Routes[i].Match,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -5,56 +5,31 @@ import (
|
|||||||
|
|
||||||
"github.com/XrayR-project/XrayR/api"
|
"github.com/XrayR-project/XrayR/api"
|
||||||
"github.com/XrayR-project/XrayR/api/gov2panel"
|
"github.com/XrayR-project/XrayR/api/gov2panel"
|
||||||
|
"github.com/gogf/gf/v2/encoding/gjson"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateClient() api.API {
|
func CreateClient() api.API {
|
||||||
apiConfig := &api.Config{
|
apiConfig := &api.Config{
|
||||||
APIHost: "http://localhost:8080",
|
APIHost: "http://localhost:8080",
|
||||||
Key: "123456",
|
Key: "123456",
|
||||||
NodeID: 1,
|
NodeID: 90,
|
||||||
NodeType: "V2ray",
|
NodeType: "V2ray",
|
||||||
}
|
}
|
||||||
client := gov2panel.New(apiConfig)
|
client := gov2panel.New(apiConfig)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetV2rayNodeInfo(t *testing.T) {
|
func TestGetNodeInfo(t *testing.T) {
|
||||||
client := CreateClient()
|
client := CreateClient()
|
||||||
nodeInfo, err := client.GetNodeInfo()
|
nodeInfo, err := client.GetNodeInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
t.Log(nodeInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetSSNodeInfo(t *testing.T) {
|
nodeInfoJson := gjson.New(nodeInfo)
|
||||||
apiConfig := &api.Config{
|
t.Log(nodeInfoJson.String())
|
||||||
APIHost: "http://127.0.0.1:668",
|
t.Log(nodeInfoJson.String())
|
||||||
Key: "qwertyuiopasdfghjkl",
|
|
||||||
NodeID: 1,
|
|
||||||
NodeType: "Shadowsocks",
|
|
||||||
}
|
|
||||||
client := gov2panel.New(apiConfig)
|
|
||||||
nodeInfo, err := client.GetNodeInfo()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
t.Log(nodeInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetTrojanNodeInfo(t *testing.T) {
|
|
||||||
apiConfig := &api.Config{
|
|
||||||
APIHost: "http://127.0.0.1:668",
|
|
||||||
Key: "qwertyuiopasdfghjkl",
|
|
||||||
NodeID: 1,
|
|
||||||
NodeType: "Trojan",
|
|
||||||
}
|
|
||||||
client := gov2panel.New(apiConfig)
|
|
||||||
nodeInfo, err := client.GetNodeInfo()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
t.Log(nodeInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUserList(t *testing.T) {
|
func TestGetUserList(t *testing.T) {
|
||||||
@ -65,6 +40,7 @@ func TestGetUserList(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Log(len(*userList))
|
||||||
t.Log(userList)
|
t.Log(userList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,24 +50,30 @@ func TestReportReportUserTraffic(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
t.Log(userList)
|
||||||
generalUserTraffic := make([]api.UserTraffic, len(*userList))
|
generalUserTraffic := make([]api.UserTraffic, len(*userList))
|
||||||
for i, userInfo := range *userList {
|
for i, userInfo := range *userList {
|
||||||
generalUserTraffic[i] = api.UserTraffic{
|
generalUserTraffic[i] = api.UserTraffic{
|
||||||
UID: userInfo.UID,
|
UID: userInfo.UID,
|
||||||
Upload: 1111,
|
Upload: 1073741824,
|
||||||
Download: 2222,
|
Download: 1073741824,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// client.Debug()
|
|
||||||
|
t.Log(gconv.String(generalUserTraffic))
|
||||||
|
client = CreateClient()
|
||||||
err = client.ReportUserTraffic(&generalUserTraffic)
|
err = client.ReportUserTraffic(&generalUserTraffic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetNodeRule(t *testing.T) {
|
func TestGetNodeRule(t *testing.T) {
|
||||||
|
|
||||||
client := CreateClient()
|
client := CreateClient()
|
||||||
client.Debug()
|
client.Debug()
|
||||||
|
|
||||||
ruleList, err := client.GetNodeRule()
|
ruleList, err := client.GetNodeRule()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -1,35 +1,9 @@
|
|||||||
package gov2panel
|
package gov2panel
|
||||||
|
|
||||||
import "encoding/json"
|
type user struct {
|
||||||
|
Id int `json:"id"`
|
||||||
type serverConfig struct {
|
Uuid string `json:"uuid"`
|
||||||
v2ray
|
SpeedLimit int `json:"speed_limit"`
|
||||||
shadowsocks
|
|
||||||
//---
|
|
||||||
Routes []route `json:"routes"`
|
|
||||||
Header *json.RawMessage `json:"header"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type v2ray struct {
|
|
||||||
Port string `json:"port"`
|
|
||||||
Scy string `json:"scy"`
|
|
||||||
Net string `json:"net"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
TLS string `json:"tls"`
|
|
||||||
Sni string `json:"sni"`
|
|
||||||
Alpn string `json:"alpn"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type shadowsocks struct {
|
|
||||||
Encryption string `json:"encryption"`
|
|
||||||
Obfs string `json:"obfs"`
|
|
||||||
ObfsSettings struct {
|
|
||||||
Path string `json:"path"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
} `json:"obfs_settings"`
|
|
||||||
ServerKey string `json:"server_key"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type route struct {
|
type route struct {
|
||||||
@ -38,9 +12,3 @@ type route struct {
|
|||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
ActionValue string `json:"action_value"`
|
ActionValue string `json:"action_value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type user struct {
|
|
||||||
Id int `json:"id"`
|
|
||||||
Uuid string `json:"uuid"`
|
|
||||||
SpeedLimit int `json:"speed_limit"`
|
|
||||||
}
|
|
||||||
|
6
go.mod
6
go.mod
@ -85,6 +85,7 @@ require (
|
|||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/civo/civogo v0.3.63 // indirect
|
github.com/civo/civogo v0.3.63 // indirect
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.9 // indirect
|
github.com/cloudflare/circl v1.3.9 // indirect
|
||||||
github.com/cloudflare/cloudflare-go v0.90.0 // indirect
|
github.com/cloudflare/cloudflare-go v0.90.0 // indirect
|
||||||
github.com/cpu/goacmedns v0.1.1 // indirect
|
github.com/cpu/goacmedns v0.1.1 // indirect
|
||||||
@ -95,6 +96,7 @@ require (
|
|||||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
|
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
|
||||||
github.com/exoscale/egoscale v1.19.0 // indirect
|
github.com/exoscale/egoscale v1.19.0 // indirect
|
||||||
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/flosch/pongo2/v4 v4.0.2 // indirect
|
github.com/flosch/pongo2/v4 v4.0.2 // indirect
|
||||||
@ -135,6 +137,7 @@ require (
|
|||||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
|
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
@ -173,6 +176,7 @@ require (
|
|||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
||||||
github.com/miekg/dns v1.1.61 // indirect
|
github.com/miekg/dns v1.1.61 // indirect
|
||||||
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
|
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
|
||||||
@ -192,6 +196,7 @@ require (
|
|||||||
github.com/nrdcg/nodion v0.1.0 // indirect
|
github.com/nrdcg/nodion v0.1.0 // indirect
|
||||||
github.com/nrdcg/porkbun v0.3.0 // indirect
|
github.com/nrdcg/porkbun v0.3.0 // indirect
|
||||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
|
||||||
@ -212,6 +217,7 @@ require (
|
|||||||
github.com/quic-go/quic-go v0.45.1 // indirect
|
github.com/quic-go/quic-go v0.45.1 // indirect
|
||||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sacloud/api-client-go v0.2.10 // indirect
|
github.com/sacloud/api-client-go v0.2.10 // indirect
|
||||||
github.com/sacloud/go-http v0.1.8 // indirect
|
github.com/sacloud/go-http v0.1.8 // indirect
|
||||||
|
Loading…
x
Reference in New Issue
Block a user