3x client
This commit is contained in:
parent
45762d8483
commit
89a13f4edb
6 changed files with 50 additions and 212 deletions
1
go.mod
1
go.mod
|
@ -6,7 +6,6 @@ require (
|
|||
connectrpc.com/authn v0.2.0
|
||||
connectrpc.com/connect v1.17.0
|
||||
github.com/bufbuild/buf v1.45.0
|
||||
github.com/carlmjohnson/requests v0.24.2
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/knadh/koanf/providers/env v1.0.0
|
||||
github.com/knadh/koanf/v2 v2.1.1
|
||||
|
|
2
go.sum
2
go.sum
|
@ -40,8 +40,6 @@ github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a h1:l3RhVoG0Rt
|
|||
github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ=
|
||||
github.com/bufbuild/protovalidate-go v0.7.2 h1:UuvKyZHl5p7u3ztEjtRtqtDxOjRKX5VUOgKFq6p6ETk=
|
||||
github.com/bufbuild/protovalidate-go v0.7.2/go.mod h1:PHV5pFuWlRzdDW02/cmVyNzdiQ+RNNwo7idGxdzS7o4=
|
||||
github.com/carlmjohnson/requests v0.24.2 h1:JDakhAmTIKL/qL/1P7Kkc2INGBJIkIFP6xUeUmPzLso=
|
||||
github.com/carlmjohnson/requests v0.24.2/go.mod h1:duYA/jDnyZ6f3xbcF5PpZ9N8clgopubP2nK5i6MVMhU=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
|
|
@ -6,19 +6,19 @@ import (
|
|||
)
|
||||
|
||||
type X3Client struct {
|
||||
Host string
|
||||
basePath string
|
||||
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func NewX3Client(host, port string) (*X3Client, error) {
|
||||
func NewX3Client(basePath string) (*X3Client, error) {
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &X3Client{
|
||||
Host: host + ":" + port,
|
||||
basePath: basePath,
|
||||
|
||||
httpClient: &http.Client{
|
||||
Jar: jar,
|
|
@ -26,7 +26,7 @@ func makeGetRequest[R any](httpClient *http.Client, url string) (R, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func makePostRequest[Q, R any](httpClient *http.Client, url string, req Q) (R, error) {
|
||||
func makePostRequest[R any](httpClient *http.Client, url string, req any) (R, error) {
|
||||
var res R
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
|
@ -50,114 +50,128 @@ func makePostRequest[Q, R any](httpClient *http.Client, url string, req Q) (R, e
|
|||
const loginURL = "/login"
|
||||
|
||||
func (c *X3Client) Login(request LoginRequest) (GeneralResponse[LoginResponse], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[LoginResponse]](c.httpClient, c.Host+loginURL+fmt.Sprintf("?username=%s&password=%s", request.Username, request.Password), nil)
|
||||
return makePostRequest[GeneralResponse[LoginResponse]](c.httpClient, c.basePath+loginURL+fmt.Sprintf("?username=%s&password=%s", request.Username, request.Password), nil)
|
||||
}
|
||||
|
||||
const inboundsURL = "/panel/api/inbounds/list"
|
||||
|
||||
func (c *X3Client) GetInbounds() (GeneralResponse[[]Inbound], error) {
|
||||
return makeGetRequest[GeneralResponse[[]Inbound]](c.httpClient, c.Host+inboundsURL)
|
||||
return makeGetRequest[GeneralResponse[[]Inbound]](c.httpClient, c.basePath+inboundsURL)
|
||||
}
|
||||
|
||||
const inboundURL = "/panel/api/inbounds/get/%d"
|
||||
|
||||
func (c *X3Client) GetInbound(inboundId int) (GeneralResponse[Inbound], error) {
|
||||
return makeGetRequest[GeneralResponse[Inbound]](c.httpClient, c.Host+fmt.Sprintf(inboundURL, inboundId))
|
||||
return makeGetRequest[GeneralResponse[Inbound]](c.httpClient, c.basePath+fmt.Sprintf(inboundURL, inboundId))
|
||||
}
|
||||
|
||||
const inboundClientTrafficURL = "/panel/api/inbounds/getClientTraffics/%s"
|
||||
|
||||
func (c *X3Client) GetInboundClientTraffic(email string) (GeneralResponse[ClientStats], error) {
|
||||
return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.Host+fmt.Sprintf(inboundClientTrafficURL, email))
|
||||
return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.basePath+fmt.Sprintf(inboundClientTrafficURL, email))
|
||||
}
|
||||
|
||||
const inboundClientTrafficByIdURL = "/panel/api/inbounds/getClientTrafficsById/%s"
|
||||
|
||||
func (c *X3Client) GetInboundClientTrafficById(uuid string) (GeneralResponse[ClientStats], error) {
|
||||
return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.Host+fmt.Sprintf(inboundClientTrafficByIdURL, uuid))
|
||||
return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.basePath+fmt.Sprintf(inboundClientTrafficByIdURL, uuid))
|
||||
}
|
||||
|
||||
const inboundCreateBackupURL = "/panel/api/inbounds/createbackup"
|
||||
|
||||
func (c *X3Client) CreateInboundBackup() (GeneralResponse[interface{}], error) {
|
||||
return makeGetRequest[GeneralResponse[interface{}]](c.httpClient, c.Host+inboundCreateBackupURL)
|
||||
return makeGetRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+inboundCreateBackupURL)
|
||||
}
|
||||
|
||||
const clientIpsURL = "/panel/api/inbounds/clientIps/%s"
|
||||
|
||||
func (c *X3Client) GetClientIps(email string) (GeneralResponse[string], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[string]](c.httpClient, c.Host+fmt.Sprintf(clientIpsURL, email), nil)
|
||||
return makePostRequest[GeneralResponse[string]](c.httpClient, c.basePath+fmt.Sprintf(clientIpsURL, email), nil)
|
||||
}
|
||||
|
||||
const addInboundURL = "/panel/api/inbounds/add"
|
||||
|
||||
func (c *X3Client) AddInbound(inbound Inbound) (GeneralResponse[Inbound], error) {
|
||||
return makePostRequest[Inbound, GeneralResponse[Inbound]](c.httpClient, c.Host+addInboundURL, inbound)
|
||||
return makePostRequest[GeneralResponse[Inbound]](c.httpClient, c.basePath+addInboundURL, inbound)
|
||||
}
|
||||
|
||||
const addClientToInboundURL = "/panel/api/inbounds/addClient"
|
||||
|
||||
func (c *X3Client) AddClientToInbound(client CreateClient) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[CreateClient, GeneralResponse[interface{}]](c.httpClient, c.Host+addClientToInboundURL, client)
|
||||
type createClient struct {
|
||||
Id int `json:"id"`
|
||||
Settings json.RawMessage `json:"settings"`
|
||||
}
|
||||
|
||||
func (c *X3Client) AddClientToInbound(inboundID int, client []Client) (GeneralResponse[interface{}], error) {
|
||||
req := createClient{
|
||||
Id: inboundID,
|
||||
}
|
||||
var err error
|
||||
req.Settings, err = json.Marshal(struct{ client []Client }{client: client})
|
||||
if err != nil {
|
||||
return GeneralResponse[interface{}]{}, err
|
||||
}
|
||||
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+addClientToInboundURL, req)
|
||||
}
|
||||
|
||||
const updateInboundURL = "/panel/api/inbounds/update/%d"
|
||||
|
||||
func (c *X3Client) UpdateInbound(inbound Inbound) (GeneralResponse[Inbound], error) {
|
||||
return makePostRequest[Inbound, GeneralResponse[Inbound]](c.httpClient, c.Host+fmt.Sprintf(updateInboundURL, inbound.Id), inbound)
|
||||
return makePostRequest[GeneralResponse[Inbound]](c.httpClient, c.basePath+fmt.Sprintf(updateInboundURL, inbound.Id), inbound)
|
||||
}
|
||||
|
||||
// TODO: Check if client id is int not an uuid
|
||||
const updateClientInboundURL = "/panel/api/inbounds/updateClient/%d"
|
||||
|
||||
func (c *X3Client) UpdateClientInbound(client CreateClient) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[CreateClient, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(updateClientInboundURL, client.Id), client)
|
||||
func (c *X3Client) UpdateClientInbound(client createClient) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(updateClientInboundURL, client.Id), client)
|
||||
}
|
||||
|
||||
const clearClientIpsURL = "/panel/api/inbounds/clearClientIps/%s"
|
||||
|
||||
func (c *X3Client) ClearClientIps(email string) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(clearClientIpsURL, email), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(clearClientIpsURL, email), nil)
|
||||
}
|
||||
|
||||
const resetAllTrafficURL = "/panel/api/inbounds/resetAllTraffics"
|
||||
|
||||
func (c *X3Client) ResetAllTraffic() (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+resetAllTrafficURL, nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+resetAllTrafficURL, nil)
|
||||
}
|
||||
|
||||
const resetAllClientTrafficByInboundURL = "/panel/api/inbounds/resetAllClientTraffics/%d"
|
||||
|
||||
func (c *X3Client) ResetAllClientTrafficByInbound(inboundId int) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(resetAllClientTrafficByInboundURL, inboundId), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(resetAllClientTrafficByInboundURL, inboundId), nil)
|
||||
}
|
||||
|
||||
const resetClientTrafficURL = "/panel/api/inbounds/%d/resetClientTraffic/%s"
|
||||
|
||||
func (c *X3Client) ResetClientTraffic(inboundId int, email string) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(resetClientTrafficURL, inboundId, email), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(resetClientTrafficURL, inboundId, email), nil)
|
||||
}
|
||||
|
||||
const deleteClientURL = "/panel/api/inbounds/%d/delClient/%s"
|
||||
|
||||
func (c *X3Client) DeleteClient(inboundId int, uuid string) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteClientURL, inboundId, uuid), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(deleteClientURL, inboundId, uuid), nil)
|
||||
}
|
||||
|
||||
const deleteInboundURL = "/panel/api/inbounds/del/%d"
|
||||
|
||||
func (c *X3Client) DeleteInbound(inboundId int) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteInboundURL, inboundId), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(deleteInboundURL, inboundId), nil)
|
||||
}
|
||||
|
||||
const deleteDepletedClientsURL = "/panel/api/inbounds/delDepletedClients/%d"
|
||||
|
||||
func (c *X3Client) DeleteDepletedClients(inboundId int) (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteDepletedClientsURL, inboundId), nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+fmt.Sprintf(deleteDepletedClientsURL, inboundId), nil)
|
||||
}
|
||||
|
||||
const onlineClientsURL = "/panel/api/inbounds/onlines"
|
||||
|
||||
func (c *X3Client) GetOnlineClients() (GeneralResponse[interface{}], error) {
|
||||
return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+onlineClientsURL, nil)
|
||||
return makePostRequest[GeneralResponse[interface{}]](c.httpClient, c.basePath+onlineClientsURL, nil)
|
||||
}
|
|
@ -45,7 +45,15 @@ type ClientStats struct {
|
|||
Reset int `json:"reset"`
|
||||
}
|
||||
|
||||
type CreateClient struct {
|
||||
Id int `json:"id"`
|
||||
Settings string `json:"settings"`
|
||||
type Client struct {
|
||||
ID string `json:"id"`
|
||||
Flow string `json:"flow"`
|
||||
Email string `json:"email"`
|
||||
LimitIP int64 `json:"limitIp"`
|
||||
TotalGB int64 `json:"totalGB"`
|
||||
ExpiryTime int64 `json:"expiryTime"`
|
||||
Enable bool `json:"enable"`
|
||||
TgID string `json:"tgId"`
|
||||
SubID string `json:"subId"`
|
||||
Reset int64 `json:"reset"`
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
package tresx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
|
||||
"github.com/carlmjohnson/requests"
|
||||
)
|
||||
|
||||
type XUIPriovider struct {
|
||||
baseUrl string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewTresXProvider(basePath string) *XUIPriovider {
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &XUIPriovider{
|
||||
baseUrl: basePath,
|
||||
client: &http.Client{
|
||||
Jar: jar,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type basicResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"msg"`
|
||||
Object json.RawMessage `json:"obj"`
|
||||
}
|
||||
|
||||
func (t *XUIPriovider) Login(login, password string) error {
|
||||
params := url.Values{}
|
||||
params.Add("username", login)
|
||||
params.Add("password", password)
|
||||
|
||||
url := fmt.Sprintf("%s/login?%s", t.baseUrl, params.Encode())
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := t.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var resp basicResponse
|
||||
err = json.Unmarshal(body, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return fmt.Errorf("login failed: %s", resp.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Inbound struct {
|
||||
ID int64 `json:"id"`
|
||||
Up int64 `json:"up"`
|
||||
Down int64 `json:"down"`
|
||||
Total int64 `json:"total"`
|
||||
Remark string `json:"remark"`
|
||||
Enable bool `json:"enable"`
|
||||
ExpiryTime int64 `json:"expiryTime"`
|
||||
ClientStats []ClientStat `json:"clientStats"`
|
||||
Listen string `json:"listen"`
|
||||
Port int64 `json:"port"`
|
||||
Protocol string `json:"protocol"`
|
||||
Settings string `json:"settings"`
|
||||
StreamSettings string `json:"streamSettings"`
|
||||
Tag string `json:"tag"`
|
||||
Sniffing string `json:"sniffing"`
|
||||
Allocate string `json:"allocate"`
|
||||
}
|
||||
|
||||
type ClientStat struct {
|
||||
ID int64 `json:"id"`
|
||||
InboundID int64 `json:"inboundId"`
|
||||
Enable bool `json:"enable"`
|
||||
Email string `json:"email"`
|
||||
Up int64 `json:"up"`
|
||||
Down int64 `json:"down"`
|
||||
ExpiryTime int64 `json:"expiryTime"`
|
||||
Total int64 `json:"total"`
|
||||
Reset int64 `json:"reset"`
|
||||
}
|
||||
|
||||
func (t *XUIPriovider) Inbounds(ctx context.Context) error {
|
||||
var resp basicResponse
|
||||
err := requests.
|
||||
URL(t.baseUrl).
|
||||
Path("panel/api/inbounds/list").
|
||||
Client(t.client).
|
||||
ToJSON(&resp).
|
||||
Fetch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return fmt.Errorf("logout failed: %s", resp.Message)
|
||||
}
|
||||
|
||||
var inbounds []Inbound
|
||||
err = json.Unmarshal(resp.Object, &inbounds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type addClientRequest struct {
|
||||
ID int `json:"id"`
|
||||
Settings json.RawMessage `json:"settings"`
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
ID string `json:"id"`
|
||||
Flow string `json:"flow"`
|
||||
Email string `json:"email"`
|
||||
LimitIP int64 `json:"limitIp"`
|
||||
TotalGB int64 `json:"totalGB"`
|
||||
ExpiryTime int64 `json:"expiryTime"`
|
||||
Enable bool `json:"enable"`
|
||||
TgID string `json:"tgId"`
|
||||
SubID string `json:"subId"`
|
||||
Reset int64 `json:"reset"`
|
||||
}
|
||||
|
||||
func (t *XUIPriovider) AddClientToInbound(ctx context.Context, inboundID int, clients []Client) error {
|
||||
addReq := addClientRequest{
|
||||
ID: inboundID,
|
||||
}
|
||||
|
||||
settings := struct {
|
||||
Clients []Client `json:"clients"`
|
||||
}{
|
||||
Clients: clients,
|
||||
}
|
||||
var err error
|
||||
addReq.Settings, err = json.Marshal(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var resp basicResponse
|
||||
err = requests.
|
||||
URL(t.baseUrl).
|
||||
Path("panel/api/inbounds/addClient").
|
||||
Post().
|
||||
BodyJSON(addReq).
|
||||
Client(t.client).
|
||||
ToJSON(&resp).
|
||||
Fetch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return fmt.Errorf("logout failed: %s", resp.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue