wechat-bot/bot.go

135 lines
3.0 KiB
Go
Raw Permalink Normal View History

2022-07-21 23:10:41 +08:00
package wxworkbot
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func init() {
}
const (
defaultWebHookUrlTemplate = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=%s"
)
var (
ErrUnsupportedMessage = errors.New("尚不支持的消息类型")
)
type WxWorkBot struct {
Key string
WebHookUrl string
Client *http.Client
}
// 创建一个新的机器人实例
func New(botKey string) *WxWorkBot {
bot := WxWorkBot{
Key: botKey,
// 直接拼接出接口 URL
WebHookUrl: fmt.Sprintf(defaultWebHookUrlTemplate, botKey),
// 默认 5 秒超时
Client: &http.Client{Timeout: 5 * time.Second},
}
return &bot
}
// 发送消息允许的参数类型Text、Markdown、Image、News
func (bot *WxWorkBot) Send(msg interface{}) error {
msgBytes, err := marshalMessage(msg)
if err != nil {
return err
}
webHookUrl := bot.WebHookUrl
if len(webHookUrl) == 0 {
webHookUrl = fmt.Sprintf(defaultWebHookUrlTemplate, bot.Key)
}
req, err := http.NewRequest(http.MethodPost, webHookUrl, bytes.NewBuffer(msgBytes))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
resp, err := bot.Client.Do(req)
if err != nil {
return err
}
body, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
var wxWorkResp wxWorkResponse
err = json.Unmarshal(body, &wxWorkResp)
if err != nil {
return err
}
if wxWorkResp.ErrorCode != 0 && wxWorkResp.ErrorMessage != "" {
return errors.New(string(body))
}
return nil
}
// 防止 < > 等 HTML 字符在 json.marshal 时被 escape
func marshal(msg interface{}) ([]byte, error) {
buf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(buf)
jsonEncoder.SetEscapeHTML(false)
jsonEncoder.SetIndent("", "")
err := jsonEncoder.Encode(msg)
if err != nil {
return nil, nil
}
return buf.Bytes(), nil
}
// 将消息包装成企信接口要求的格式,返回 json bytes
func marshalMessage(msg interface{}) ([]byte, error) {
if text, ok := msg.(Text); ok {
textMsg := textMessage{
message: message{MsgType: "text"},
Text: text,
}
return marshal(textMsg)
}
if textMsg, ok := msg.(textMessage); ok {
textMsg.MsgType = "text"
return marshal(textMsg)
}
if markdown, ok := msg.(Markdown); ok {
markdownMsg := markdownMessage{
message: message{MsgType: "markdown"},
Markdown: markdown,
}
return marshal(markdownMsg)
}
if markdownMsg, ok := msg.(markdownMessage); ok {
markdownMsg.MsgType = "markdown"
return marshal(markdownMsg)
}
if image, ok := msg.(Image); ok {
imageMsg := imageMessage{
message: message{MsgType: "image"},
Image: image,
}
return marshal(imageMsg)
}
if imageMsg, ok := msg.(imageMessage); ok {
imageMsg.MsgType = "image"
return marshal(imageMsg)
}
if news, ok := msg.(News); ok {
newsMsg := newsMessage{
message: message{MsgType: "news"},
News: news,
}
return marshal(newsMsg)
}
if newsMsg, ok := msg.(newsMessage); ok {
newsMsg.MsgType = "news"
return marshal(newsMsg)
}
return nil, ErrUnsupportedMessage
}