message.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package hook
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/gorilla/websocket"
  7. "path/filepath"
  8. "strings"
  9. "wechat-api/workphone"
  10. )
  11. // 开启/关闭实时消息接收功能
  12. func (h *Hook) ConfigureMsgRecive(isEnable string, url string) (err error) {
  13. resp, err := h.Client.R().SetBody(&ConfigureMsgReciveReq{
  14. IsEnable: isEnable,
  15. URL: url,
  16. }).Post("http://" + h.ServerIp + ":" + h.WxPort + "/ConfigureMsgRecive")
  17. if err != nil {
  18. return
  19. }
  20. if !resp.IsSuccessState() {
  21. err = fmt.Errorf("ConfigureMsgRecive failed with status code %d", resp.StatusCode)
  22. return
  23. }
  24. return
  25. }
  26. // SendTextMsg 发送微信文本消息
  27. func (h *Hook) SendTextMsg(wxid, msg, wxWxid string, msgId int64) error {
  28. if h.ServerIp == "" || h.ServerIp == "0" {
  29. conn, err := h.connWorkPhone()
  30. if err != nil {
  31. err = fmt.Errorf("SendTextMsg failed")
  32. return err
  33. }
  34. defer func(conn *websocket.Conn) {
  35. err = conn.Close()
  36. if err != nil {
  37. err = fmt.Errorf("SendTextMsg failed")
  38. }
  39. }(conn)
  40. encodedString := base64.StdEncoding.EncodeToString([]byte(msg))
  41. //sendMsg := &workphone.TalkToFriendTaskMessage{
  42. // WeChatId: wxWxid,
  43. // FriendId: wxid,
  44. // ContentType: workphone.EnumContentType_Text,
  45. // Content: []byte(encodedString),
  46. //}
  47. //content, err := anypb.New(sendMsg) <-- 这里有坑,会增加字段 "@type": "type.googleapis.com/Jubo.JuLiao.IM.Wx.Proto.TalkToFriendTaskMessage",
  48. //if err != nil {
  49. // return fmt.Errorf("failed to pack message: %v", err)
  50. //}
  51. //transportMessage := &workphone.TransportMessage{
  52. // MsgType: workphone.EnumMsgType_TalkToFriendTask,
  53. // Content: content,
  54. //}
  55. // 将 TransportMessage 转换为 JSON
  56. //transportMessageJSON, err := protojson.MarshalOptions{
  57. // UseProtoNames: true,
  58. //}.Marshal(transportMessage)
  59. //if err != nil {
  60. // return fmt.Errorf("failed to marshal transport message: %v", err)
  61. //}
  62. var message map[string]interface{}
  63. if h.Ctype == uint64(3) {
  64. message = map[string]interface{}{
  65. "MsgType": "TalkToFriendTask",
  66. "Content": map[string]interface{}{
  67. "WxId": wxWxid,
  68. "ConvId": wxid,
  69. "ContentType": "Text",
  70. "Content": encodedString,
  71. "TaskId": msgId,
  72. },
  73. }
  74. } else {
  75. message = map[string]interface{}{
  76. "MsgType": "TalkToFriendTask",
  77. "Content": map[string]interface{}{
  78. "WeChatId": wxWxid,
  79. "FriendId": wxid,
  80. "ContentType": "Text",
  81. "Content": encodedString,
  82. "MsgId": msgId,
  83. },
  84. }
  85. }
  86. transportMessageJSON, err := json.Marshal(message)
  87. if err != nil {
  88. return err
  89. }
  90. // 发送 JSON 消息
  91. err = conn.WriteMessage(websocket.TextMessage, transportMessageJSON)
  92. if err != nil {
  93. return fmt.Errorf("failed to send message: %v", err)
  94. }
  95. // 读取回复消息
  96. _, replyMessage, err := conn.ReadMessage()
  97. if err != nil {
  98. return fmt.Errorf("failed to read message: %v", err)
  99. }
  100. var replyMessageData map[string]interface{}
  101. err = json.Unmarshal([]byte(replyMessage), &replyMessageData)
  102. if err != nil {
  103. return fmt.Errorf("failed to send message: %v", err)
  104. }
  105. if replyMessageData["msgType"] == nil || replyMessageData["msgType"] != "MsgReceivedAck" {
  106. return fmt.Errorf("failed to send message: %v")
  107. }
  108. return nil
  109. } else {
  110. resp, err := h.Client.R().SetBody(&SendTextMsgReq{
  111. Wxid: wxid,
  112. Msg: msg,
  113. }).Post("http://" + h.ServerIp + ":" + h.WxPort + "/SendTextMsg")
  114. if err != nil {
  115. return err
  116. }
  117. if !resp.IsSuccessState() {
  118. err = fmt.Errorf("SendTextMsg failed with status code %d", resp.StatusCode)
  119. return err
  120. }
  121. return nil
  122. }
  123. }
  124. // SendPicMsg 发送微信图片
  125. func (h *Hook) SendPicMsg(wxid, picpath, diyfilename, wxWxid string) (err error) {
  126. if h.ServerIp == "" {
  127. conn, err := h.connWorkPhone()
  128. if err != nil {
  129. err = fmt.Errorf("SendPicMsg failed")
  130. return err
  131. }
  132. defer func(conn *websocket.Conn) {
  133. err = conn.Close()
  134. if err != nil {
  135. err = fmt.Errorf("SendPicMsg failed")
  136. }
  137. }(conn)
  138. encodedString := base64.StdEncoding.EncodeToString([]byte(picpath))
  139. contentType := "File"
  140. if isImageFile(diyfilename) {
  141. contentType = "Picture"
  142. }
  143. var message map[string]interface{}
  144. if h.Ctype == uint64(3) {
  145. message = map[string]interface{}{
  146. "MsgType": "TalkToFriendTask",
  147. "Content": map[string]interface{}{
  148. "WxId": wxWxid,
  149. "ConvId": wxid,
  150. "ContentType": contentType,
  151. "Content": encodedString,
  152. },
  153. }
  154. } else {
  155. message = map[string]interface{}{
  156. "MsgType": "TalkToFriendTask",
  157. "Content": map[string]interface{}{
  158. "WeChatId": wxWxid,
  159. "FriendId": wxid,
  160. "ContentType": contentType,
  161. "Content": encodedString,
  162. },
  163. }
  164. }
  165. transportMessageJSON, err := json.Marshal(message)
  166. if err != nil {
  167. return err
  168. }
  169. // 发送 JSON 消息
  170. err = conn.WriteMessage(websocket.TextMessage, transportMessageJSON)
  171. if err != nil {
  172. return fmt.Errorf("failed to send message: %v", err)
  173. }
  174. // 读取回复消息
  175. _, replyMessage, err := conn.ReadMessage()
  176. if err != nil {
  177. return fmt.Errorf("failed to read message: %v", err)
  178. }
  179. var replyMessageData map[string]interface{}
  180. err = json.Unmarshal([]byte(replyMessage), &replyMessageData)
  181. if err != nil {
  182. return fmt.Errorf("failed to send message: %v", err)
  183. }
  184. if replyMessageData["msgType"] == nil || replyMessageData["msgType"] != workphone.EnumMsgType_name[int32(workphone.EnumMsgType_MsgReceivedAck)] {
  185. return fmt.Errorf("failed to send message: %v")
  186. }
  187. return nil
  188. } else {
  189. resp, err := h.Client.R().SetBody(&SendPicMsgReq{
  190. Wxid: wxid,
  191. Picpath: picpath,
  192. Diyfilename: diyfilename,
  193. }).Post("http://" + h.ServerIp + ":" + h.WxPort + "/SendPicMsg")
  194. if err != nil {
  195. return err
  196. }
  197. if !resp.IsSuccessState() {
  198. err = fmt.Errorf("SendPicMsg failed with status code %d", resp.StatusCode)
  199. return err
  200. }
  201. return nil
  202. }
  203. }
  204. // 发送微信图片(本地测试)
  205. func (h *Hook) SendPicMsgLocal(wxid, picpath string) (err error) {
  206. resp, err := h.Client.R().SetBody(&SendPicMsgLocalReq{
  207. Wxid: wxid,
  208. Picpath: picpath,
  209. }).Post("http://" + h.ServerIp + ":" + h.WxPort + "/SendPicMsg")
  210. if err != nil {
  211. return
  212. }
  213. if !resp.IsSuccessState() {
  214. err = fmt.Errorf("SendPicMsgLocal failed with status code %d", resp.StatusCode)
  215. return
  216. }
  217. return
  218. }
  219. func isImageFile(filename string) bool {
  220. ext := strings.ToLower(filepath.Ext(filename))
  221. imageExtensions := []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"}
  222. for _, extToCheck := range imageExtensions {
  223. if ext == extToCheck {
  224. return true
  225. }
  226. }
  227. return false
  228. }