135 lines
3.0 KiB
Go
135 lines
3.0 KiB
Go
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
|
||
}
|