client.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package webmail
  2. import (
  3. "compress/gzip"
  4. "compress/zlib"
  5. "fmt"
  6. "github.com/mailru/easyjson"
  7. "golang.org/x/net/html/charset"
  8. "io"
  9. "net/http"
  10. "net/url"
  11. "strings"
  12. "time"
  13. )
  14. type client struct {
  15. http *http.Client
  16. endpoint string
  17. }
  18. func NewClient(endpoint string, timeout time.Duration) Client {
  19. t := http.DefaultTransport.(*http.Transport)
  20. t.Proxy = http.ProxyFromEnvironment
  21. cli := &client{
  22. endpoint: endpoint,
  23. http: &http.Client{
  24. Transport: t,
  25. Timeout: timeout,
  26. },
  27. }
  28. return cli
  29. }
  30. func (cli *client) Close() error {
  31. return nil
  32. }
  33. func (cli *client) CreateAlias(alias string) error {
  34. return cli.action(CreateAlias, alias)
  35. }
  36. func (cli *client) RemoveAlias(alias string) error {
  37. return cli.action(RemoveAlias, alias)
  38. }
  39. func (cli *client) action(e Action, alias string) error {
  40. alias = strings.TrimSpace(alias)
  41. if alias == "" {
  42. return fmt.Errorf("illegal arguments: alias must not be an empty string")
  43. }
  44. var (
  45. d []byte
  46. result = new(Result)
  47. err error
  48. )
  49. if d, err = cli.do(e, alias); err != nil {
  50. return err
  51. }
  52. if err = easyjson.Unmarshal(d, result); err != nil {
  53. return err
  54. }
  55. var errNo int64
  56. if errNo, err = result.Error.Int64(); err != nil {
  57. return err
  58. }
  59. if result.Ok != "ok" || errNo > 0 {
  60. return fmt.Errorf("got unexpected result: `%s`", string(d))
  61. }
  62. return nil
  63. }
  64. func (cli *client) ListAliases() ([]string, error) {
  65. var (
  66. d []byte
  67. result = ResultList{}
  68. err error
  69. )
  70. if d, err = cli.do(ListAliases, ""); err != nil {
  71. return nil, err
  72. }
  73. if err = easyjson.Unmarshal(d, &result); err != nil {
  74. return nil, err
  75. }
  76. return result, nil
  77. }
  78. func (cli *client) do(action Action, alias string) ([]byte, error) {
  79. var (
  80. request *http.Request
  81. response *http.Response
  82. err error
  83. )
  84. values := url.Values{}
  85. values.Set("act", string(action))
  86. if ListAliases != action {
  87. values.Set("alias", alias)
  88. }
  89. if request, err = http.NewRequest(http.MethodPost, cli.endpoint, strings.NewReader(values.Encode())); err != nil {
  90. return nil, err
  91. }
  92. request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  93. if response, err = cli.http.Do(request); err != nil {
  94. return nil, err
  95. }
  96. if response.StatusCode < 200 || response.StatusCode > 299 {
  97. return nil, fmt.Errorf("got unexpected http status code [%d] %s",
  98. response.StatusCode, response.Status)
  99. }
  100. if response.ContentLength != -1 && response.ContentLength < 1 {
  101. return nil, nil
  102. }
  103. var (
  104. contentEncoding = response.Header.Get("Content-Encoding")
  105. contentType = response.Header.Get("Content-Type")
  106. contentReader io.Reader = response.Body
  107. )
  108. if "gzip" == contentEncoding {
  109. if r, err := gzip.NewReader(response.Body); err == nil {
  110. defer r.Close()
  111. contentReader = r
  112. }
  113. } else if "deflate" == contentEncoding {
  114. if r, err := zlib.NewReader(response.Body); err == nil {
  115. defer r.Close()
  116. contentReader = r
  117. }
  118. }
  119. if "application/octet-stream" != contentType {
  120. if r, err := charset.NewReader(contentReader, contentType); err == nil {
  121. contentReader = r
  122. } else {
  123. return nil, err
  124. }
  125. }
  126. return io.ReadAll(contentReader)
  127. }