-
Notifications
You must be signed in to change notification settings - Fork 93
/
type.go
359 lines (315 loc) · 8.36 KB
/
type.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
package wechat
import (
"encoding/json"
"encoding/xml"
"fmt"
"strings"
)
// Type io类型汇总
const (
TypeText = "text"
TypeImage = "image"
TypeVoice = "voice"
TypeMusic = "music"
TypeVideo = "video"
TypeTextcard = "textcard" // 仅企业微信可用
TypeWxCard = "wxcard" // 仅服务号可用
TypeMarkDown = "markdown" // 仅企业微信可用
TypeTaskCard = "taskcard" // 仅企业微信可用
TypeFile = "file" // 仅企业微信可用
TypeNews = "news"
TypeMpNews = "mpnews" // 仅企业微信可用
TypeEvent = "event" // 订阅或取消订阅
)
const (
EventSubscribe = "subscribe"
EventUnsubscribe = "unsubscribe"
)
// WxErr 通用错误
type WxErr struct {
ErrCode int
ErrMsg string
}
func (w *WxErr) Error() error {
if w.ErrCode != 0 {
return fmt.Errorf("err: errcode=%v , errmsg=%v", w.ErrCode, w.ErrMsg)
}
return nil
}
// CDATA 标准规范,XML编码成 `<![CDATA[消息内容]]>`
type CDATA string
// MarshalXML 自定义xml编码接口,实现讨论: http://stackoverflow.com/q/41951345/7493327
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(struct {
string `xml:",cdata"`
}{string(c)}, start)
}
// wxResp 响应消息共用字段
// 响应消息被动回复为XML结构,文本类型采用CDATA编码规范
// 响应消息主动发送为json结构,即客服消息
type wxResp struct {
XMLName xml.Name `xml:"xml" json:"-"`
ToUserName CDATA `json:"touser"`
ToParty CDATA `xml:"-" json:"toparty"` // 企业号专用
ToTag CDATA `xml:"-" json:"totag"` // 企业号专用
FromUserName CDATA `json:"-"`
CreateTime int64 `json:"-"`
MsgType CDATA `json:"msgtype"`
AgentId int `xml:"-" json:"agentid"`
Safe int `xml:"-" json:"safe"`
}
// to字段格式:"userid1|userid2 deptid1|deptid2 tagid1|tagid2"
func (s *Server) newWxResp(msgType, to string) (r wxResp) {
toArr := strings.Split(to, " ")
r = wxResp{
ToUserName: CDATA(toArr[0]),
MsgType: CDATA(msgType),
AgentId: s.AgentId,
Safe: s.Safe}
if len(toArr) > 1 {
r.ToParty = CDATA(toArr[1])
}
if len(toArr) > 2 {
r.ToTag = CDATA(toArr[2])
}
return
}
// Text 文本消息
type (
Text struct {
wxResp
content `xml:"Content" json:"text"`
}
content struct {
Content CDATA `json:"content"`
}
)
// NewText Text 文本消息
func (s *Server) NewText(to string, msg ...string) Text {
return Text{
s.newWxResp(TypeText, to),
content{CDATA(strings.Join(msg, ""))},
}
}
// Image 图片消息
type (
Image struct {
wxResp
Image media `json:"image"`
}
media struct {
MediaId CDATA `json:"media_id"`
}
)
// NewImage Image 消息
func (s *Server) NewImage(to, mediaId string) Image {
return Image{
s.newWxResp(TypeImage, to),
media{CDATA(mediaId)},
}
}
// Voice 语音消息
type Voice struct {
wxResp
Voice media `json:"voice"`
}
// NewVoice Voice消息
func (s *Server) NewVoice(to, mediaId string) Voice {
return Voice{
s.newWxResp(TypeVoice, to),
media{CDATA(mediaId)},
}
}
// File 文件消息,仅企业号支持
type File struct {
wxResp
File media `json:"file"`
}
// NewFile File消息
func (s *Server) NewFile(to, mediaId string) File {
return File{
s.newWxResp(TypeFile, to),
media{CDATA(mediaId)},
}
}
// Video 视频消息
type (
Video struct {
wxResp
Video video `json:"video"`
}
video struct {
MediaId CDATA `json:"media_id"`
Title CDATA `json:"title"`
Description CDATA `json:"description"`
}
)
// NewVideo Video消息
func (s *Server) NewVideo(to, mediaId, title, desc string) Video {
return Video{
s.newWxResp(TypeVideo, to),
video{CDATA(mediaId), CDATA(title), CDATA(desc)},
}
}
// Textcard 卡片消息,仅企业微信客户端有效
type (
Textcard struct {
wxResp
Textcard textcard `json:"textcard"`
}
textcard struct {
Title CDATA `json:"title"`
Description CDATA `json:"description"`
Url CDATA `json:"url"`
Btn CDATA `json:"btntxt"`
}
)
// NewTextcard Textcard消息
func (s *Server) NewTextcard(to, title, description, url, btntxt string) Textcard {
return Textcard{
s.newWxResp(TypeTextcard, to),
textcard{CDATA(title), CDATA(description), CDATA(url), CDATA(btntxt)},
}
}
// Music 音乐消息,企业微信不支持
type (
Music struct {
wxResp
Music music `json:"music"`
}
music struct {
Title CDATA `json:"title"`
Description CDATA `json:"description"`
MusicUrl CDATA `json:"musicurl"`
HQMusicUrl CDATA `json:"hqmusicurl"`
ThumbMediaId CDATA `json:"thumb_media_id"`
}
)
// NewMusic Music消息
func (s *Server) NewMusic(to, mediaId, title, desc, musicUrl, qhMusicUrl string) Music {
return Music{
s.newWxResp(TypeMusic, to),
music{CDATA(title), CDATA(desc), CDATA(musicUrl), CDATA(qhMusicUrl), CDATA(mediaId)},
}
}
// News 新闻消息
type News struct {
wxResp
ArticleCount int
Articles struct {
Item []Article `xml:"item" json:"articles"`
} `json:"news"`
}
// NewNews news消息
func (s *Server) NewNews(to string, arts ...Article) (news News) {
news.wxResp = s.newWxResp(TypeNews, to)
news.ArticleCount = len(arts)
news.Articles.Item = arts
return
}
// Article 文章
type Article struct {
Title CDATA `json:"title"`
Description CDATA `json:"description"`
PicUrl CDATA `json:"picurl"`
Url CDATA `json:"url"`
}
// NewArticle 先创建文章,再传给NewNews()
func NewArticle(title, desc, picUrl, url string) Article {
return Article{CDATA(title), CDATA(desc), CDATA(picUrl), CDATA(url)}
}
type (
// MpNews 加密新闻消息,仅企业微信支持
MpNews struct {
wxResp
MpNews struct {
Articles []MpArticle `json:"articles"`
} `json:"mpnews"`
}
// MpNewsId 加密新闻消息(通过mediaId直接发)
MpNewsId struct {
wxResp
MpNews struct {
MediaId CDATA `json:"media_id"`
} `json:"mpnews"`
}
)
// NewMpNews 加密新闻mpnews消息(仅企业微信可用)
func (s *Server) NewMpNews(to string, arts ...MpArticle) (news MpNews) {
news.wxResp = s.newWxResp(TypeMpNews, to)
news.MpNews.Articles = arts
return
}
// NewMpNewsId 加密新闻mpnews消息(仅企业微信可用)
func (s *Server) NewMpNewsId(to string, mediaId string) (news MpNewsId) {
news.wxResp = s.newWxResp(TypeMpNews, to)
news.MpNews.MediaId = CDATA(mediaId)
return
}
// MpArticle 加密文章
type MpArticle struct {
Title string `json:"title"`
ThumbMediaId string `json:"thumb_media_id"`
Author string `json:"author"`
Url string `json:"content_source_url"`
Content string `json:"content"`
Digest string `json:"digest"`
}
// NewMpArticle 先创建加密文章,再传给NewMpNews()
func NewMpArticle(title, mediaId, author, url, content, digest string) MpArticle {
return MpArticle{title, mediaId, author, url, content, digest}
}
// WxCard 卡券
type WxCard struct {
wxResp
WxCard struct {
CardId string `json:"card_id"`
} `json:"wxcard"`
}
// NewWxCard 卡券消息,服务号可用
func (s *Server) NewWxCard(to, cardId string) (c WxCard) {
c.wxResp = s.newWxResp(TypeWxCard, to)
c.WxCard.CardId = cardId
return
}
// MarkDown markdown消息,仅企业微信支持,上限2048字节,utf-8编码
type MarkDown struct {
wxResp
MarkDown struct {
Content string `json:"content"`
} `json:"markdown"`
}
// NewMarkDown markdown消息,企业微信可用
func (s *Server) NewMarkDown(to, content string) (md MarkDown) {
md.wxResp = s.newWxResp(TypeMarkDown, to)
md.MarkDown.Content = content
return
}
// TaskCard 任务卡片消息,仅企业微信支持,支持一到两个按钮设置
type TaskCard struct {
wxResp
TaskCard struct {
Title string `json:"title"`
Description string `json:"description"`
Url string `json:"url"`
TaskId string `json:"task_id"`
Btn []map[string]interface{} `json:"btn"`
} `json:"taskcard"`
}
// NewTaskCard 任务卡片消息,企业微信可用
func (s *Server) NewTaskCard(to, Title, Desc, Url, TaskId, Btn string) (tc TaskCard) {
tc.wxResp = s.newWxResp(TypeTaskCard, to)
tc.TaskCard.Title = Title
tc.TaskCard.Description = Desc
tc.TaskCard.Url = Url
tc.TaskCard.TaskId = TaskId
mp := make([]map[string]interface{}, 0)
if Btn != "" {
if err := json.Unmarshal([]byte(Btn), &mp); err != nil {
fmt.Println("create taskcard btn err:", err)
} else {
tc.TaskCard.Btn = mp
}
}
return
}