|
|
|
@@ -4,6 +4,8 @@ import ( |
|
|
|
"bytes" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"mime" |
|
|
|
"mime/multipart" |
|
|
|
"net/http" |
|
|
|
"net/url" |
|
|
|
"strings" |
|
|
|
@@ -155,6 +157,50 @@ func MakeQueryParam(method string, path string, q any) *RequestParam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func MakeMultipartParam(method string, path string, info any, stream io.ReadCloser) *RequestParam { |
|
|
|
data, err := serder.ObjectToJSONEx(info) |
|
|
|
if err != nil { |
|
|
|
// 开发人员应该保证param是可序列化的 |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
|
|
|
|
pr, pw := io.Pipe() |
|
|
|
mw := multipart.NewWriter(pw) |
|
|
|
go func() { |
|
|
|
defer mw.Close() |
|
|
|
err := mw.WriteField("info", string(data)) |
|
|
|
if err != nil { |
|
|
|
pw.CloseWithError(err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
fw, err := mw.CreateFormFile("file", "file") |
|
|
|
if err != nil { |
|
|
|
pw.CloseWithError(err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
_, err = io.Copy(fw, stream) |
|
|
|
if err != nil { |
|
|
|
pw.CloseWithError(err) |
|
|
|
return |
|
|
|
} |
|
|
|
}() |
|
|
|
|
|
|
|
headers := http.Header{} |
|
|
|
headers.Set("Content-Type", fmt.Sprintf("%s;boundary=%s", http2.ContentTypeMultiPart, mw.Boundary())) |
|
|
|
|
|
|
|
return &RequestParam{ |
|
|
|
Method: method, |
|
|
|
Path: path, |
|
|
|
Header: headers, |
|
|
|
Body: &StreamBody{ |
|
|
|
Stream: pr, |
|
|
|
LengthHint: -1, |
|
|
|
}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type APIResponse interface { |
|
|
|
ParseResponse(resp *http.Response) error |
|
|
|
} |
|
|
|
@@ -200,6 +246,27 @@ func ParseCodeDataJSONResponse[T any](resp *http.Response, ret T) error { |
|
|
|
return fmt.Errorf("unknow response content type: %s, status: %d, body[:200]: %s", contType, resp.StatusCode, strCont) |
|
|
|
} |
|
|
|
|
|
|
|
func ParseFileResponse(resp *http.Response) (string, io.ReadCloser, error) { |
|
|
|
contType := resp.Header.Get("Content-Type") |
|
|
|
if strings.Contains(contType, http2.ContentTypeJSON) { |
|
|
|
var err error |
|
|
|
var r CodeDataResponse[any] |
|
|
|
|
|
|
|
if err = serder.JSONToObjectStreamExRaw(resp.Body, &r); err != nil { |
|
|
|
return "", nil, fmt.Errorf("parsing response: %w", err) |
|
|
|
} |
|
|
|
|
|
|
|
return "", nil, &CodeMessageError{Code: r.Code, Message: r.Message} |
|
|
|
} |
|
|
|
|
|
|
|
_, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition")) |
|
|
|
if err != nil { |
|
|
|
return "", nil, fmt.Errorf("parsing content disposition: %w", err) |
|
|
|
} |
|
|
|
|
|
|
|
return params["filename"], resp.Body, nil |
|
|
|
} |
|
|
|
|
|
|
|
func IsErrorCode(err error, code string) bool { |
|
|
|
if e, ok := err.(*CodeMessageError); ok { |
|
|
|
return e.Code == code |
|
|
|
|