voucher/internal/pkg/ding/ding.go

154 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("<font color='#003BFF'>@%s</font>", 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)
}
// SendJSONAsMarkdown 发送JSON数据转换为Markdown格式
func (c *TalkClient) SendJSONAsMarkdown(data interface{}, title string) error {
// 将JSON数据转换为格式化的字符串
jsonBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
return fmt.Errorf("序列化JSON失败: %w", err)
}
// 构建Markdown内容使用代码块格式
markdownText := fmt.Sprintf("### %s\n\n```json\n%s\n```", title, string(jsonBytes))
// 发送Markdown消息
return c.SendMarkdownMessage(title, markdownText, nil, false)
}