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.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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(0)
  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. if p.Header != nil {
  43. req.Header = p.Header
  44. }
  45. return req, nil
  46. }
  47. func (p *RequestParam) Do(baseURL string, cli *http.Client) (*http.Response, error) {
  48. req, err := p.MakeRequest(baseURL)
  49. if err != nil {
  50. return nil, err
  51. }
  52. return cli.Do(req)
  53. }
  54. func joinUrlUnsafe(base string, path string) string {
  55. if strings.HasSuffix(base, "/") {
  56. if strings.HasPrefix(path, "/") {
  57. return base + path[1:]
  58. }
  59. return base + path
  60. }
  61. if strings.HasPrefix(path, "/") {
  62. return base + path
  63. }
  64. return base + "/" + path
  65. }
  66. type RequestBody interface {
  67. // 请求体长度,如果长度未知,返回-1
  68. Length() int64
  69. // 将内部值变成一个流,用于发送请求
  70. IntoStream() io.ReadCloser
  71. }
  72. type StringBody struct {
  73. Value string
  74. }
  75. func (s *StringBody) Length() int64 {
  76. return int64(len(s.Value))
  77. }
  78. func (s *StringBody) IntoStream() io.ReadCloser {
  79. return io.NopCloser(bytes.NewReader([]byte(s.Value)))
  80. }
  81. type BytesBody struct {
  82. Value []byte
  83. }
  84. func (b *BytesBody) Length() int64 {
  85. return int64(len(b.Value))
  86. }
  87. func (b *BytesBody) IntoStream() io.ReadCloser {
  88. return io.NopCloser(bytes.NewReader(b.Value))
  89. }
  90. type StreamBody struct {
  91. Stream io.ReadCloser
  92. LengthHint int64 // 长度提示,如果长度未知,可以设置为-1
  93. }
  94. func (s *StreamBody) Length() int64 {
  95. return s.LengthHint
  96. }
  97. func (s *StreamBody) IntoStream() io.ReadCloser {
  98. return s.Stream
  99. }
  100. type APIRequest interface {
  101. MakeParam() *RequestParam
  102. }
  103. func MakeJSONParam(method string, path string, body any) *RequestParam {
  104. data, err := serder.ObjectToJSONEx(body)
  105. if err != nil {
  106. // 开发人员应该保证param是可序列化的
  107. panic(err)
  108. }
  109. return &RequestParam{
  110. Method: method,
  111. Path: path,
  112. Body: &BytesBody{Value: data},
  113. }
  114. }
  115. func MakeQueryParam(method string, path string, q any) *RequestParam {
  116. values, err := query.Values(q)
  117. if err != nil {
  118. // 开发人员应该保证param是可序列化的
  119. panic(err)
  120. }
  121. return &RequestParam{
  122. Method: method,
  123. Path: path,
  124. Query: values,
  125. }
  126. }
  127. type APIResponse interface {
  128. ParseResponse(resp *http.Response) error
  129. }
  130. type CodeDataResponse[T any] struct {
  131. Code string `json:"code"`
  132. Message string `json:"message"`
  133. Data T `json:"data"`
  134. }
  135. func (r *CodeDataResponse[T]) Unwarp() (T, error) {
  136. if r.Code == errorcode.OK {
  137. return r.Data, nil
  138. }
  139. var def T
  140. return def, &CodeMessageError{Code: r.Code, Message: r.Message}
  141. }
  142. func ParseCodeDataJSONResponse[T any](resp *http.Response, ret T) error {
  143. contType := resp.Header.Get("Content-Type")
  144. if strings.Contains(contType, http2.ContentTypeJSON) {
  145. var err error
  146. var r CodeDataResponse[T]
  147. r.Data = ret
  148. if err = serder.JSONToObjectStreamExRaw(resp.Body, &r); err != nil {
  149. return fmt.Errorf("parsing response: %w", err)
  150. }
  151. if r.Code != errorcode.OK {
  152. return &CodeMessageError{Code: r.Code, Message: r.Message}
  153. }
  154. return nil
  155. }
  156. cont, err := io2.ReadMost(resp.Body, 200)
  157. if err != nil {
  158. return fmt.Errorf("unknow response content type: %s, status: %d", contType, resp.StatusCode)
  159. }
  160. strCont := string(cont)
  161. return fmt.Errorf("unknow response content type: %s, status: %d, body[:200]: %s", contType, resp.StatusCode, strCont)
  162. }