token-store.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package channel
  2. import (
  3. "message-pusher/common"
  4. "message-pusher/model"
  5. "sync"
  6. "time"
  7. )
  8. type TokenStoreItem interface {
  9. Key() string
  10. Token() string
  11. Refresh()
  12. IsFilled() bool
  13. }
  14. type tokenStore struct {
  15. Map map[string]*TokenStoreItem
  16. Mutex sync.RWMutex
  17. ExpirationSeconds int
  18. }
  19. var s tokenStore
  20. func TokenStoreInit() {
  21. s.Map = make(map[string]*TokenStoreItem)
  22. // https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
  23. // https://developer.work.weixin.qq.com/document/path/91039
  24. s.ExpirationSeconds = 2 * 55 * 60 // 2 hours - 5 minutes
  25. go func() {
  26. users, err := model.GetAllUsersWithSecrets()
  27. if err != nil {
  28. common.FatalLog(err.Error())
  29. }
  30. var items []TokenStoreItem
  31. for _, user := range users {
  32. if user.WeChatTestAccountId != "" {
  33. item := &WeChatTestAccountTokenStoreItem{
  34. AppID: user.WeChatTestAccountId,
  35. AppSecret: user.WeChatTestAccountSecret,
  36. }
  37. items = append(items, item)
  38. }
  39. if user.WeChatCorpAccountId != "" {
  40. item := &WeChatCorpAccountTokenStoreItem{
  41. CorpId: user.WeChatCorpAccountId,
  42. AgentSecret: user.WeChatCorpAccountAgentSecret,
  43. AgentId: user.WeChatCorpAccountAgentId,
  44. }
  45. items = append(items, item)
  46. }
  47. }
  48. s.Mutex.RLock()
  49. for i := range items {
  50. // s.Map[item.Key()] = &item // This is wrong, you are getting the address of a local variable!
  51. s.Map[items[i].Key()] = &items[i]
  52. }
  53. s.Mutex.RUnlock()
  54. for {
  55. s.Mutex.RLock()
  56. var tmpMap = make(map[string]*TokenStoreItem)
  57. for k, v := range s.Map {
  58. tmpMap[k] = v
  59. }
  60. s.Mutex.RUnlock()
  61. for k := range tmpMap {
  62. (*tmpMap[k]).Refresh()
  63. }
  64. s.Mutex.RLock()
  65. // we shouldn't directly replace the old map with the new map, cause the old map's keys may already change
  66. for k := range s.Map {
  67. v, okay := tmpMap[k]
  68. if okay {
  69. s.Map[k] = v
  70. }
  71. }
  72. sleepDuration := common.Max(s.ExpirationSeconds, 60)
  73. s.Mutex.RUnlock()
  74. time.Sleep(time.Duration(sleepDuration) * time.Second)
  75. }
  76. }()
  77. }
  78. // TokenStoreAddItem It's okay to add an incomplete item.
  79. func TokenStoreAddItem(item TokenStoreItem) {
  80. if !item.IsFilled() {
  81. return
  82. }
  83. item.Refresh()
  84. s.Mutex.RLock()
  85. s.Map[item.Key()] = &item
  86. s.Mutex.RUnlock()
  87. }
  88. func TokenStoreRemoveItem(item TokenStoreItem) {
  89. s.Mutex.RLock()
  90. delete(s.Map, item.Key())
  91. s.Mutex.RUnlock()
  92. }
  93. func TokenStoreAddUser(user *model.User) {
  94. testItem := WeChatTestAccountTokenStoreItem{
  95. AppID: user.WeChatTestAccountId,
  96. AppSecret: user.WeChatTestAccountSecret,
  97. }
  98. TokenStoreAddItem(&testItem)
  99. corpItem := WeChatCorpAccountTokenStoreItem{
  100. CorpId: user.WeChatCorpAccountId,
  101. AgentSecret: user.WeChatCorpAccountAgentSecret,
  102. AgentId: user.WeChatCorpAccountAgentId,
  103. }
  104. TokenStoreAddItem(&corpItem)
  105. }
  106. func TokenStoreUpdateUser(cleanUser *model.User, originUser *model.User) {
  107. // WeChat Test Account
  108. // The fields of cleanUser may be incomplete!
  109. if cleanUser.WeChatTestAccountId == originUser.WeChatTestAccountId {
  110. cleanUser.WeChatTestAccountId = ""
  111. }
  112. if cleanUser.WeChatTestAccountSecret == originUser.WeChatTestAccountSecret {
  113. cleanUser.WeChatTestAccountSecret = ""
  114. }
  115. // This means the user updated those fields.
  116. if cleanUser.WeChatTestAccountId != "" || cleanUser.WeChatTestAccountSecret != "" {
  117. oldWeChatTestAccountTokenStoreItem := WeChatTestAccountTokenStoreItem{
  118. AppID: originUser.WeChatTestAccountId,
  119. AppSecret: originUser.WeChatTestAccountSecret,
  120. }
  121. // Yeah, it's a deep copy.
  122. newWeChatTestAccountTokenStoreItem := oldWeChatTestAccountTokenStoreItem
  123. if cleanUser.WeChatTestAccountId != "" {
  124. newWeChatTestAccountTokenStoreItem.AppID = cleanUser.WeChatTestAccountId
  125. }
  126. if cleanUser.WeChatTestAccountSecret != "" {
  127. newWeChatTestAccountTokenStoreItem.AppSecret = cleanUser.WeChatTestAccountSecret
  128. }
  129. if !oldWeChatTestAccountTokenStoreItem.IsShared() {
  130. TokenStoreRemoveItem(&oldWeChatTestAccountTokenStoreItem)
  131. }
  132. TokenStoreAddItem(&newWeChatTestAccountTokenStoreItem)
  133. }
  134. // WeChat Corp Account
  135. if cleanUser.WeChatCorpAccountId == originUser.WeChatCorpAccountId {
  136. cleanUser.WeChatCorpAccountId = ""
  137. }
  138. if cleanUser.WeChatCorpAccountAgentId == originUser.WeChatCorpAccountAgentId {
  139. cleanUser.WeChatCorpAccountAgentId = ""
  140. }
  141. if cleanUser.WeChatCorpAccountAgentSecret == originUser.WeChatCorpAccountAgentSecret {
  142. cleanUser.WeChatCorpAccountAgentSecret = ""
  143. }
  144. if cleanUser.WeChatCorpAccountId != "" || cleanUser.WeChatCorpAccountAgentId != "" || cleanUser.WeChatCorpAccountAgentSecret != "" {
  145. oldWeChatCorpAccountTokenStoreItem := WeChatCorpAccountTokenStoreItem{
  146. CorpId: originUser.WeChatCorpAccountId,
  147. AgentSecret: originUser.WeChatCorpAccountAgentSecret,
  148. AgentId: originUser.WeChatCorpAccountAgentId,
  149. }
  150. newWeChatCorpAccountTokenStoreItem := oldWeChatCorpAccountTokenStoreItem
  151. if cleanUser.WeChatCorpAccountId != "" {
  152. newWeChatCorpAccountTokenStoreItem.CorpId = cleanUser.WeChatCorpAccountId
  153. }
  154. if cleanUser.WeChatCorpAccountAgentSecret != "" {
  155. newWeChatCorpAccountTokenStoreItem.AgentSecret = cleanUser.WeChatCorpAccountAgentSecret
  156. }
  157. if cleanUser.WeChatCorpAccountAgentId != "" {
  158. newWeChatCorpAccountTokenStoreItem.AgentId = cleanUser.WeChatCorpAccountAgentId
  159. }
  160. if !oldWeChatCorpAccountTokenStoreItem.IsShared() {
  161. TokenStoreRemoveItem(&oldWeChatCorpAccountTokenStoreItem)
  162. }
  163. TokenStoreAddItem(&newWeChatCorpAccountTokenStoreItem)
  164. }
  165. }
  166. // TokenStoreRemoveUser
  167. // user must be filled.
  168. // It's okay to delete a user that don't have an item here.
  169. func TokenStoreRemoveUser(user *model.User) {
  170. testAccountTokenStoreItem := WeChatTestAccountTokenStoreItem{
  171. AppID: user.WeChatTestAccountId,
  172. AppSecret: user.WeChatTestAccountSecret,
  173. }
  174. if !testAccountTokenStoreItem.IsShared() {
  175. TokenStoreRemoveItem(&testAccountTokenStoreItem)
  176. }
  177. corpAccountTokenStoreItem := WeChatCorpAccountTokenStoreItem{
  178. CorpId: user.WeChatCorpAccountId,
  179. AgentSecret: user.WeChatCorpAccountAgentSecret,
  180. AgentId: user.WeChatCorpAccountAgentId,
  181. }
  182. if !corpAccountTokenStoreItem.IsShared() {
  183. TokenStoreRemoveItem(&corpAccountTokenStoreItem)
  184. }
  185. }
  186. func TokenStoreGetToken(key string) string {
  187. s.Mutex.RLock()
  188. defer s.Mutex.RUnlock()
  189. item, ok := s.Map[key]
  190. if ok {
  191. return (*item).Token()
  192. }
  193. common.SysError("token for " + key + " is blank!")
  194. return ""
  195. }