lark.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package channel
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "crypto/sha256"
  6. "encoding/base64"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "message-pusher/model"
  11. "net/http"
  12. "strconv"
  13. "strings"
  14. "time"
  15. )
  16. type larkMessageRequestCardElementText struct {
  17. Content string `json:"content"`
  18. Tag string `json:"tag"`
  19. }
  20. type larkMessageRequestCardElement struct {
  21. Tag string `json:"tag"`
  22. Text larkMessageRequestCardElementText `json:"text"`
  23. }
  24. type larkMessageRequest struct {
  25. MessageType string `json:"msg_type"`
  26. Timestamp string `json:"timestamp"`
  27. Sign string `json:"sign"`
  28. Content struct {
  29. Text string `json:"text"`
  30. } `json:"content"`
  31. Card struct {
  32. Config struct {
  33. WideScreenMode bool `json:"wide_screen_mode"`
  34. EnableForward bool `json:"enable_forward"`
  35. }
  36. Elements []larkMessageRequestCardElement `json:"elements"`
  37. } `json:"card"`
  38. }
  39. type larkMessageResponse struct {
  40. Code int `json:"code"`
  41. Message string `json:"msg"`
  42. }
  43. func SendLarkMessage(message *model.Message, user *model.User, channel_ *model.Channel) error {
  44. // https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN#e1cdee9f
  45. messageRequest := larkMessageRequest{
  46. MessageType: "text",
  47. }
  48. atPrefix := ""
  49. if message.To != "" {
  50. if message.To == "@all" {
  51. atPrefix = "<at user_id=\"all\">所有人</at>"
  52. } else {
  53. ids := strings.Split(message.To, "|")
  54. for _, id := range ids {
  55. atPrefix += fmt.Sprintf("<at user_id=\"%s\"> </at>", id)
  56. }
  57. }
  58. }
  59. if message.Content == "" {
  60. messageRequest.MessageType = "text"
  61. messageRequest.Content.Text = atPrefix + message.Description
  62. } else {
  63. messageRequest.MessageType = "interactive"
  64. messageRequest.Card.Config.WideScreenMode = true
  65. messageRequest.Card.Config.EnableForward = true
  66. messageRequest.Card.Elements = append(messageRequest.Card.Elements, larkMessageRequestCardElement{
  67. Tag: "div",
  68. Text: larkMessageRequestCardElementText{
  69. Content: atPrefix + message.Content,
  70. Tag: "lark_md",
  71. },
  72. })
  73. }
  74. now := time.Now()
  75. timestamp := now.Unix()
  76. sign, err := larkSign(channel_.Secret, timestamp)
  77. if err != nil {
  78. return err
  79. }
  80. messageRequest.Sign = sign
  81. messageRequest.Timestamp = strconv.FormatInt(timestamp, 10)
  82. jsonData, err := json.Marshal(messageRequest)
  83. if err != nil {
  84. return err
  85. }
  86. resp, err := http.Post(channel_.URL, "application/json",
  87. bytes.NewBuffer(jsonData))
  88. if err != nil {
  89. return err
  90. }
  91. var res larkMessageResponse
  92. err = json.NewDecoder(resp.Body).Decode(&res)
  93. if err != nil {
  94. return err
  95. }
  96. if res.Code != 0 {
  97. return errors.New(res.Message)
  98. }
  99. return nil
  100. }
  101. func larkSign(secret string, timestamp int64) (string, error) {
  102. // https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN
  103. // timestamp + key -> sha256 -> base64 encode
  104. stringToSign := fmt.Sprintf("%v", timestamp) + "\n" + secret
  105. var data []byte
  106. h := hmac.New(sha256.New, []byte(stringToSign))
  107. _, err := h.Write(data)
  108. if err != nil {
  109. return "", err
  110. }
  111. signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
  112. return signature, nil
  113. }