mirror of
https://github.com/XrayR-project/XrayR.git
synced 2025-06-15 00:39:53 +00:00
对接GoV2Panel面板 (#474)
* Update actions * up --------- Co-authored-by: thank243 <thank243@gmail.com>
This commit is contained in:
parent
b8d40c201b
commit
4c52e33adb
@ -62,6 +62,7 @@ A Xray backend framework that can easily support many panels.
|
||||
| [PMPanel](https://github.com/ByteInternetHK/PMPanel) | √ | √ | √ |
|
||||
| [ProxyPanel](https://github.com/ProxyPanel/ProxyPanel) | √ | √ | √ |
|
||||
| [WHMCS (V2RaySocks)](https://v2raysocks.doxtex.com/) | √ | √ | √ |
|
||||
| [GoV2Panel](https://github.com/pingProMax/gov2panel) | √ | √ | √ |
|
||||
|
||||
## 软件安装
|
||||
|
||||
|
402
api/gov2panel/gov2panel.go
Normal file
402
api/gov2panel/gov2panel.go
Normal file
@ -0,0 +1,402 @@
|
||||
package gov2panel
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/bitly/go-simplejson"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/infra/conf"
|
||||
|
||||
"github.com/XrayR-project/XrayR/api"
|
||||
)
|
||||
|
||||
// APIClient create an api client to the panel.
|
||||
type APIClient struct {
|
||||
client *resty.Client
|
||||
APIHost string
|
||||
NodeID int
|
||||
Key string
|
||||
NodeType string
|
||||
EnableVless bool
|
||||
VlessFlow string
|
||||
SpeedLimit float64
|
||||
DeviceLimit int
|
||||
LocalRuleList []api.DetectRule
|
||||
resp atomic.Value
|
||||
eTags map[string]string
|
||||
}
|
||||
|
||||
// New create an api instance
|
||||
func New(apiConfig *api.Config) *APIClient {
|
||||
client := resty.New()
|
||||
client.SetRetryCount(3)
|
||||
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{
|
||||
client: client,
|
||||
NodeID: apiConfig.NodeID,
|
||||
Key: apiConfig.Key,
|
||||
APIHost: apiConfig.APIHost,
|
||||
NodeType: apiConfig.NodeType,
|
||||
EnableVless: apiConfig.EnableVless,
|
||||
VlessFlow: apiConfig.VlessFlow,
|
||||
SpeedLimit: apiConfig.SpeedLimit,
|
||||
DeviceLimit: apiConfig.DeviceLimit,
|
||||
LocalRuleList: localRuleList,
|
||||
eTags: make(map[string]string),
|
||||
}
|
||||
return apiClient
|
||||
}
|
||||
|
||||
// readLocalRuleList reads the local rule list file
|
||||
func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {
|
||||
LocalRuleList = make([]api.DetectRule, 0)
|
||||
|
||||
if path != "" {
|
||||
// open the file
|
||||
file, err := os.Open(path)
|
||||
defer file.Close()
|
||||
// handle errors while opening
|
||||
if err != nil {
|
||||
log.Printf("Error when opening file: %s", err)
|
||||
return LocalRuleList
|
||||
}
|
||||
|
||||
fileScanner := bufio.NewScanner(file)
|
||||
|
||||
// read line by line
|
||||
for fileScanner.Scan() {
|
||||
LocalRuleList = append(LocalRuleList, api.DetectRule{
|
||||
ID: -1,
|
||||
Pattern: regexp.MustCompile(fileScanner.Text()),
|
||||
})
|
||||
}
|
||||
// handle first encountered error while reading
|
||||
if err := fileScanner.Err(); err != nil {
|
||||
log.Fatalf("Error while reading file: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
server := new(serverConfig)
|
||||
path := "/api/server/config"
|
||||
|
||||
res, err := c.client.R().
|
||||
SetHeader("If-None-Match", c.eTags["node"]).
|
||||
ForceContentType("application/json").
|
||||
Get(path)
|
||||
|
||||
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
b, _ := nodeInfoResp.Encode()
|
||||
json.Unmarshal(b, server)
|
||||
|
||||
if gconv.Uint32(server.Port) == 0 {
|
||||
return nil, errors.New("server port must > 0")
|
||||
}
|
||||
|
||||
c.resp.Store(server)
|
||||
|
||||
switch c.NodeType {
|
||||
case "V2ray":
|
||||
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 {
|
||||
return nil, fmt.Errorf("parse node info failed: %s, \nError: %v", res.String(), err)
|
||||
}
|
||||
|
||||
return nodeInfo, nil
|
||||
}
|
||||
|
||||
// GetUserList will pull user form panel
|
||||
func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
|
||||
var users []*user
|
||||
path := "/api/server/user"
|
||||
|
||||
switch c.NodeType {
|
||||
case "V2ray", "Trojan", "Shadowsocks":
|
||||
break
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported node type: %s", c.NodeType)
|
||||
}
|
||||
|
||||
res, err := c.client.R().
|
||||
SetHeader("If-None-Match", c.eTags["users"]).
|
||||
ForceContentType("application/json").
|
||||
Get(path)
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
b, _ := usersResp.Get("users").Encode()
|
||||
json.Unmarshal(b, &users)
|
||||
if len(users) == 0 {
|
||||
return nil, errors.New("users is null")
|
||||
}
|
||||
|
||||
userList := make([]api.UserInfo, len(users))
|
||||
for i := 0; i < len(users); i++ {
|
||||
u := api.UserInfo{
|
||||
UID: users[i].Id,
|
||||
UUID: users[i].Uuid,
|
||||
}
|
||||
|
||||
// Support 1.7.1 speed limit
|
||||
if c.SpeedLimit > 0 {
|
||||
u.SpeedLimit = uint64(c.SpeedLimit * 1000000 / 8)
|
||||
} else {
|
||||
u.SpeedLimit = uint64(users[i].SpeedLimit * 1000000 / 8)
|
||||
}
|
||||
|
||||
u.DeviceLimit = c.DeviceLimit // todo waiting v2board send configuration
|
||||
u.Email = u.UUID + "@gov2panel.user"
|
||||
if c.NodeType == "Shadowsocks" {
|
||||
u.Passwd = u.UUID
|
||||
}
|
||||
userList[i] = u
|
||||
}
|
||||
|
||||
return &userList, nil
|
||||
}
|
||||
|
||||
// ReportUserTraffic reports the user traffic
|
||||
func (c *APIClient) ReportUserTraffic(userTraffic *[]api.UserTraffic) error {
|
||||
path := "/api/server/push"
|
||||
|
||||
res, err := c.client.R().SetBody(userTraffic).ForceContentType("application/json").Post(path)
|
||||
_, err = c.parseResponse(res, path, err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNodeRule implements the API interface
|
||||
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
|
||||
routes := c.resp.Load().(*serverConfig).Routes
|
||||
|
||||
ruleList := c.LocalRuleList
|
||||
|
||||
for i := range routes {
|
||||
if routes[i].Action == "block" {
|
||||
|
||||
ruleList = append(ruleList, api.DetectRule{
|
||||
ID: i,
|
||||
Pattern: regexp.MustCompile(strings.Join(routes[i].Match, "|")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &ruleList, nil
|
||||
}
|
||||
|
||||
// ReportNodeStatus implements the API interface
|
||||
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReportNodeOnlineUsers implements the API interface
|
||||
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList *[]api.OnlineUser) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReportIllegal implements the API interface
|
||||
func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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),
|
||||
TransportProtocol: "tcp",
|
||||
EnableTLS: true,
|
||||
Host: s.Host,
|
||||
ServiceName: s.Sni,
|
||||
NameServerConfig: s.parseDNSConfig(),
|
||||
}
|
||||
return nodeInfo, nil
|
||||
}
|
||||
|
||||
// parseSSNodeResponse parse the response for the given nodeInfo format
|
||||
func (c *APIClient) parseSSNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
|
||||
var header json.RawMessage
|
||||
|
||||
if s.Obfs == "http" {
|
||||
path := "/"
|
||||
if p := s.ObfsSettings.Path; p != "" {
|
||||
if strings.HasPrefix(p, "/") {
|
||||
path = p
|
||||
} else {
|
||||
path += p
|
||||
}
|
||||
}
|
||||
h := simplejson.New()
|
||||
h.Set("type", "http")
|
||||
h.SetPath([]string{"request", "path"}, path)
|
||||
header, _ = h.Encode()
|
||||
}
|
||||
// Create GeneralNodeInfo
|
||||
return &api.NodeInfo{
|
||||
NodeType: c.NodeType,
|
||||
NodeID: c.NodeID,
|
||||
Port: gconv.Uint32(s.Port),
|
||||
TransportProtocol: "tcp",
|
||||
CypherMethod: s.Encryption,
|
||||
ServerKey: s.ServerKey, // shadowsocks2022 share key
|
||||
NameServerConfig: s.parseDNSConfig(),
|
||||
Header: header,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseV2rayNodeResponse parse the response for the given nodeInfo format
|
||||
func (c *APIClient) parseV2rayNodeResponse(s *serverConfig) (*api.NodeInfo, error) {
|
||||
var (
|
||||
header json.RawMessage
|
||||
enableTLS bool
|
||||
)
|
||||
|
||||
switch s.Net {
|
||||
case "tcp":
|
||||
if s.Header != nil {
|
||||
if httpHeader, err := s.Header.MarshalJSON(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
header = httpHeader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
101
api/gov2panel/gov2panel_test.go
Normal file
101
api/gov2panel/gov2panel_test.go
Normal file
@ -0,0 +1,101 @@
|
||||
package gov2panel_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/XrayR-project/XrayR/api"
|
||||
"github.com/XrayR-project/XrayR/api/gov2panel"
|
||||
)
|
||||
|
||||
func CreateClient() api.API {
|
||||
apiConfig := &api.Config{
|
||||
APIHost: "http://localhost:8080",
|
||||
Key: "123456",
|
||||
NodeID: 1,
|
||||
NodeType: "V2ray",
|
||||
}
|
||||
client := gov2panel.New(apiConfig)
|
||||
return client
|
||||
}
|
||||
|
||||
func TestGetV2rayNodeInfo(t *testing.T) {
|
||||
client := CreateClient()
|
||||
nodeInfo, err := client.GetNodeInfo()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(nodeInfo)
|
||||
}
|
||||
|
||||
func TestGetSSNodeInfo(t *testing.T) {
|
||||
apiConfig := &api.Config{
|
||||
APIHost: "http://127.0.0.1:668",
|
||||
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) {
|
||||
client := CreateClient()
|
||||
|
||||
userList, err := client.GetUserList()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Log(userList)
|
||||
}
|
||||
|
||||
func TestReportReportUserTraffic(t *testing.T) {
|
||||
client := CreateClient()
|
||||
userList, err := client.GetUserList()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
generalUserTraffic := make([]api.UserTraffic, len(*userList))
|
||||
for i, userInfo := range *userList {
|
||||
generalUserTraffic[i] = api.UserTraffic{
|
||||
UID: userInfo.UID,
|
||||
Upload: 1111,
|
||||
Download: 2222,
|
||||
}
|
||||
}
|
||||
// client.Debug()
|
||||
err = client.ReportUserTraffic(&generalUserTraffic)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNodeRule(t *testing.T) {
|
||||
client := CreateClient()
|
||||
client.Debug()
|
||||
ruleList, err := client.GetNodeRule()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Log(ruleList)
|
||||
}
|
46
api/gov2panel/model.go
Normal file
46
api/gov2panel/model.go
Normal file
@ -0,0 +1,46 @@
|
||||
package gov2panel
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type serverConfig struct {
|
||||
v2ray
|
||||
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 {
|
||||
Id int `json:"id"`
|
||||
Match []string `json:"match"`
|
||||
Action string `json:"action"`
|
||||
ActionValue string `json:"action_value"`
|
||||
}
|
||||
|
||||
type user struct {
|
||||
Id int `json:"id"`
|
||||
Uuid string `json:"uuid"`
|
||||
SpeedLimit int `json:"speed_limit"`
|
||||
}
|
3
go.mod
3
go.mod
@ -14,6 +14,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-acme/lego/v4 v4.14.2
|
||||
github.com/go-resty/resty/v2 v2.9.1
|
||||
github.com/gogf/gf/v2 v2.5.4
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/r3labs/diff/v2 v2.15.1
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
@ -202,6 +203,8 @@ require (
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/ratelimit v0.2.0 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -298,6 +298,8 @@ github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVr
|
||||
github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogf/gf/v2 v2.5.4 h1:UBCSw8mInkHmEqL0E1LYc6QhSpaNFY/wHcFrTI/rzTk=
|
||||
github.com/gogf/gf/v2 v2.5.4/go.mod h1:7yf5qp0BznfsYx7Sw49m3mQvBsHpwAjJk3Q9ZnKoUEc=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
@ -911,6 +913,10 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
|
@ -13,7 +13,7 @@ ConnectionConfig:
|
||||
DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
|
||||
BufferSize: 64 # The internal cache size of each connection, kB
|
||||
Nodes:
|
||||
- PanelType: "SSpanel" # Panel type: SSpanel, NewV2board, PMpanel, Proxypanel, V2RaySocks
|
||||
- PanelType: "SSpanel" # Panel type: SSpanel, NewV2board, PMpanel, Proxypanel, V2RaySocks, GoV2Panel
|
||||
ApiConfig:
|
||||
ApiHost: "http://127.0.0.1:667"
|
||||
ApiKey: "123"
|
||||
@ -78,7 +78,7 @@ Nodes:
|
||||
ALICLOUD_ACCESS_KEY: aaa
|
||||
ALICLOUD_SECRET_KEY: bbb
|
||||
|
||||
# - PanelType: "SSpanel" # Panel type: SSpanel, V2board, NewV2board, PMpanel, Proxypanel, V2RaySocks
|
||||
# - PanelType: "SSpanel" # Panel type: SSpanel, V2board, NewV2board, PMpanel, Proxypanel, V2RaySocks, GoV2Panel
|
||||
# ApiConfig:
|
||||
# ApiHost: "http://127.0.0.1:668"
|
||||
# ApiKey: "123"
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/XrayR-project/XrayR/api/gov2panel"
|
||||
"github.com/XrayR-project/XrayR/api/newV2board"
|
||||
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
||||
|
||||
@ -184,6 +185,8 @@ func (p *Panel) Start() {
|
||||
apiClient = proxypanel.New(nodeConfig.ApiConfig)
|
||||
case "V2RaySocks":
|
||||
apiClient = v2raysocks.New(nodeConfig.ApiConfig)
|
||||
case "GoV2Panel":
|
||||
apiClient = gov2panel.New(nodeConfig.ApiConfig)
|
||||
default:
|
||||
log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user