q-koa 12.8.5 → 12.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const util = require('util')
|
|
2
|
+
const axios = require('axios')
|
|
3
|
+
|
|
4
|
+
const { lodash } = require('q-koa')
|
|
5
|
+
const getAccessTokenUrl =
|
|
6
|
+
'https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s'
|
|
7
|
+
|
|
8
|
+
const getOpenListUrl =
|
|
9
|
+
'https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s'
|
|
10
|
+
|
|
11
|
+
const getUserInfoUrl =
|
|
12
|
+
'https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN'
|
|
13
|
+
|
|
14
|
+
const getUserInfoListUrl =
|
|
15
|
+
'https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s'
|
|
16
|
+
|
|
17
|
+
const sendMessageUrl =
|
|
18
|
+
'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s'
|
|
19
|
+
|
|
20
|
+
const getTemplateUrl =
|
|
21
|
+
'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=%s'
|
|
22
|
+
|
|
23
|
+
const LRU = require('lru-cache')
|
|
24
|
+
const cache = new LRU({
|
|
25
|
+
max: 100,
|
|
26
|
+
maxAge: 1000 * 60 * 60,
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
module.exports = class Singleton {
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.config = {
|
|
32
|
+
...config,
|
|
33
|
+
grant_type: 'client_credential',
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 单例模式
|
|
37
|
+
*/
|
|
38
|
+
if (!Singleton.instance) {
|
|
39
|
+
Singleton.instance = this
|
|
40
|
+
}
|
|
41
|
+
const previous = Singleton.instance.getConfig()
|
|
42
|
+
if (!lodash.isEqual(previous, config)) {
|
|
43
|
+
Singleton.instance = this
|
|
44
|
+
}
|
|
45
|
+
return Singleton.instance
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
init() {
|
|
49
|
+
if (!this.config.appid || !this.config.secrect) {
|
|
50
|
+
throw new Error('没有配置appid或secrect')
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getAccessToken() {
|
|
55
|
+
const { appid, secrect, grant_type } = this.config
|
|
56
|
+
if (cache.get(appid)) {
|
|
57
|
+
return cache.get(appid)
|
|
58
|
+
}
|
|
59
|
+
const url = util.format(getAccessTokenUrl, grant_type, appid, secrect)
|
|
60
|
+
|
|
61
|
+
const result = await axios.get(url).then((res) => res.data)
|
|
62
|
+
const { errcode, errmsg, access_token } = result
|
|
63
|
+
|
|
64
|
+
if (errcode) {
|
|
65
|
+
throw new Error(errmsg)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cache.set(appid, access_token)
|
|
69
|
+
return access_token
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getOpenList() {
|
|
73
|
+
const access_token = await this.getAccessToken()
|
|
74
|
+
const url = util.format(getOpenListUrl, access_token)
|
|
75
|
+
const result = await axios.post(url).then((res) => res.data)
|
|
76
|
+
if (result.errcode) {
|
|
77
|
+
if (result.errcode === 40001) {
|
|
78
|
+
cache.reset()
|
|
79
|
+
return await this.getOpenList()
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
82
|
+
}
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getUserInfo(openid) {
|
|
87
|
+
const access_token = await this.getAccessToken()
|
|
88
|
+
const url = util.format(getUserInfoUrl, access_token, openid)
|
|
89
|
+
const result = await axios.post(url).then((res) => res.data)
|
|
90
|
+
if (result.errcode) {
|
|
91
|
+
if (result.errcode === 40001) {
|
|
92
|
+
cache.reset()
|
|
93
|
+
return await this.getUserInfo(openid)
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
96
|
+
}
|
|
97
|
+
return result
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getUserInfoList(list = []) {
|
|
101
|
+
const user_list = list.map((openid) => {
|
|
102
|
+
return {
|
|
103
|
+
openid,
|
|
104
|
+
lang: 'zh_CN',
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
const access_token = await this.getAccessToken()
|
|
108
|
+
const url = util.format(getUserInfoListUrl, access_token)
|
|
109
|
+
const result = await axios
|
|
110
|
+
.post(url, {
|
|
111
|
+
user_list,
|
|
112
|
+
})
|
|
113
|
+
.then((res) => res.data)
|
|
114
|
+
if (result.errcode) {
|
|
115
|
+
if (result.errcode === 40001) {
|
|
116
|
+
cache.reset()
|
|
117
|
+
return await this.getUserInfoList(list)
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
120
|
+
}
|
|
121
|
+
return result.user_info_list
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async sendMessage(options) {
|
|
125
|
+
const access_token = await this.getAccessToken()
|
|
126
|
+
const url = util.format(sendMessageUrl, access_token)
|
|
127
|
+
const formatOptions = {
|
|
128
|
+
...options,
|
|
129
|
+
data: lodash.mapValues(options.data, (item) => {
|
|
130
|
+
return {
|
|
131
|
+
value: item,
|
|
132
|
+
}
|
|
133
|
+
}),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result = await axios.post(url, formatOptions).then((res) => res.data)
|
|
137
|
+
if (result.errcode) {
|
|
138
|
+
if (result.errcode === 40001) {
|
|
139
|
+
cache.reset()
|
|
140
|
+
return await this.sendMessage(options)
|
|
141
|
+
}
|
|
142
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
143
|
+
}
|
|
144
|
+
return result
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async getTemplate() {
|
|
148
|
+
const access_token = await this.getAccessToken()
|
|
149
|
+
const url = util.format(getTemplateUrl, access_token)
|
|
150
|
+
const result = await axios.post(url).then((res) => res.data)
|
|
151
|
+
if (result.errcode) {
|
|
152
|
+
if (result.errcode === 40001) {
|
|
153
|
+
cache.reset()
|
|
154
|
+
return await this.getTemplate()
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
157
|
+
}
|
|
158
|
+
return result
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getConfig() {
|
|
162
|
+
return this.config
|
|
163
|
+
}
|
|
164
|
+
}
|