157 lines
3.8 KiB
Go
157 lines
3.8 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×tamp=%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 {
|
||
|
||
if len(atMobiles) > 0 {
|
||
var atStr string
|
||
for _, mobile := range atMobiles {
|
||
atStr += fmt.Sprintf("<font color='green'>@%s</font>", mobile)
|
||
}
|
||
text += fmt.Sprintf("\n<font color='red'>请尽快处理</font>%s", 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)
|
||
}
|