wechat.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package wechat
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "go-common/app/tool/saga/conf"
  7. "go-common/app/tool/saga/dao"
  8. "go-common/app/tool/saga/model"
  9. "go-common/library/log"
  10. "github.com/pkg/errors"
  11. )
  12. // Wechat 企业微信应用
  13. type Wechat struct {
  14. dao *dao.Dao
  15. saga *model.AppConfig
  16. contact *model.AppConfig
  17. }
  18. // New create an new wechat work
  19. func New(d *dao.Dao) (w *Wechat) {
  20. w = &Wechat{
  21. dao: d,
  22. saga: conf.Conf.Property.Wechat,
  23. contact: conf.Conf.Property.Contact,
  24. }
  25. return w
  26. }
  27. // NewTxtNotify create wechat format text notification
  28. func (w *Wechat) NewTxtNotify(content string) (txtMsg *model.TxtNotification) {
  29. return &model.TxtNotification{
  30. Notification: model.Notification{
  31. MsgType: "text",
  32. AgentID: w.saga.AppID,
  33. },
  34. Body: model.Text{
  35. Content: content,
  36. },
  37. Safe: 0,
  38. }
  39. }
  40. // AccessToken get access_token from cache first, if not found, get it via wechat api.
  41. func (w *Wechat) AccessToken(c context.Context, app *model.AppConfig) (token string, err error) {
  42. var (
  43. key string
  44. expire int32
  45. )
  46. key = fmt.Sprintf("appid_%d", app.AppID)
  47. if token, err = w.dao.AccessToken(c, key); err != nil {
  48. log.Warn("AccessToken: failed to get access_token from cache, appId (%d), error (%s)", app.AppID, err.Error())
  49. if token, expire, err = w.dao.WechatAccessToken(c, app.AppSecret); err != nil {
  50. err = errors.Wrapf(err, "AccessToken: both mc and api can't provide access_token, appId(%d)", app.AppID)
  51. return
  52. }
  53. // 通过API获取到了,缓存一波
  54. err = w.dao.SetAccessToken(c, key, token, expire)
  55. return
  56. }
  57. if token == "" {
  58. if token, expire, err = w.dao.WechatAccessToken(c, app.AppSecret); err != nil {
  59. return
  60. }
  61. // 通过API获取到了,缓存一波
  62. err = w.dao.SetAccessToken(c, key, token, expire)
  63. }
  64. return
  65. }
  66. // PushMsg push text message via wechat notification api with access_token.
  67. func (w *Wechat) PushMsg(c context.Context, userNames []string, content string) (err error) {
  68. var (
  69. token string
  70. userIds string
  71. invalidUser string
  72. txtMsg = w.NewTxtNotify(content)
  73. )
  74. if token, err = w.AccessToken(c, w.saga); err != nil {
  75. return
  76. }
  77. if token == "" {
  78. err = errors.Errorf("PushMsg: get access token failed, it's empty. appid (%d), secret (%s)", w.saga.AppID, w.saga.AppSecret)
  79. return
  80. }
  81. if userIds, err = w.UserIds(userNames); err != nil {
  82. return
  83. }
  84. txtMsg.ToUser = userIds
  85. if invalidUser, err = w.dao.WechatPushMsg(c, token, txtMsg); err != nil {
  86. if err = w.addRequireVisible(c, invalidUser); err != nil {
  87. log.Error("PushMsg add userID (%s) in cache, error(%s)", invalidUser, err.Error())
  88. }
  89. return
  90. }
  91. return
  92. }
  93. // UserIds query user ids for user name list
  94. func (w *Wechat) UserIds(userNames []string) (ids string, err error) {
  95. ids, err = w.dao.UserIds(userNames)
  96. return
  97. }
  98. // addRequireVisible update wechat require visible users in memcache
  99. func (w *Wechat) addRequireVisible(c context.Context, userIDs string) (err error) {
  100. var (
  101. contactInfo *model.ContactInfo
  102. userID string
  103. alreadyIn bool
  104. )
  105. users := strings.Split(userIDs, "|")
  106. for _, userID = range users {
  107. if alreadyIn, err = w.alreadyInCache(c, userID); err != nil || alreadyIn {
  108. continue
  109. }
  110. if contactInfo, err = w.dao.QueryUserByID(userID); err != nil {
  111. log.Error("no such userID (%s) in db, error(%s)", userID, err.Error())
  112. return
  113. }
  114. if err = w.dao.SetRequireVisibleUsers(c, contactInfo); err != nil {
  115. log.Error("failed set to cache userID (%s) username (%s), err (%s)", userID, contactInfo.UserName, err.Error())
  116. return
  117. }
  118. }
  119. return
  120. }
  121. // alreadyInCache check user is or not in the memcache
  122. func (w *Wechat) alreadyInCache(c context.Context, userID string) (alreadyIn bool, err error) {
  123. var (
  124. userMap = make(map[string]model.RequireVisibleUser)
  125. )
  126. if err = w.dao.RequireVisibleUsers(c, &userMap); err != nil {
  127. log.Error("get userID (%s) from cache error(%s)", userID, err.Error())
  128. return
  129. }
  130. for k, v := range userMap {
  131. if userID == k {
  132. log.Info("(%s) is already exist in cache, value(%v)", k, v)
  133. alreadyIn = true
  134. return
  135. }
  136. }
  137. return
  138. }