webhook.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package webhook
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io"
  6. "net/http"
  7. "time"
  8. "github.com/pkg/errors"
  9. )
  10. var (
  11. // timeout is the timeout for webhook request. Default to 30 seconds.
  12. timeout = 30 * time.Second
  13. )
  14. type Memo struct {
  15. // The name of the memo.
  16. // Format: memos/{id}
  17. // id is the system generated id.
  18. Name string
  19. // The name of the creator.
  20. // Format: users/{id}
  21. Creator string
  22. // The raw content.
  23. Content string
  24. }
  25. // WebhookPayload is the payload of webhook request.
  26. // nolint
  27. type WebhookPayload struct {
  28. URL string `json:"url"`
  29. ActivityType string `json:"activityType"`
  30. CreatorID int32 `json:"creatorId"`
  31. CreatedTs int64 `json:"createdTs"`
  32. Memo *Memo `json:"memo"`
  33. }
  34. // WebhookResponse is the response of webhook request.
  35. // nolint
  36. type WebhookResponse struct {
  37. Code int `json:"code"`
  38. Message string `json:"message"`
  39. }
  40. // Post posts the message to webhook endpoint.
  41. func Post(payload WebhookPayload) error {
  42. body, err := json.Marshal(&payload)
  43. if err != nil {
  44. return errors.Wrapf(err, "failed to marshal webhook request to %s", payload.URL)
  45. }
  46. req, err := http.NewRequest("POST", payload.URL, bytes.NewBuffer(body))
  47. if err != nil {
  48. return errors.Wrapf(err, "failed to construct webhook request to %s", payload.URL)
  49. }
  50. req.Header.Set("Content-Type", "application/json")
  51. client := &http.Client{
  52. Timeout: timeout,
  53. }
  54. resp, err := client.Do(req)
  55. if err != nil {
  56. return errors.Wrapf(err, "failed to post webhook to %s", payload.URL)
  57. }
  58. b, err := io.ReadAll(resp.Body)
  59. if err != nil {
  60. return errors.Wrapf(err, "failed to read webhook response from %s", payload.URL)
  61. }
  62. defer resp.Body.Close()
  63. if resp.StatusCode < 200 || resp.StatusCode > 299 {
  64. return errors.Errorf("failed to post webhook %s, status code: %d, response body: %s", payload.URL, resp.StatusCode, b)
  65. }
  66. response := &WebhookResponse{}
  67. if err := json.Unmarshal(b, response); err != nil {
  68. return errors.Wrapf(err, "failed to unmarshal webhook response from %s", payload.URL)
  69. }
  70. if response.Code != 0 {
  71. return errors.Errorf("receive error code sent by webhook server, code %d, msg: %s", response.Code, response.Message)
  72. }
  73. return nil
  74. }