184 lines
4.1 KiB
Go
184 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/url"
|
|
ul "net/url"
|
|
"strings"
|
|
|
|
"github.com/google/go-querystring/query"
|
|
"gitlink.org.cn/cloudream/common/pkgs/iterator"
|
|
"gitlink.org.cn/cloudream/common/sdks"
|
|
"gitlink.org.cn/cloudream/common/utils/http2"
|
|
"gitlink.org.cn/cloudream/common/utils/math2"
|
|
"gitlink.org.cn/cloudream/common/utils/serder"
|
|
"gitlink.org.cn/cloudream/jcs-pub/client/sdk/api"
|
|
)
|
|
|
|
func ParseJSONResponse[TBody any](resp *http.Response) (TBody, error) {
|
|
var ret TBody
|
|
contType := resp.Header.Get("Content-Type")
|
|
if strings.Contains(contType, http2.ContentTypeJSON) {
|
|
var err error
|
|
if ret, err = serder.JSONToObjectStreamEx[TBody](resp.Body); err != nil {
|
|
return ret, fmt.Errorf("parsing response: %w", err)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
cont, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return ret, fmt.Errorf("unknow response content type: %s, status: %d", contType, resp.StatusCode)
|
|
}
|
|
strCont := string(cont)
|
|
|
|
return ret, fmt.Errorf("unknow response content type: %s, status: %d, body(prefix): %s", contType, resp.StatusCode, strCont[:math2.Min(len(strCont), 200)])
|
|
}
|
|
|
|
func JSONAPI[Resp sdks.APIResponse, Req sdks.APIRequest](cfg *api.Config, cli *http.Client, req Req, resp Resp) (Resp, error) {
|
|
|
|
param := req.MakeParam()
|
|
|
|
v1EndPoint, err := url.JoinPath(cfg.EndPoint, "v1")
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
httpReq, err := param.MakeRequest(v1EndPoint)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
httpResp, err := cli.Do(httpReq)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
err = resp.ParseResponse(httpResp)
|
|
return resp, err
|
|
}
|
|
|
|
func JSONAPINoData[Req sdks.APIRequest](cfg *api.Config, cli *http.Client, req Req) error {
|
|
param := req.MakeParam()
|
|
|
|
v1EndPoint, err := url.JoinPath(cfg.EndPoint, "v1")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
httpReq, err := param.MakeRequest(v1EndPoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resp, err := cli.Do(httpReq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return sdks.ParseCodeDataJSONResponse(resp, any(nil))
|
|
}
|
|
|
|
func calcSha256(body sdks.RequestBody) string {
|
|
hasher := sha256.New()
|
|
switch body := body.(type) {
|
|
case *sdks.StringBody:
|
|
hasher.Write([]byte(body.Value))
|
|
return hex.EncodeToString(hasher.Sum(nil))
|
|
|
|
case *sdks.BytesBody:
|
|
hasher.Write(body.Value)
|
|
return hex.EncodeToString(hasher.Sum(nil))
|
|
|
|
case *sdks.StreamBody:
|
|
return ""
|
|
|
|
default:
|
|
hash := sha256.Sum256([]byte(""))
|
|
return hex.EncodeToString(hash[:])
|
|
}
|
|
}
|
|
|
|
func PostMultiPart(cfg *api.Config, url string, info any, files http2.MultiPartFileIterator) (*http.Response, error) {
|
|
req, err := http.NewRequest(http.MethodPost, url, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pr, pw := io.Pipe()
|
|
muWriter := multipart.NewWriter(pw)
|
|
|
|
req.Header.Set("Content-Type", fmt.Sprintf("%s;boundary=%s", http2.ContentTypeMultiPart, muWriter.Boundary()))
|
|
|
|
writeResult := make(chan error, 1)
|
|
go func() {
|
|
writeResult <- func() error {
|
|
defer pw.Close()
|
|
defer muWriter.Close()
|
|
|
|
if info != nil {
|
|
mp, err := query.Values(info)
|
|
if err != nil {
|
|
return fmt.Errorf("formValues object to map failed, err: %w", err)
|
|
}
|
|
|
|
for k, v := range mp {
|
|
err := muWriter.WriteField(k, v[0])
|
|
if err != nil {
|
|
return fmt.Errorf("write form field failed, err: %w", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
for {
|
|
file, err := files.MoveNext()
|
|
if err == iterator.ErrNoMoreItem {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("opening file: %w", err)
|
|
}
|
|
|
|
err = sendFileOnePart(muWriter, file.FieldName, file.FileName, file.File)
|
|
file.File.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
}()
|
|
|
|
req.Body = pr
|
|
|
|
cli := http.Client{}
|
|
resp, err := cli.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
writeErr := <-writeResult
|
|
if writeErr != nil {
|
|
return nil, writeErr
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func sendFileOnePart(muWriter *multipart.Writer, fieldName, fileName string, file io.ReadCloser) error {
|
|
w, err := muWriter.CreateFormFile(fieldName, ul.PathEscape(fileName))
|
|
if err != nil {
|
|
return fmt.Errorf("create form file failed, err: %w", err)
|
|
}
|
|
|
|
_, err = io.Copy(w, file)
|
|
return err
|
|
}
|