Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

312 lines
8.8KB

  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(ToUserName string, txt 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. //BuildKFTransferAnyOneMsg Transfer to anyone
  30. func BuildKFTransferAnyOneMsg(toUser string) (xml string, err error) {
  31. return BuildKFTransferMsg(toUser, "")
  32. }
  33. //BuildKFTransferMsg Transfer a message to specific kf
  34. func BuildKFTransferMsg(toUser, kf string) (xml string, err error) {
  35. msg := buildKfForwardMsg(toUser, kf)
  36. e := Encode(msg)
  37. xml, _, _, _ = signMsg(e)
  38. return
  39. }
  40. //BuildLocationMsg doesn't work for build location message
  41. // func BuildLocationMsg(long, lat, precision float64, ToUserName string) (xml string) {
  42. // msg := buildLocationMsg()
  43. // e := Encode(msg)
  44. // xml, _, _, _ = signMsg(e)
  45. // return
  46. // }
  47. func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) {
  48. timestamp = int32(time.Now().Unix())
  49. nonce = rand.Int31()
  50. strTimestamp := fmt.Sprintf("%d", timestamp)
  51. strNonce := fmt.Sprintf("%d", nonce)
  52. signature = getSignature(APIConfig.Token, strTimestamp, strNonce, content)
  53. xml = "<xml>" +
  54. "<Encrypt>" + content + "</Encrypt>" +
  55. "<MsgSignature>" + signature + "</MsgSignature>" +
  56. "<TimeStamp>" + strTimestamp + "</TimeStamp>" +
  57. "<Nonce>" + strNonce + "</Nonce>" +
  58. "</xml>"
  59. return
  60. }
  61. func getSignature(token string, timestamp string, nonce string, content string) (signature string) {
  62. strs := []string{token, timestamp, nonce, content}
  63. sort.Strings(strs)
  64. s := strings.Join(strs, "")
  65. h := sha1.New()
  66. h.Write([]byte(s))
  67. signature = fmt.Sprintf("%x", h.Sum(nil))
  68. return
  69. }
  70. func buildTxtMsg(ToUserName, content string) (msg string) {
  71. msg = fmt.Sprintf(txtMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), content)
  72. return
  73. }
  74. func txtMsgTemplate() string {
  75. return `<xml>
  76. <ToUserName><![CDATA[%s]]></ToUserName>
  77. <FromUserName><![CDATA[%s]]></FromUserName>
  78. <CreateTime>%d</CreateTime>
  79. <MsgType><![CDATA[text]]></MsgType>
  80. <Content><![CDATA[%s]]></Content>
  81. </xml>`
  82. }
  83. //upload image to media as temp data, get mediaid and send it out
  84. func buildUploadPicMsg(ToUserName, path string) (msg string) {
  85. mediaID := uploadImage(path)
  86. msg = buildPicMsg(ToUserName, mediaID)
  87. return
  88. }
  89. func buildPicMsg(ToUserName, mediaID string) (msg string) {
  90. msg = fmt.Sprintf(picMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
  91. return
  92. }
  93. func picMsgTemplate() string {
  94. return `<xml>
  95. <ToUserName><![CDATA[%s]]></ToUserName>
  96. <FromUserName><![CDATA[%s]]></FromUserName>
  97. <CreateTime>%d</CreateTime>
  98. <MsgType><![CDATA[image]]></MsgType>
  99. <Image>
  100. <MediaId><![CDATA[%s]]></MediaId>
  101. </Image>
  102. </xml>`
  103. }
  104. func buildUploadVoiceMsg(ToUserName, path string) (msg string) {
  105. mediaID := uploadVoice(path)
  106. log.Println("get media id " + mediaID)
  107. msg = buildVoiceMsg(ToUserName, mediaID)
  108. return
  109. }
  110. func buildVoiceMsg(ToUserName, mediaID string) (msg string) {
  111. msg = fmt.Sprintf(voiceMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID)
  112. return
  113. }
  114. func voiceMsgTemplate() string {
  115. return `<xml>
  116. <ToUserName><![CDATA[%s]]></ToUserName>
  117. <FromUserName><![CDATA[%s]]></FromUserName>
  118. <CreateTime>%d</CreateTime>
  119. <MsgType><![CDATA[voice]]></MsgType>
  120. <Voice>
  121. <MediaId><![CDATA[%s]]></MediaId>
  122. </Voice>
  123. </xml>`
  124. }
  125. func buildVideoMsg(ToUserName, mediaID, title, description string) (msg string) {
  126. msg = fmt.Sprintf(videoMsgTemplate(), ToUserName, APIConfig.PublicAccountID, int32(time.Now().Unix()), mediaID, title, description)
  127. return
  128. }
  129. func videoMsgTemplate() string {
  130. return `<xml>
  131. <ToUserName><![CDATA[%s]]></ToUserName>
  132. <FromUserName><![CDATA[%s]]></FromUserName>
  133. <CreateTime>%d</CreateTime>
  134. <MsgType><![CDATA[video]]></MsgType>
  135. <Video>
  136. <MediaId><![CDATA[%s]]></MediaId>
  137. <Title><![CDATA[%s]]></Title>
  138. <Description><![CDATA[%s]]></Description>
  139. </Video>
  140. </xml>`
  141. }
  142. func buildSampleMusicMsg(ToUserName string) (msg string) {
  143. thumbID := "AxEDlSNwJcs_0KnyiGnpAYiB1-sjITosWkU3VFsj62KuCyTQO-Fh1UH8d-pBmY1K"
  144. thumbID = "JZoNKZr9gzaI5ELBnFUljujiBfIwr4CtXHkZtQMjm-sLVD5PGOU_uvsaF3oNNFjp"
  145. thumbID = "5dlAsVZ8znWBuGLTjAFM8mIqapHiI0Cmazsvx4TmbsQXZk73RZz8AVnbZp6oSJZn" //jpg 200x200
  146. thumbID = "e2iNEiSxCX5TV1WbFd0TQJsw84YtISnam2Q_qEXDdT4" //永久素材的 ID
  147. url := "http://www.youtubeinmp3.com/download/get/?i=vNIuJKoAE46uz2RggRaKGFqQUVAqd0Td&e=92&progressType=button&color=008000"
  148. url = "http://agobe.yt-downloader.org/download.php?id=d7be28d3a1fafa69d7e464edb8186226"
  149. url = "http://www.sample-videos.com/audio/mp3/india-national-anthem.mp3"
  150. url = "http://google.com/"
  151. url = "http://m.creaders.net/travel/2017/05/11/1823175.html"
  152. url = "https://biukop.com.au/music.mp3" //real mp3
  153. //url = "https://doc.biukop.com.au/angular2/#/pages/dashboard"
  154. //url = "http://mp.weixin.qq.com/s/Jo7rmlMZa_iO97eckWIzFg"
  155. msg = buildMusicMsg(ToUserName, thumbID, "音乐标杆出", "测试音乐缩略土月卡其", url, url)
  156. return
  157. }
  158. func buildMusicMsg(ToUserName, ThumbMediaID, title, description, url, hqURL string) (msg string) {
  159. msg = fmt.Sprintf(musicMsgTemplate(),
  160. ToUserName,
  161. APIConfig.PublicAccountID,
  162. int32(time.Now().Unix()),
  163. title,
  164. description,
  165. url,
  166. hqURL,
  167. ThumbMediaID)
  168. return
  169. }
  170. func musicMsgTemplate() string {
  171. return `<xml>
  172. <ToUserName><![CDATA[%s]]></ToUserName>
  173. <FromUserName><![CDATA[%s]]></FromUserName>
  174. <CreateTime>%d</CreateTime>
  175. <MsgType><![CDATA[music]]></MsgType>
  176. <Music>
  177. <Title><![CDATA[%s]]></Title>
  178. <Description><![CDATA[%s]]></Description>
  179. <MusicUrl><![CDATA%s]]></MusicUrl>
  180. <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
  181. <ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
  182. </Music>
  183. </xml>`
  184. }
  185. func buildSampleArticleMsg(ToUserName string) (msg string) {
  186. art := Article{}
  187. art.title = "标题描述很长,不知道多少汉字"
  188. art.description = "f;alsfjl;dsajfls;ajfl;sajl;fjdsal;fs"
  189. art.picURL = "http://placehold.it/360x200"
  190. art.url = "http://doc.biukop.com.au/"
  191. articles := []Article{}
  192. articles = append(articles, art)
  193. articles = append(articles, art)
  194. msg = buildNewsMsg(ToUserName, "标题", "描述", articles)
  195. return
  196. }
  197. func buildNewsMsg(ToUserName, title, description string, articles []Article) (msg string) {
  198. count := 0
  199. items := []string{}
  200. for _, a := range articles {
  201. if count >= 8 {
  202. err := errors.New("too many articles, only take first 8")
  203. log.Println(err)
  204. break
  205. }
  206. s := buildArticleItem(a)
  207. items = append(items, s)
  208. count++
  209. }
  210. strItems := strings.Join(items, "")
  211. msg = fmt.Sprintf(newsMsgTemplate(),
  212. ToUserName,
  213. APIConfig.PublicAccountID,
  214. int32(time.Now().Unix()),
  215. count,
  216. strItems)
  217. return
  218. }
  219. func buildArticleItem(item Article) (article string) {
  220. template := `<item>
  221. <Title><![CDATA[%s]]></Title>
  222. <Description><![CDATA[%s]]></Description>
  223. <PicUrl><![CDATA[%s]]></PicUrl>
  224. <Url><![CDATA[%s]]></Url>
  225. </item>
  226. `
  227. article = fmt.Sprintf(template,
  228. item.title, item.description, item.picURL, item.url)
  229. return article
  230. }
  231. func newsMsgTemplate() string {
  232. return `<xml>
  233. <ToUserName><![CDATA[%s]]></ToUserName>
  234. <FromUserName><![CDATA[%s]]></FromUserName>
  235. <CreateTime>%d</CreateTime>
  236. <MsgType><![CDATA[news]]></MsgType>
  237. <ArticleCount>%d</ArticleCount>
  238. <Articles>
  239. %s
  240. </Articles>
  241. </xml>`
  242. }
  243. // func buildLocationMsg() string {
  244. // template := `<xml>
  245. // <ToUserName><![CDATA[oUN420bxqFqlx0ZQHciUOesZO3PE]]></ToUserName>
  246. // <FromUserName><![CDATA[gh_f09231355c68]]></FromUserName>
  247. // <CreateTime>1494124221</CreateTime>
  248. // <MsgType><![CDATA[location]]></MsgType>
  249. // <Location_X>23.134521</Location_X>
  250. // <Location_Y>113.358803</Location_Y>
  251. // <Scale>20</Scale>
  252. // <Label><![CDATA[位置信息]]></Label>
  253. // </xml> `
  254. // return template
  255. // }
  256. func buildKfForwardMsg(toUser string, kf string) (msg string) {
  257. //转发信息到任意客服
  258. template := `<xml>s
  259. <ToUserName><![CDATA[%s]]></ToUserName>
  260. <FromUserName><![CDATA[%s]]></FromUserName>
  261. <CreateTime>%d</CreateTime>
  262. <MsgType><![CDATA[transfer_customer_service]]></MsgType>
  263. </xml>`
  264. //发送信息指定客服人员
  265. templateKF := ` <xml>
  266. <ToUserName><![CDATA[%s]]></ToUserName>
  267. <FromUserName><![CDATA[%s]]></FromUserName>
  268. <CreateTime>%d</CreateTime>
  269. <MsgType><![CDATA[transfer_customer_service]]></MsgType>
  270. <TransInfo>
  271. <KfAccount><![CDATA[%s]]></KfAccount>
  272. </TransInfo>
  273. </xml>`
  274. if kf == "" {
  275. msg = fmt.Sprintf(template, toUser, APIConfig.PublicAccountID, time.Now().Unix())
  276. } else {
  277. msg = fmt.Sprintf(templateKF, toUser, APIConfig.PublicAccountID, time.Now().Unix(), kf)
  278. }
  279. return
  280. }