You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

sdks.go 4.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package sdks
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "github.com/google/go-querystring/query"
  10. "gitlink.org.cn/cloudream/common/consts/errorcode"
  11. "gitlink.org.cn/cloudream/common/utils/http2"
  12. "gitlink.org.cn/cloudream/common/utils/io2"
  13. "gitlink.org.cn/cloudream/common/utils/serder"
  14. )
  15. type CodeMessageError struct {
  16. Code string
  17. Message string
  18. }
  19. func (e *CodeMessageError) Error() string {
  20. return fmt.Sprintf("code: %s, message: %s", e.Code, e.Message)
  21. }
  22. type RequestParam struct {
  23. Method string
  24. Path string
  25. Query url.Values
  26. Header http.Header
  27. Body RequestBody
  28. }
  29. func (p *RequestParam) MakeRequest(baseURL string) (*http.Request, error) {
  30. var body io.ReadCloser
  31. bodyLen := int64(-1)
  32. if p.Body != nil {
  33. body = p.Body.IntoStream()
  34. bodyLen = p.Body.Length()
  35. }
  36. req, err := http.NewRequest(p.Method, joinUrlUnsafe(baseURL, p.Path), body)
  37. if err != nil {
  38. return nil, err
  39. }
  40. req.ContentLength = bodyLen
  41. req.URL.RawQuery = p.Query.Encode()
  42. req.Header = p.Header
  43. return req, nil
  44. }
  45. func (p *RequestParam) Do(baseURL string, cli *http.Client) (*http.Response, error) {
  46. req, err := p.MakeRequest(baseURL)
  47. if err != nil {
  48. return nil, err
  49. }
  50. return cli.Do(req)
  51. }
  52. func joinUrlUnsafe(base string, path string) string {
  53. if strings.HasSuffix(base, "/") {
  54. if strings.HasPrefix(path, "/") {
  55. return base + path[1:]
  56. }
  57. return base + path
  58. }
  59. if strings.HasPrefix(path, "/") {
  60. return base + path
  61. }
  62. return base + "/" + path
  63. }
  64. type RequestBody interface {
  65. // 请求体长度,如果长度未知,返回-1
  66. Length() int64
  67. // 将内部值变成一个流,用于发送请求
  68. IntoStream() io.ReadCloser
  69. }
  70. type StringBody struct {
  71. Value string
  72. }
  73. func (s StringBody) Length() int64 {
  74. return int64(len(s.Value))
  75. }
  76. func (s StringBody) IntoStream() io.ReadCloser {
  77. return io.NopCloser(bytes.NewReader([]byte(s.Value)))
  78. }
  79. type BytesBody struct {
  80. Value []byte
  81. }
  82. func (b BytesBody) Length() int64 {
  83. return int64(len(b.Value))
  84. }
  85. func (b BytesBody) IntoStream() io.ReadCloser {
  86. return io.NopCloser(bytes.NewReader(b.Value))
  87. }
  88. type StreamBody struct {
  89. Stream io.ReadCloser
  90. LengthHint int64 // 长度提示,如果长度未知,可以设置为-1
  91. }
  92. func (s StreamBody) Length() int64 {
  93. return s.LengthHint
  94. }
  95. func (s StreamBody) IntoStream() io.ReadCloser {
  96. return s.Stream
  97. }
  98. type APIRequest interface {
  99. MakeParam() *RequestParam
  100. }
  101. func MakeJSONParam(method string, path string, body any) *RequestParam {
  102. data, err := serder.ObjectToJSONEx(body)
  103. if err != nil {
  104. // 开发人员应该保证param是可序列化的
  105. panic(err)
  106. }
  107. return &RequestParam{
  108. Method: method,
  109. Path: path,
  110. Body: BytesBody{Value: data},
  111. }
  112. }
  113. func MakeQueryParam(method string, path string, q any) *RequestParam {
  114. values, err := query.Values(q)
  115. if err != nil {
  116. // 开发人员应该保证param是可序列化的
  117. panic(err)
  118. }
  119. return &RequestParam{
  120. Method: method,
  121. Path: path,
  122. Query: values,
  123. }
  124. }
  125. type APIResponse interface {
  126. ParseResponse(resp *http.Response) error
  127. }
  128. type CodeDataResponse[T any] struct {
  129. Code string `json:"code"`
  130. Message string `json:"message"`
  131. Data T `json:"data"`
  132. }
  133. func (r *CodeDataResponse[T]) Unwarp() (T, error) {
  134. if r.Code == errorcode.OK {
  135. return r.Data, nil
  136. }
  137. var def T
  138. return def, &CodeMessageError{Code: r.Code, Message: r.Message}
  139. }
  140. func ParseCodeDataJSONResponse[T any](resp *http.Response, ret T) error {
  141. contType := resp.Header.Get("Content-Type")
  142. if strings.Contains(contType, http2.ContentTypeJSON) {
  143. var err error
  144. var r CodeDataResponse[T]
  145. if err = serder.JSONToObjectStreamExRaw(resp.Body, &r); err != nil {
  146. return fmt.Errorf("parsing response: %w", err)
  147. }
  148. return nil
  149. }
  150. cont, err := io2.ReadMost(resp.Body, 200)
  151. if err != nil {
  152. return fmt.Errorf("unknow response content type: %s, status: %d", contType, resp.StatusCode)
  153. }
  154. strCont := string(cont)
  155. return fmt.Errorf("unknow response content type: %s, status: %d, body[:200]: %s", contType, resp.StatusCode, strCont)
  156. }