139 lines
3.2 KiB
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×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 {
|
|
var atStr string
|
|
for _, mobile := range atMobiles {
|
|
atStr += fmt.Sprintf("<font color='#FFA500'>@%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)
|
|
}
|