Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

223 lines
5.7KB

  1. package main
  2. import (
  3. "crypto/sha1"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "math/rand"
  8. "sort"
  9. "strings"
  10. "time"
  11. )
  12. //Article is one item in News Message
  13. // one such message can contains upto 10 Articles
  14. type Article struct {
  15. title, description, picURL, url string
  16. }
  17. //BuildTextMsg Given a text message send it to wechat client
  18. func BuildTextMsg(txt string, ToUserName string) (xml string, err error) {
  19. if txt == "" || ToUserName == "" {
  20. err = errors.New("Empty text body or Empty destination")
  21. xml = ""
  22. return
  23. }
  24. msg := fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), txt)
  25. e := Encode(msg)
  26. xml, _, _, _ = signMsg(e)
  27. return
  28. }
  29. //BuildLocationMsg doesn't work for build location message
  30. func BuildLocationMsg(long, lat, precision float64, ToUserName string) (xml string) {
  31. msg := buildLocationMsg()
  32. e := Encode(msg)
  33. xml, _, _, _ = signMsg(e)
  34. return
  35. }
  36. func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) {
  37. timestamp = int32(time.Now().Unix())
  38. nonce = rand.Int31()
  39. strTimestamp := fmt.Sprintf("%d", timestamp)
  40. strNonce := fmt.Sprintf("%d", nonce)
  41. signature = getSignature(APIConfig.Token, strTimestamp, strNonce, content)
  42. xml = "<xml>" +
  43. "<Encrypt>" + content + "</Encrypt>" +
  44. "<MsgSignature>" + signature + "</MsgSignature>" +
  45. "<TimeStamp>" + strTimestamp + "</TimeStamp>" +
  46. "<Nonce>" + strNonce + "</Nonce>" +
  47. "</xml>"
  48. return
  49. }
  50. func getSignature(token string, timestamp string, nonce string, content string) (signature string) {
  51. strs := []string{token, timestamp, nonce, content}
  52. sort.Strings(strs)
  53. s := strings.Join(strs, "")
  54. h := sha1.New()
  55. h.Write([]byte(s))
  56. signature = fmt.Sprintf("%x", h.Sum(nil))
  57. return
  58. }
  59. func buildTxtMsg(ToUserName, content string) (msg string) {
  60. msg = fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), content)
  61. return
  62. }
  63. func txtMsgTemplate() string {
  64. return `<xml>
  65. <ToUserName><![CDATA[%s]]></ToUserName>
  66. <FromUserName><![CDATA[%s]]></FromUserName>
  67. <CreateTime>%d</CreateTime>
  68. <MsgType><![CDATA[text]]></MsgType>
  69. <Content><![CDATA[%s]]></Content>
  70. </xml>`
  71. }
  72. func buildPicMsg(ToUserName, mediaID string) (msg string) {
  73. msg = fmt.Sprintf(picMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
  74. return
  75. }
  76. func picMsgTemplate() string {
  77. return `<xml>
  78. <ToUserName><![CDATA[%s]]></ToUserName>
  79. <FromUserName><![CDATA[%s]]></FromUserName>
  80. <CreateTime>%d</CreateTime>
  81. <MsgType><![CDATA[image]]></MsgType>
  82. <Image>
  83. <MediaId><![CDATA[%s]]></MediaId>
  84. </Image>
  85. </xml>`
  86. }
  87. func buildVoiceMsg(ToUserName, mediaID string) (msg string) {
  88. msg = fmt.Sprintf(voiceMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
  89. return
  90. }
  91. func voiceMsgTemplate() string {
  92. return `<xml>
  93. <ToUserName><![CDATA[%s]]></ToUserName>
  94. <FromUserName><![CDATA[%s]]></FromUserName>
  95. <CreateTime>%d</CreateTime>
  96. <MsgType><![CDATA[voice]]></MsgType>
  97. <Voice>
  98. <MediaId><![CDATA[%s]]></MediaId>
  99. </Voice>
  100. </xml>`
  101. }
  102. func buildVideoMsg(ToUserName, mediaID, title, description string) (msg string) {
  103. msg = fmt.Sprintf(videoMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID, title, description)
  104. return
  105. }
  106. func videoMsgTemplate() string {
  107. return `<xml>
  108. <ToUserName><![CDATA[%s]]></ToUserName>
  109. <FromUserName><![CDATA[%s]]></FromUserName>
  110. <CreateTime>%d</CreateTime>
  111. <MsgType><![CDATA[video]]></MsgType>
  112. <Video>
  113. <MediaId><![CDATA[%s]]></MediaId>
  114. <Title><![CDATA[%s]]></Title>
  115. <Description><![CDATA[%s]]></Description>
  116. </Video>
  117. </xml>`
  118. }
  119. func bulidMusicMsg(ToUserName, mediaID, title, description, url, hqURL string) (msg string) {
  120. msg = fmt.Sprintf(musicMsgTemplate(),
  121. ToUserName,
  122. APIConfig.PublicAccountID,
  123. int32(time.Now().Unix()),
  124. title,
  125. description,
  126. url,
  127. hqURL,
  128. mediaID)
  129. return
  130. }
  131. func musicMsgTemplate() string {
  132. return `<xml>
  133. <ToUserName><![CDATA[toUser]]></ToUserName>
  134. <FromUserName><![CDATA[fromUser]]></FromUserName>
  135. <CreateTime>12345678</CreateTime>
  136. <MsgType><![CDATA[music]]></MsgType>
  137. <Music>
  138. <Title><![CDATA[TITLE]]></Title>
  139. <Description><![CDATA[DESCRIPTION]]></Description>
  140. <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
  141. <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
  142. <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
  143. </Music>
  144. </xml>`
  145. }
  146. func buildNewsMsg(ToUserName, title, description string, articles []Article) (msg string) {
  147. count := 0
  148. items := []string{}
  149. for _, a := range articles {
  150. if count >= 8 {
  151. err := errors.New("too many articles, only take first 8")
  152. log.Fatal(err)
  153. break
  154. }
  155. s := buildArticleItem(a)
  156. items = append(items, s)
  157. count++
  158. }
  159. strItems := strings.Join(items, "")
  160. msg = fmt.Sprintf(newsMsgTemplate(),
  161. ToUserName,
  162. APIConfig.PublicAccountID,
  163. int32(time.Now().Unix()),
  164. count,
  165. strItems)
  166. return
  167. }
  168. func buildArticleItem(item Article) (article string) {
  169. template := `<item>
  170. <Title><![CDATA[%s]]></Title>
  171. <Description><![CDATA[%s]]></Description>
  172. <PicUrl><![CDATA[%s]]></PicUrl>
  173. <Url><![CDATA[%s]]></Url>
  174. </item>
  175. `
  176. article = fmt.Sprintf(template,
  177. item.title, item.description, item.picURL, item.url)
  178. return article
  179. }
  180. func newsMsgTemplate() string {
  181. return `<xml>
  182. <ToUserName><![CDATA[%s]]></ToUserName>
  183. <FromUserName><![CDATA[%s]]></FromUserName>
  184. <CreateTime>%d</CreateTime>
  185. <MsgType><![CDATA[news]]></MsgType>
  186. <ArticleCount>%d</ArticleCount>
  187. <Articles>
  188. %s
  189. </Articles>
  190. </xml>`
  191. }
  192. func buildLocationMsg() string {
  193. template := `<xml>
  194. <ToUserName><![CDATA[oUN420bxqFqlx0ZQHciUOesZO3PE]]></ToUserName>
  195. <FromUserName><![CDATA[gh_f09231355c68]]></FromUserName>
  196. <CreateTime>1494124221</CreateTime>
  197. <MsgType><![CDATA[location]]></MsgType>
  198. <Location_X>23.134521</Location_X>
  199. <Location_Y>113.358803</Location_Y>
  200. <Scale>20</Scale>
  201. <Label><![CDATA[位置信息]]></Label>
  202. </xml> `
  203. return template
  204. }