py-wecom-toolkit 1.0.0__py3-none-any.whl

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,43 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ py_wecom - 企业微信API Python SDK
5
+
6
+ 提供企业微信API的完整Python封装,支持以下功能模块:
7
+
8
+ 1. **Webhook模块** (`py_wecom.webhook`)
9
+ - 企业微信Webhook消息发送
10
+ - 支持文本、Markdown、图片、图文、文件、语音、模板卡片等消息类型
11
+ - 支持同步和异步两种调用方式
12
+
13
+ 2. **Server模块** (`py_wecom.server`)
14
+ - 企业微信Server API集成
15
+ - 支持获取access_token、发送消息、上传素材等功能
16
+ - 支持同步和异步两种调用方式
17
+
18
+ 快速开始:
19
+
20
+ **Webhook使用示例**:
21
+ >>> from py_wecom_toolkit.webhook import Webhook
22
+ >>> from py_wecom_toolkit.webhook.messages import Text, TextContent
23
+ >>> webhook = Webhook(key="your_webhook_key")
24
+ >>> response = webhook.send_text(content=Text(text=TextContent(content="Hello World")))
25
+ >>> print(response.json())
26
+
27
+ **Server使用示例**:
28
+ >>> from py_wecom_toolkit.server import Base
29
+ >>> from py_wecom_toolkit.server.messages import Sender, Text, TextContent
30
+ >>> from diskcache import Cache
31
+ >>> diskcache_default = Cache()
32
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret", cache_config={"instance": diskcache_default})
33
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
34
+ >>> server.refresh_access_token()
35
+ >>> sender = Sender(corpid="your_corpid", corpsecret="your_corpsecret", agentid="your_agentid", cache_config={"instance": diskcache_default})
36
+ >>> sender.refresh_access_token()
37
+ >>> response = sender.send_text(content=Text(text=TextContent(content="Hello from py-wecom!")), agentid="your_agentid")
38
+ >>> print(response.json())
39
+
40
+ 参考文档:
41
+ - Webhook API: https://developer.work.weixin.qq.com/document/path/91770
42
+ - Server API: https://developer.work.weixin.qq.com/document/path/90664
43
+ """
@@ -0,0 +1,559 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ 企业微信Server模块
5
+
6
+ 提供企业微信Server API的客户端实现,支持同步和异步两种模式。
7
+
8
+ 主要功能:
9
+ - 获取access_token(支持缓存)
10
+ - 获取API域名IP
11
+ - 获取回调IP
12
+
13
+ 参考文档:
14
+ - https://developer.work.weixin.qq.com/document/path/90664
15
+ """
16
+
17
+ from typing import Optional, Union
18
+
19
+ import diskcache
20
+ import httpx
21
+ import redis
22
+ from py_httpx_toolkit import Httpx
23
+
24
+ from .utils import build_success_instance, success_is_valid
25
+
26
+
27
+ class Base(Httpx):
28
+ """
29
+ 企业微信Server API基础客户端类
30
+
31
+ 提供企业微信Server API的核心功能,包括access_token管理、IP查询等。
32
+ 支持同步和异步两种模式,支持使用diskcache或Redis缓存access_token。
33
+
34
+ Attributes:
35
+ base_url: 企业微信API基础URL,默认为官方地址
36
+ corpid: 企业ID,可在企业微信管理后台获取
37
+ corpsecret: 应用密钥,可在企业微信管理后台获取
38
+ agentid: 企业应用ID,可在企业微信管理后台获取
39
+ cache_config: 缓存配置字典,包含instance(缓存实例)、key(缓存键名)、expire(过期时间)
40
+ client_kwargs: HTTP客户端配置参数
41
+ access_token: 当前的access_token
42
+
43
+ 代码演示:
44
+ >>> from py_wecom_toolkit.server import Base
45
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
46
+ >>> server.refresh_access_token()
47
+ >>> print(server.access_token)
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ base_url: Optional[str] = "https://qyapi.weixin.qq.com/",
53
+ corpid: Optional[str] = None,
54
+ corpsecret: Optional[str] = None,
55
+ agentid: Optional[Union[str, int]] = None,
56
+ cache_config: Optional[dict] = None,
57
+ client_kwargs: Optional[dict] = None,
58
+ ):
59
+ # 设置基础URL,去除末尾斜杠以确保URL格式统一
60
+ self.base_url = base_url[:-1] if base_url.endswith("/") else base_url
61
+ # 设置企业ID,若为None则设为空字符串
62
+ self.corpid = corpid or ""
63
+ # 设置应用密钥,若为None则设为空字符串
64
+ self.corpsecret = corpsecret or ""
65
+ # 设置企业应用ID,若为None则设为空字符串
66
+ self.agentid = agentid or ""
67
+ # 设置缓存配置,若为None则设为空字典
68
+ self.cache_config = cache_config or {}
69
+ # 合并默认缓存配置与用户配置,用户配置优先覆盖默认值
70
+ # 默认配置:不使用缓存实例,缓存键名为py_wecom_server_{corpid}_{agentid},过期时间7100秒
71
+ self.cache_config = {
72
+ **{
73
+ "instance": None,
74
+ "key": f"py_wecom_server_{self.corpid}_{self.agentid}",
75
+ "expire": 7100,
76
+ },
77
+ **self.cache_config,
78
+ }
79
+ # 设置HTTP客户端配置,若为None则设为空字典
80
+ self.client_kwargs = client_kwargs or {}
81
+ # 合并默认客户端配置与用户配置,用户配置优先覆盖默认值
82
+ # 默认配置:基础URL、超时时间60秒
83
+ self.client_kwargs = {
84
+ **{
85
+ "base_url": self.base_url,
86
+ "timeout": 60,
87
+ "verify": False,
88
+ },
89
+ **self.client_kwargs,
90
+ }
91
+ # 初始化access_token为空字符串
92
+ self.access_token = None
93
+
94
+ def gettoken(
95
+ self,
96
+ client: Optional[httpx.Client] = None,
97
+ client_kwargs: Optional[dict] = None,
98
+ **kwargs
99
+ ) -> httpx.Response:
100
+ """
101
+ 同步获取access_token
102
+
103
+ @see: https://developer.work.weixin.qq.com/document/path/91039
104
+
105
+ 调用企业微信API /cgi-bin/gettoken 获取access_token,用于后续API调用的身份验证。
106
+ access_token的有效期为7200秒,需要定期刷新。
107
+
108
+ Args:
109
+ client: 可选的HTTP客户端实例,若提供则直接使用
110
+ client_kwargs: 创建临时客户端时的额外配置参数
111
+ **kwargs: 额外的请求参数,将与默认参数合并
112
+
113
+ Returns:
114
+ httpx.Response: HTTP响应对象,成功时包含access_token字段
115
+
116
+ 响应结构:
117
+ {
118
+ "errcode": 0,
119
+ "errmsg": "ok",
120
+ "access_token": "ACCESS_TOKEN",
121
+ "expires_in": 7200
122
+ }
123
+
124
+ 代码演示:
125
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
126
+ >>> response = server.gettoken()
127
+ >>> print(response.json())
128
+ """
129
+ client_kwargs = client_kwargs or {}
130
+ # 处理None值,确保kwargs是字典类型
131
+ kwargs = kwargs or {}
132
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
133
+ kwargs = {
134
+ # 默认请求参数:获取token的路径、GET方法、企业ID和应用密钥参数
135
+ **{
136
+ "method": "GET",
137
+ "url": "/cgi-bin/gettoken",
138
+ "params": {
139
+ "corpid": self.corpid,
140
+ "corpsecret": self.corpsecret,
141
+ }
142
+ },
143
+ **kwargs
144
+ }
145
+ return self.request(client=client, client_kwargs=client_kwargs, **kwargs)
146
+
147
+ async def async_gettoken(
148
+ self,
149
+ client: Optional[httpx.AsyncClient] = None,
150
+ client_kwargs: Optional[dict] = None,
151
+ **kwargs
152
+ ) -> httpx.Response:
153
+ """
154
+ 异步获取access_token
155
+
156
+ @see: https://developer.work.weixin.qq.com/document/path/91039
157
+
158
+ 调用企业微信API /cgi-bin/gettoken 获取access_token,用于后续API调用的身份验证。
159
+ access_token的有效期为7200秒,需要定期刷新。
160
+
161
+ Args:
162
+ client: 可选的异步HTTP客户端实例,若提供则直接使用
163
+ client_kwargs: 创建临时客户端时的额外配置参数
164
+ **kwargs: 额外的请求参数,将与默认参数合并
165
+
166
+ Returns:
167
+ httpx.Response: HTTP响应对象,成功时包含access_token字段
168
+
169
+ 代码演示:
170
+ >>> import asyncio
171
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
172
+ >>> async def main():
173
+ >>> response = await server.async_gettoken()
174
+ >>> print(response.json())
175
+ >>> asyncio.run(main())
176
+ """
177
+ client_kwargs = client_kwargs or {}
178
+ # 处理None值,确保kwargs是字典类型
179
+ kwargs = kwargs or {}
180
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
181
+ kwargs = {
182
+ # 默认请求参数:获取token的路径、GET方法、企业ID和应用密钥参数
183
+ **{
184
+ "method": "GET",
185
+ "url": "/cgi-bin/gettoken",
186
+ "params": {
187
+ "corpid": self.corpid,
188
+ "corpsecret": self.corpsecret,
189
+ }
190
+ },
191
+ **kwargs
192
+ }
193
+ return await self.async_request(client=client, client_kwargs=client_kwargs, **kwargs)
194
+
195
+ def get_api_domain_ip(
196
+ self,
197
+ client: Optional[httpx.Client] = None,
198
+ client_kwargs: Optional[dict] = None,
199
+ **kwargs
200
+ ) -> httpx.Response:
201
+ """
202
+ 同步获取企业微信API域名IP列表
203
+
204
+ @see: https://developer.work.weixin.qq.com/document/path/90960
205
+
206
+ 获取企业微信API服务器的IP地址列表,用于白名单配置等场景。
207
+
208
+ Args:
209
+ client: 可选的HTTP客户端实例,若提供则直接使用
210
+ client_kwargs: 创建临时客户端时的额外配置参数
211
+ **kwargs: 额外的请求参数,将与默认参数合并
212
+
213
+ Returns:
214
+ httpx.Response: HTTP响应对象,成功时包含IP列表
215
+
216
+ 响应结构:
217
+ {
218
+ "errcode": 0,
219
+ "errmsg": "ok",
220
+ "ip_list": ["IP1", "IP2", ...]
221
+ }
222
+
223
+ 代码演示:
224
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
225
+ >>> server.refresh_access_token()
226
+ >>> response = server.get_api_domain_ip()
227
+ >>> print(response.json())
228
+ """
229
+ client_kwargs = client_kwargs or {}
230
+ # 处理None值,确保kwargs是字典类型
231
+ kwargs = kwargs or {}
232
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
233
+ kwargs = {
234
+ **{
235
+ "method": "GET",
236
+ "url": "/cgi-bin/get_api_domain_ip",
237
+ "params": {
238
+ "access_token": self.access_token,
239
+ }
240
+ },
241
+ **kwargs
242
+ }
243
+ return self.request(client=client, client_kwargs=client_kwargs, **kwargs)
244
+
245
+ async def async_get_api_domain_ip(
246
+ self,
247
+ client: Optional[httpx.AsyncClient] = None,
248
+ client_kwargs: Optional[dict] = None,
249
+ **kwargs
250
+ ) -> httpx.Response:
251
+ """
252
+ 异步获取企业微信API域名IP列表
253
+
254
+ @see: https://developer.work.weixin.qq.com/document/path/90960
255
+
256
+ 获取企业微信API服务器的IP地址列表,用于白名单配置等场景。
257
+
258
+ Args:
259
+ client: 可选的异步HTTP客户端实例,若提供则直接使用
260
+ client_kwargs: 创建临时客户端时的额外配置参数
261
+ **kwargs: 额外的请求参数,将与默认参数合并
262
+
263
+ Returns:
264
+ httpx.Response: HTTP响应对象,成功时包含IP列表
265
+
266
+ 代码演示:
267
+ >>> import asyncio
268
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
269
+ >>> await server.async_refresh_access_token()
270
+ >>> response = await server.async_get_api_domain_ip()
271
+ >>> print(response.json())
272
+ """
273
+ client_kwargs = client_kwargs or {}
274
+ # 处理None值,确保kwargs是字典类型
275
+ kwargs = kwargs or {}
276
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
277
+ kwargs = {
278
+ **{
279
+ "method": "GET",
280
+ "url": "/cgi-bin/get_api_domain_ip",
281
+ "params": {
282
+ "access_token": self.access_token,
283
+ }
284
+ },
285
+ **kwargs
286
+ }
287
+ return await self.async_request(client=client, client_kwargs=client_kwargs, **kwargs)
288
+
289
+ def getcallbackip(
290
+ self,
291
+ client: Optional[httpx.Client] = None,
292
+ client_kwargs: Optional[dict] = None,
293
+ **kwargs
294
+ ) -> httpx.Response:
295
+ """
296
+ 同步获取企业微信回调IP列表
297
+
298
+ @see: https://developer.work.weixin.qq.com/document/path/90961
299
+
300
+ 获取企业微信服务器用于回调的IP地址列表,用于配置服务器白名单。
301
+
302
+ Args:
303
+ client: 可选的HTTP客户端实例,若提供则直接使用
304
+ client_kwargs: 创建临时客户端时的额外配置参数
305
+ **kwargs: 额外的请求参数,将与默认参数合并
306
+
307
+ Returns:
308
+ httpx.Response: HTTP响应对象,成功时包含回调IP列表
309
+
310
+ 响应结构:
311
+ {
312
+ "errcode": 0,
313
+ "errmsg": "ok",
314
+ "ip_list": ["IP1", "IP2", ...]
315
+ }
316
+
317
+ 代码演示:
318
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
319
+ >>> server.refresh_access_token()
320
+ >>> response = server.getcallbackip()
321
+ >>> print(response.json())
322
+ """
323
+ client_kwargs = client_kwargs or {}
324
+ # 处理None值,确保kwargs是字典类型
325
+ kwargs = kwargs or {}
326
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
327
+ kwargs = {
328
+ **{
329
+ "method": "GET",
330
+ "url": "/cgi-bin/getcallbackip",
331
+ "params": {
332
+ "access_token": self.access_token,
333
+ }
334
+ },
335
+ **kwargs
336
+ }
337
+ return self.request(client=client, client_kwargs=client_kwargs, **kwargs)
338
+
339
+ async def async_getcallbackip(
340
+ self,
341
+ client: Optional[httpx.AsyncClient] = None,
342
+ client_kwargs: Optional[dict] = None,
343
+ **kwargs
344
+ ) -> httpx.Response:
345
+ """
346
+ 异步获取企业微信回调IP列表
347
+
348
+ @see: https://developer.work.weixin.qq.com/document/path/90961
349
+
350
+ 获取企业微信服务器用于回调的IP地址列表,用于配置服务器白名单。
351
+
352
+ Args:
353
+ client: 可选的异步HTTP客户端实例,若提供则直接使用
354
+ client_kwargs: 创建临时客户端时的额外配置参数
355
+ **kwargs: 额外的请求参数,将与默认参数合并
356
+
357
+ Returns:
358
+ httpx.Response: HTTP响应对象,成功时包含回调IP列表
359
+
360
+ 代码演示:
361
+ >>> import asyncio
362
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret")
363
+ >>> await server.async_refresh_access_token()
364
+ >>> response = await server.async_getcallbackip()
365
+ >>> print(response.json())
366
+ """
367
+ client_kwargs = client_kwargs or {}
368
+ # 处理None值,确保kwargs是字典类型
369
+ kwargs = kwargs or {}
370
+ # 合并默认请求参数与用户参数,用户参数优先覆盖默认值
371
+ kwargs = {
372
+ **{
373
+ "method": "GET",
374
+ "url": "/cgi-bin/getcallbackip",
375
+ "params": {
376
+ "access_token": self.access_token,
377
+ }
378
+ },
379
+ **kwargs
380
+ }
381
+ return await self.async_request(client=client, client_kwargs=client_kwargs, **kwargs)
382
+
383
+ def refresh_access_token(
384
+ self,
385
+ gettoken_func_kwargs: Optional[dict] = None,
386
+ get_api_domain_ip_func_kwargs: Optional[dict] = None,
387
+ cache_config: Optional[dict] = None,
388
+ ) -> "Base":
389
+ """
390
+ 同步刷新access_token
391
+
392
+ 获取并更新access_token,支持使用diskcache或Redis进行缓存,减少API调用次数。
393
+
394
+ 逻辑流程:
395
+ 1. 合并缓存配置(实例配置与调用时配置)
396
+ 2. 判断是否配置了缓存实例(diskcache.Cache或redis.Redis)
397
+ 3. 如果未配置缓存:直接调用gettoken获取access_token
398
+ 4. 如果配置了缓存:
399
+ - 优先从缓存获取access_token
400
+ - 如果缓存中没有或无效,调用gettoken获取并写入缓存
401
+ - 调用get_api_domain_ip验证token有效性
402
+ - 如果验证失败,重新获取并更新缓存
403
+ 5. 更新实例的access_token属性
404
+
405
+ Args:
406
+ gettoken_func_kwargs: gettoken方法的额外参数
407
+ get_api_domain_ip_func_kwargs: get_api_domain_ip方法的额外参数
408
+ cache_config: 缓存配置字典,包含:
409
+ - instance: 缓存实例(diskcache.Cache或redis.Redis)
410
+ - key: 缓存键名,默认为"pywecom_server_{corpid}_{agentid}"
411
+ - expire: 缓存过期时间,默认为7100秒(小于7200秒官方有效期)
412
+
413
+ Returns:
414
+ Base: 返回self,支持链式调用
415
+
416
+ 代码演示:
417
+ >>> from py_wecom_toolkit.server import Base
418
+ >>> import diskcache
419
+ >>> # 创建带缓存的实例
420
+ >>> cache = diskcache.Cache("./cache")
421
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret",
422
+ ... cache_config={"instance": cache})
423
+ >>> server.refresh_access_token()
424
+ >>> print(server.access_token)
425
+ """
426
+ gettoken_func_kwargs = gettoken_func_kwargs or {}
427
+ get_api_domain_ip_func_kwargs = get_api_domain_ip_func_kwargs or {}
428
+ cache_config = cache_config or {}
429
+ # 合并实例缓存配置与调用时的缓存配置,调用时配置优先
430
+ cache_config = {
431
+ **self.cache_config,
432
+ **cache_config,
433
+ }
434
+ cache_key = cache_config.get("key", f"pywecom_server_{self.corpid}_{self.agentid}")
435
+ cache_expire = cache_config.get("expire", 7100)
436
+ cache_inst = cache_config.get("instance", None)
437
+
438
+ # 【逻辑分支1】未配置缓存实例,直接获取token
439
+ if not isinstance(cache_inst, Union[diskcache.Cache, redis.Redis]):
440
+ response = self.gettoken(**gettoken_func_kwargs)
441
+ if success_is_valid(response):
442
+ self.access_token = response.json().get("access_token", None)
443
+ else:
444
+ # 【逻辑分支2】配置了缓存实例,优先使用缓存
445
+ # 从缓存获取access_token
446
+ self.access_token = cache_inst.get(cache_key)
447
+ # 如果缓存中没有有效token,重新获取
448
+ if not isinstance(self.access_token, str) or not len(self.access_token):
449
+ response = self.gettoken(**gettoken_func_kwargs)
450
+ if success_is_valid(response):
451
+ self.access_token = response.json().get("access_token", None)
452
+ # 根据缓存类型设置缓存
453
+ if isinstance(cache_inst, diskcache.Cache):
454
+ cache_inst.set(cache_key, self.access_token, expire=cache_expire)
455
+ if isinstance(cache_inst, redis.Redis):
456
+ cache_inst.set(cache_key, self.access_token, ex=cache_expire)
457
+
458
+ # 【验证机制】调用get_api_domain_ip验证token有效性
459
+ response = self.get_api_domain_ip(**get_api_domain_ip_func_kwargs)
460
+ if not success_is_valid(response):
461
+ # token失效,重新获取并更新缓存
462
+ response = self.gettoken(**gettoken_func_kwargs)
463
+ if success_is_valid(response):
464
+ self.access_token = response.json().get("access_token", None)
465
+ if isinstance(cache_inst, diskcache.Cache):
466
+ cache_inst.set(cache_key, self.access_token, expire=cache_expire)
467
+ if isinstance(cache_inst, redis.Redis):
468
+ cache_inst.set(cache_key, self.access_token, ex=cache_expire)
469
+
470
+ return self
471
+
472
+ async def async_refresh_access_token(
473
+ self,
474
+ gettoken_func_kwargs: Optional[dict] = None,
475
+ get_api_domain_ip_func_kwargs: Optional[dict] = None,
476
+ cache_config: Optional[dict] = None,
477
+ ) -> "Base":
478
+ """
479
+ 异步刷新access_token
480
+
481
+ 获取并更新access_token,支持使用diskcache或Redis进行缓存,减少API调用次数。
482
+
483
+ 逻辑流程:
484
+ 1. 合并缓存配置(实例配置与调用时配置)
485
+ 2. 判断是否配置了缓存实例(diskcache.Cache或redis.Redis)
486
+ 3. 如果未配置缓存:直接调用async_gettoken获取access_token
487
+ 4. 如果配置了缓存:
488
+ - 优先从缓存获取access_token
489
+ - 如果缓存中没有或无效,调用async_gettoken获取并写入缓存
490
+ - 调用async_get_api_domain_ip验证token有效性
491
+ - 如果验证失败,重新获取并更新缓存
492
+ 5. 更新实例的access_token属性
493
+
494
+ Args:
495
+ gettoken_func_kwargs: async_gettoken方法的额外参数
496
+ get_api_domain_ip_func_kwargs: async_get_api_domain_ip方法的额外参数
497
+ cache_config: 缓存配置字典,包含:
498
+ - instance: 缓存实例(diskcache.Cache或redis.Redis)
499
+ - key: 缓存键名,默认为"pywecom_server_{corpid}_{agentid}"
500
+ - expire: 缓存过期时间,默认为7100秒
501
+
502
+ Returns:
503
+ Base: 返回self,支持链式调用
504
+
505
+ 代码演示:
506
+ >>> import asyncio
507
+ >>> from py_wecom_toolkit.server import Base
508
+ >>> import redis
509
+ >>> # 创建带Redis缓存的实例
510
+ >>> r = redis.Redis(host='localhost', port=6379, db=0)
511
+ >>> server = Base(corpid="your_corpid", corpsecret="your_corpsecret",
512
+ ... cache_config={"instance": r})
513
+ >>> await server.async_refresh_access_token()
514
+ >>> print(server.access_token)
515
+ """
516
+ gettoken_func_kwargs = gettoken_func_kwargs or {}
517
+ get_api_domain_ip_func_kwargs = get_api_domain_ip_func_kwargs or {}
518
+ cache_config = cache_config or {}
519
+ # 合并实例缓存配置与调用时的缓存配置,调用时配置优先
520
+ cache_config = {
521
+ **self.cache_config,
522
+ **cache_config,
523
+ }
524
+ cache_key = cache_config.get("key", f"pywecom_server_{self.corpid}_{self.agentid}")
525
+ cache_expire = cache_config.get("expire", 7100)
526
+ cache_inst = cache_config.get("instance", None)
527
+
528
+ # 【逻辑分支1】未配置缓存实例,直接获取token
529
+ if not isinstance(cache_inst, Union[diskcache.Cache, redis.Redis]):
530
+ response = await self.async_gettoken(**gettoken_func_kwargs)
531
+ if success_is_valid(response):
532
+ self.access_token = response.json().get("access_token", None)
533
+ if isinstance(cache_inst, diskcache.Cache):
534
+ cache_inst.set(cache_key, self.access_token, expire=cache_expire)
535
+ if isinstance(cache_inst, redis.Redis):
536
+ cache_inst.set(cache_key, self.access_token, ex=cache_expire)
537
+ else:
538
+ # 【逻辑分支2】配置了缓存实例,优先使用缓存
539
+ # 从缓存获取access_token
540
+ self.access_token = cache_inst.get(cache_key)
541
+ # 如果缓存中没有有效token,重新获取
542
+ if not isinstance(self.access_token, str) or not len(self.access_token):
543
+ response = await self.async_gettoken(**gettoken_func_kwargs)
544
+ if success_is_valid(response):
545
+ self.access_token = response.json().get("access_token", None)
546
+
547
+ # 【验证机制】调用async_get_api_domain_ip验证token有效性
548
+ response = await self.async_get_api_domain_ip(**get_api_domain_ip_func_kwargs)
549
+ if not success_is_valid(response):
550
+ # token失效,重新获取并更新缓存
551
+ response = await self.async_gettoken(**gettoken_func_kwargs)
552
+ if success_is_valid(response):
553
+ self.access_token = response.json().get("access_token", None)
554
+ if isinstance(cache_inst, diskcache.Cache):
555
+ cache_inst.set(cache_key, self.access_token, expire=cache_expire)
556
+ if isinstance(cache_inst, redis.Redis):
557
+ cache_inst.set(cache_key, self.access_token, ex=cache_expire)
558
+
559
+ return self