diff --git a/go.mod b/go.mod index 689898c..6797669 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 822f06a..50cc9f1 100644 --- a/go.sum +++ b/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= diff --git a/src/x3-client/client.go b/pkg/x3-client/client.go similarity index 73% rename from src/x3-client/client.go rename to pkg/x3-client/client.go index c13bf66..b4bf5c0 100644 --- a/src/x3-client/client.go +++ b/pkg/x3-client/client.go @@ -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, diff --git a/src/x3-client/http.go b/pkg/x3-client/http.go similarity index 60% rename from src/x3-client/http.go rename to pkg/x3-client/http.go index d440ef0..76e4b5a 100644 --- a/src/x3-client/http.go +++ b/pkg/x3-client/http.go @@ -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) } diff --git a/src/x3-client/models.go b/pkg/x3-client/models.go similarity index 79% rename from src/x3-client/models.go rename to pkg/x3-client/models.go index 989a3c0..1d2a10a 100644 --- a/src/x3-client/models.go +++ b/pkg/x3-client/models.go @@ -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"` } diff --git a/src/panels/3x/api.go b/src/panels/3x/api.go deleted file mode 100644 index a3a83c0..0000000 --- a/src/panels/3x/api.go +++ /dev/null @@ -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 -}