voucher/internal/pkg/ding/ding.go

139 lines
3.2 KiB
Go

package ding
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"time"
)
// TalkClient 钉钉消息推送客户端结构体
type TalkClient struct {
webhookURL string
secret string
}
// NewDingTalkClient 创建一个新的钉钉消息推送客户端实例
func NewDingTalkClient(webhookURL, secret string) *TalkClient {
return &TalkClient{
webhookURL: webhookURL,
secret: secret,
}
}
// generateSign 生成加签
func (c *TalkClient) generateSign(timestamp string) (string, error) {
stringToSign := timestamp + "\n" + c.secret
h := hmac.New(sha256.New, []byte(c.secret))
_, err := h.Write([]byte(stringToSign))
if err != nil {
return "", err
}
signData := h.Sum(nil)
return base64.StdEncoding.EncodeToString(signData), nil
}
// sendRequest 发送 HTTP 请求
func (c *TalkClient) sendRequest(message map[string]interface{}) error {
timestamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
fullURL := fmt.Sprintf("%s&timestamp=%s", c.webhookURL, timestamp)
if len(c.secret) > 0 {
sign, err := c.generateSign(timestamp)
if err != nil {
return err
}
fullURL = fmt.Sprintf("%s&sign=%s", fullURL, sign)
}
messageJSON, err := json.Marshal(message)
if err != nil {
return err
}
req, err := http.NewRequest("POST", fullURL, bytes.NewBuffer(messageJSON))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to send message, status code: %d, body: %s", resp.StatusCode, string(body))
}
return nil
}
// SendTextMessage 发送文本消息并可 @ 人员
func (c *TalkClient) SendTextMessage(content string, atMobiles []string, isAtAll bool) error {
message := map[string]interface{}{
"msgtype": "text",
"text": map[string]string{
"content": content,
},
"at": map[string]interface{}{
"atMobiles": atMobiles,
"isAtAll": isAtAll,
},
}
return c.sendRequest(message)
}
// SendLinkMessage 发送链接消息并可 @ 人员
func (c *TalkClient) SendLinkMessage(title, text, messageURL, picURL string, atMobiles []string, isAtAll bool) error {
message := map[string]interface{}{
"msgtype": "link",
"link": map[string]string{
"title": title,
"text": text,
"messageUrl": messageURL,
"picUrl": picURL,
},
"at": map[string]interface{}{
"atMobiles": atMobiles,
"isAtAll": isAtAll,
},
}
return c.sendRequest(message)
}
// SendMarkdownMessage 发送 Markdown 消息并可 @ 人员
func (c *TalkClient) SendMarkdownMessage(title, text string, atMobiles []string, isAtAll bool) error {
var atStr string
for _, mobile := range atMobiles {
atStr += fmt.Sprintf(" @%s", mobile)
}
text += atStr
message := map[string]interface{}{
"msgtype": "markdown",
"markdown": map[string]string{
"title": title,
"text": text,
},
"at": map[string]interface{}{
"atMobiles": atMobiles,
"isAtAll": isAtAll,
},
}
return c.sendRequest(message)
}