Files
decort-golang-sdk/legacy-client.go

297 lines
7.1 KiB
Go
Raw Normal View History

2023-03-01 19:05:53 +03:00
package decortsdk
import (
2023-09-18 14:13:55 +03:00
"bytes"
2023-03-01 19:05:53 +03:00
"context"
2023-09-18 14:13:55 +03:00
"crypto/tls"
2025-08-29 12:51:25 +03:00
"encoding/json"
2023-09-18 14:13:55 +03:00
"fmt"
2023-03-01 19:05:53 +03:00
"io"
"net/http"
2023-09-18 14:13:55 +03:00
"net/url"
2023-03-01 19:05:53 +03:00
"strings"
2023-09-18 14:13:55 +03:00
"sync"
"time"
2023-03-01 19:05:53 +03:00
"github.com/google/go-querystring/query"
2023-03-17 12:54:34 +03:00
"repository.basistech.ru/BASIS/decort-golang-sdk/config"
2024-03-14 14:52:56 +03:00
"repository.basistech.ru/BASIS/decort-golang-sdk/internal/constants"
2023-03-17 12:54:34 +03:00
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker"
2025-11-14 17:38:59 +03:00
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/sdn"
2023-03-01 19:05:53 +03:00
)
2024-03-14 14:52:56 +03:00
// LegacyDecortClient is Legacy HTTP-client for platform
2023-03-01 19:05:53 +03:00
type LegacyDecortClient struct {
2023-09-18 14:13:55 +03:00
decortURL string
client *http.Client
cfg config.LegacyConfig
expiryTime time.Time
mutex *sync.Mutex
2023-03-01 19:05:53 +03:00
}
// Legacy client builder
func NewLegacy(cfg config.LegacyConfig) *LegacyDecortClient {
if cfg.Retries == 0 {
cfg.Retries = 5
}
2023-09-18 14:13:55 +03:00
var expiryTime time.Time
if cfg.Token != "" {
expiryTime = time.Now().AddDate(0, 0, 1)
}
2023-03-01 19:05:53 +03:00
return &LegacyDecortClient{
decortURL: cfg.DecortURL,
2023-09-18 14:13:55 +03:00
client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: cfg.SSLSkipVerify,
},
},
},
2024-06-28 10:54:20 +03:00
cfg: trimLegacyConfig(&cfg),
2023-09-18 14:13:55 +03:00
expiryTime: expiryTime,
mutex: &sync.Mutex{},
2023-03-01 19:05:53 +03:00
}
}
// CloudAPI builder
func (ldc *LegacyDecortClient) CloudAPI() *cloudapi.CloudAPI {
return cloudapi.New(ldc)
}
// CloudBroker builder
func (ldc *LegacyDecortClient) CloudBroker() *cloudbroker.CloudBroker {
return cloudbroker.New(ldc)
}
2025-11-14 17:38:59 +03:00
// SDN builder
func (ldc *LegacyDecortClient) SDN() *sdn.SDN {
return sdn.New(ldc)
}
2023-03-01 19:05:53 +03:00
// DecortApiCall method for sending requests to the platform
func (ldc *LegacyDecortClient) DecortApiCall(ctx context.Context, method, url string, params interface{}) ([]byte, error) {
2024-03-14 14:52:56 +03:00
// get token
2023-10-25 17:37:18 +03:00
if err := ldc.getToken(ctx); err != nil {
return nil, err
}
2023-09-27 15:06:18 +03:00
2024-05-31 13:35:39 +03:00
var body *bytes.Buffer
var ctype string
byteSlice, ok := params.([]byte)
if ok {
body = bytes.NewBuffer(byteSlice)
ctype = "application/octet-stream"
} else {
values, err := query.Values(params)
if err != nil {
return nil, err
2025-08-29 12:51:25 +03:00
}
body = bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token))
}
req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body)
if err != nil {
return nil, err
}
// perform request
respBytes, err := ldc.do(req, ctype)
if err != nil {
return nil, err
}
return respBytes, err
}
// DecortApiCallCtype method for sending requests to the platform with content type
func (ldc *LegacyDecortClient) DecortApiCallCtype(ctx context.Context, method, url, ctype string, params interface{}) ([]byte, error) {
// get token
if err := ldc.getToken(ctx); err != nil {
return nil, err
}
var body *bytes.Buffer
switch ctype {
case constants.MIMESTREAM:
body = bytes.NewBuffer(params.([]byte))
case constants.MIMEJSON:
jsonBody, err := json.Marshal(params)
if err != nil {
return nil, err
}
body = bytes.NewBuffer(jsonBody)
default:
ctype = constants.MIMEPOSTForm
values, err := query.Values(params)
if err != nil {
return nil, err
2024-05-31 13:35:39 +03:00
}
body = bytes.NewBufferString(values.Encode() + fmt.Sprintf("&authkey=%s", ldc.cfg.Token))
2023-09-18 14:13:55 +03:00
}
2023-11-15 12:03:31 +03:00
2024-04-16 14:26:06 +03:00
req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body)
2023-03-01 19:05:53 +03:00
if err != nil {
return nil, err
}
2023-12-18 16:27:15 +03:00
// perform request
2024-05-31 13:35:39 +03:00
respBytes, err := ldc.do(req, ctype)
2024-03-14 14:52:56 +03:00
if err != nil {
return nil, err
2024-03-06 16:50:27 +03:00
}
2024-03-14 14:52:56 +03:00
return respBytes, err
2024-03-14 10:17:08 +03:00
}
2024-03-14 14:52:56 +03:00
func (ldc *LegacyDecortClient) DecortApiCallMP(ctx context.Context, method, url string, params interface{}) ([]byte, error) {
body, ctype, err := multiPartReq(params)
if err != nil {
return nil, err
2024-03-14 10:17:08 +03:00
}
2024-04-16 14:26:06 +03:00
req, err := http.NewRequestWithContext(ctx, method, ldc.decortURL+constants.RESTMACHINE+url, body)
2023-12-18 16:27:15 +03:00
if err != nil {
return nil, err
2023-03-01 19:05:53 +03:00
}
2024-03-14 14:52:56 +03:00
// get token
if err = ldc.getToken(ctx); err != nil {
2023-12-18 16:27:15 +03:00
return nil, err
}
2024-03-14 14:52:56 +03:00
// perform request
respBytes, err := ldc.do(req, ctype)
2023-12-18 16:27:15 +03:00
if err != nil {
return nil, err
}
2024-03-14 14:52:56 +03:00
return respBytes, err
2023-03-01 19:05:53 +03:00
}
2023-09-18 14:13:55 +03:00
2024-03-14 14:52:56 +03:00
func (ldc *LegacyDecortClient) getToken(ctx context.Context) error {
ldc.mutex.Lock()
defer ldc.mutex.Unlock()
// new token is not needed
if ldc.cfg.Token != "" && !time.Now().After(ldc.expiryTime) {
return nil
2023-09-18 14:13:55 +03:00
}
2024-03-14 14:52:56 +03:00
// set up request headers and body
body := fmt.Sprintf("username=%s&password=%s", url.QueryEscape(ldc.cfg.Username), url.QueryEscape(ldc.cfg.Password))
bodyReader := strings.NewReader(body)
2023-09-18 14:13:55 +03:00
2024-04-16 14:26:06 +03:00
req, _ := http.NewRequestWithContext(ctx, "POST", ldc.cfg.DecortURL+constants.RESTMACHINE+"/cloudapi/user/authenticate", bodyReader)
2024-03-14 14:52:56 +03:00
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
2023-09-18 14:13:55 +03:00
2024-03-14 14:52:56 +03:00
// request token
resp, err := ldc.client.Do(req)
if err != nil || resp == nil {
return fmt.Errorf("cannot get token: %w", err)
2023-11-29 15:57:26 +03:00
}
2024-03-14 14:52:56 +03:00
defer resp.Body.Close()
2023-11-29 15:57:26 +03:00
2024-03-14 14:52:56 +03:00
var tokenBytes []byte
tokenBytes, err = io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("cannot get token: %w", err)
2024-03-14 10:17:08 +03:00
}
2024-03-14 14:52:56 +03:00
if resp.StatusCode != 200 {
return fmt.Errorf("cannot get token: %s", tokenBytes)
2024-03-14 10:17:08 +03:00
}
2024-03-14 14:52:56 +03:00
// save token in config
token := string(tokenBytes)
ldc.cfg.Token = token
ldc.expiryTime = time.Now().AddDate(0, 0, 1)
2024-03-14 10:17:08 +03:00
2024-03-14 14:52:56 +03:00
return nil
2023-10-25 17:37:18 +03:00
}
2024-03-14 14:52:56 +03:00
// do method performs request and returns response as an array of bytes and nil error in case of response status code 200.
// In any other cases do returns nil response and error.
// Retries are implemented in case of connection reset errors.
func (ldc *LegacyDecortClient) do(req *http.Request, ctype string) ([]byte, error) {
// set up request headers and body
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
if ctype != "" {
req.Header.Set("Content-Type", ctype)
2023-10-25 17:37:18 +03:00
}
2024-03-14 14:52:56 +03:00
req.Header.Set("Accept", "application/json")
2023-10-25 17:37:18 +03:00
2024-03-14 14:52:56 +03:00
buf, err := io.ReadAll(req.Body)
if err != nil {
return nil, err
2023-10-25 17:37:18 +03:00
}
2024-03-14 14:52:56 +03:00
req.Body.Close()
req.Body = io.NopCloser(bytes.NewBuffer(buf))
2023-10-25 17:37:18 +03:00
2024-03-14 14:52:56 +03:00
resp, err := ldc.client.Do(req)
if resp != nil {
defer resp.Body.Close()
}
// retries logic GOES HERE
// get http response
//var resp *http.Response
//for i := uint64(0); i < ldc.cfg.Retries; i++ {
// req := req.Clone(req.Context())
// req.Body = io.NopCloser(bytes.NewBuffer(buf))
//
// if i > 0 {
// time.Sleep(5 * time.Second) // no time sleep for the first request
// }
//
// resp, err = ldc.client.Do(req)
//
// // stop retries on success and close response body
// if resp != nil {
// defer resp.Body.Close()
// }
// if err == nil {
// break
// }
//
// // retries in case of connection errors with time sleep
// if isConnectionError(err) {
// continue
// }
//
// // return error in case of non-connection error
// return nil, err
//}
// handle http request errors
if err != nil {
return nil, err
2024-03-14 10:17:08 +03:00
}
2024-03-14 14:52:56 +03:00
if resp == nil {
return nil, fmt.Errorf("got empty response without error")
2023-10-25 17:37:18 +03:00
}
2024-03-14 14:52:56 +03:00
// handle successful request
respBytes, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
return respBytes, nil
2023-10-25 17:37:18 +03:00
}
2024-03-14 14:52:56 +03:00
// handle errors with status code other than 200
err = fmt.Errorf("%s", respBytes)
return nil, fmt.Errorf("could not execute request: %w", err)
2023-09-27 15:06:18 +03:00
}
2024-06-28 10:54:20 +03:00
func trimLegacyConfig(cfg *config.LegacyConfig) config.LegacyConfig {
cfg.DecortURL = strings.TrimSuffix(cfg.DecortURL, "/")
return *cfg
}