| import ( | import ( | ||||
| "crypto/sha1" | "crypto/sha1" | ||||
| "errors" | |||||
| "fmt" | "fmt" | ||||
| "log" | |||||
| "math/rand" | "math/rand" | ||||
| "sort" | "sort" | ||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| ) | ) | ||||
| //Article is one item in News Message | |||||
| // one such message can contains upto 10 Articles | |||||
| type Article struct { | |||||
| title, description, picURL, url string | |||||
| } | |||||
| //BuildTextMsg Given a text message send it to wechat client | //BuildTextMsg Given a text message send it to wechat client | ||||
| func BuildTextMsg(txt string, ToUserName string) (string, error) { | |||||
| func BuildTextMsg(txt string, ToUserName string) (xml string, err error) { | |||||
| if txt == "" || ToUserName == "" { | |||||
| err = errors.New("Empty text body or Empty destination") | |||||
| xml = "" | |||||
| return | |||||
| } | |||||
| template := `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[text]]></MsgType> | |||||
| <Content><![CDATA[%s]]></Content> | |||||
| </xml>` | |||||
| msg := fmt.Sprintf(template, ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), txt) | |||||
| msg := fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), txt) | |||||
| e := Encode(msg) | e := Encode(msg) | ||||
| str, _, _, _ := signMsg(e) | |||||
| return str, nil | |||||
| xml, _, _, _ = signMsg(e) | |||||
| return | |||||
| } | } | ||||
| func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) { | func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) { | ||||
| signature = fmt.Sprintf("%x", h.Sum(nil)) | signature = fmt.Sprintf("%x", h.Sum(nil)) | ||||
| return | return | ||||
| } | } | ||||
| func buildTxtMsg(ToUserName, content string) (msg string) { | |||||
| msg = fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), content) | |||||
| return | |||||
| } | |||||
| func txtMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[text]]></MsgType> | |||||
| <Content><![CDATA[%s]]></Content> | |||||
| </xml>` | |||||
| } | |||||
| func buildPicMsg(ToUserName, mediaID string) (msg string) { | |||||
| msg = fmt.Sprintf(picMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID) | |||||
| return | |||||
| } | |||||
| func picMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[image]]></MsgType> | |||||
| <Image> | |||||
| <MediaId><![CDATA[%s]]></MediaId> | |||||
| </Image> | |||||
| </xml>` | |||||
| } | |||||
| func buildVoiceMsg(ToUserName, mediaID string) (msg string) { | |||||
| msg = fmt.Sprintf(voiceMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID) | |||||
| return | |||||
| } | |||||
| func voiceMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[voice]]></MsgType> | |||||
| <Voice> | |||||
| <MediaId><![CDATA[%s]]></MediaId> | |||||
| </Voice> | |||||
| </xml>` | |||||
| } | |||||
| func buildVideoMsg(ToUserName, mediaID, title, description string) (msg string) { | |||||
| msg = fmt.Sprintf(videoMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID, title, description) | |||||
| return | |||||
| } | |||||
| func videoMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[video]]></MsgType> | |||||
| <Video> | |||||
| <MediaId><![CDATA[%s]]></MediaId> | |||||
| <Title><![CDATA[%s]]></Title> | |||||
| <Description><![CDATA[%s]]></Description> | |||||
| </Video> | |||||
| </xml>` | |||||
| } | |||||
| func bulidMusicMsg(ToUserName, mediaID, title, description, url, hqURL string) (msg string) { | |||||
| msg = fmt.Sprintf(musicMsgTemplate(), | |||||
| ToUserName, | |||||
| APIConfig.PublicAccountID, | |||||
| int32(time.Now().Unix()), | |||||
| title, | |||||
| description, | |||||
| url, | |||||
| hqURL, | |||||
| mediaID) | |||||
| return | |||||
| } | |||||
| func musicMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[toUser]]></ToUserName> | |||||
| <FromUserName><![CDATA[fromUser]]></FromUserName> | |||||
| <CreateTime>12345678</CreateTime> | |||||
| <MsgType><![CDATA[music]]></MsgType> | |||||
| <Music> | |||||
| <Title><![CDATA[TITLE]]></Title> | |||||
| <Description><![CDATA[DESCRIPTION]]></Description> | |||||
| <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl> | |||||
| <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl> | |||||
| <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId> | |||||
| </Music> | |||||
| </xml>` | |||||
| } | |||||
| func buildNewsMsg(ToUserName, title, description string, articles []Article) (msg string) { | |||||
| count := len(articles) | |||||
| if count <= 0 { | |||||
| log.Fatal("using empty article to build NewsMsg") | |||||
| msg = "" | |||||
| return | |||||
| } | |||||
| items := []string{} | |||||
| for _, a := range articles { | |||||
| s := buildArticleItem(a) | |||||
| items = append(items, s) | |||||
| } | |||||
| strItems := strings.Join(items, "") | |||||
| msg = fmt.Sprintf(newsMsgTemplate(), | |||||
| ToUserName, | |||||
| APIConfig.PublicAccountID, | |||||
| int32(time.Now().Unix()), | |||||
| count, | |||||
| strItems) | |||||
| return | |||||
| } | |||||
| func buildArticleItem(item Article) (article string) { | |||||
| template := `<item> | |||||
| <Title><![CDATA[%s]]></Title> | |||||
| <Description><![CDATA[%s]]></Description> | |||||
| <PicUrl><![CDATA[%s]]></PicUrl> | |||||
| <Url><![CDATA[%s]]></Url> | |||||
| </item> | |||||
| ` | |||||
| article = fmt.Sprintf(template, | |||||
| item.title, item.description, item.picURL, item.url) | |||||
| return article | |||||
| } | |||||
| func newsMsgTemplate() string { | |||||
| return `<xml> | |||||
| <ToUserName><![CDATA[%s]]></ToUserName> | |||||
| <FromUserName><![CDATA[%s]]></FromUserName> | |||||
| <CreateTime>%d</CreateTime> | |||||
| <MsgType><![CDATA[news]]></MsgType> | |||||
| <ArticleCount>%d</ArticleCount> | |||||
| <Articles> | |||||
| %s | |||||
| </Articles> | |||||
| </xml>` | |||||
| } |