|
- package api
-
- import (
- "crypto/sha256"
- "encoding/hex"
- "fmt"
- "io"
- "mime/multipart"
- "net/http"
- ul "net/url"
- "path/filepath"
- "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"
- )
-
- func MakeIPFSFilePath(fileHash string) string {
- return filepath.Join("ipfs", fileHash)
- }
-
- 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 *Config, cli *http.Client, req Req, resp Resp) (Resp, error) {
-
- param := req.MakeParam()
-
- httpReq, err := param.MakeRequest(cfg.URL)
- 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 *Config, cli *http.Client, req Req) error {
- param := req.MakeParam()
-
- httpReq, err := param.MakeRequest(cfg.URL)
- 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 *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
- }
|