nonebot-plugin-l4d2-server 1.0.3__py3-none-any.whl → 1.0.5__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.
@@ -24,10 +24,11 @@ from nonebot.adapters import Message
24
24
  from nonebot.log import logger
25
25
  from nonebot.matcher import Matcher
26
26
  from nonebot.params import CommandArg, CommandStart, RawCommand
27
+ from nonebot.permission import SUPERUSER
27
28
  from nonebot.plugin import on_command
28
29
  from nonebot_plugin_alconna import UniMessage
29
30
 
30
- from .config import config
31
+ from .config import config, config_manager
31
32
  from .l4_help import get_l4d2_core_help
32
33
  from .l4_local import * # noqa: F403
33
34
  from .l4_request import (
@@ -39,13 +40,14 @@ from .l4_request import (
39
40
  tj_request,
40
41
  )
41
42
  from .utils.api.request import L4API
43
+ from .utils.api.utils import out_msg_out
42
44
 
43
45
  if TYPE_CHECKING:
44
46
  from .utils.api.models import OutServer
45
47
 
46
48
  reload_ip()
47
49
 
48
- l4_help = on_command("l4help", aliases={"l4帮助", "l4d2帮助"})
50
+ l4_help = on_command("l4help", aliases={"l4d2帮助"})
49
51
  l4_request = on_command("anne", aliases=COMMAND, priority=10)
50
52
  l4_reload = on_command("l4reload", aliases={"l4刷新,l4重载"})
51
53
  l4_all = on_command("l4all", aliases={"l4全服"})
@@ -59,13 +61,11 @@ config_path = Path(config.l4_path) / "config.json"
59
61
 
60
62
 
61
63
  @l4_help.handle()
62
- async def _(matcher: Matcher):
64
+ async def _():
63
65
  """帮助"""
64
66
  logger.info("开始执行[l4d2帮助]")
65
67
  im = await get_l4d2_core_help()
66
- if isinstance(im, str):
67
- await matcher.finish(im)
68
- await UniMessage.image(raw=im).send()
68
+ await out_msg_out(im)
69
69
 
70
70
 
71
71
  @l4_request.handle()
@@ -74,11 +74,31 @@ async def _(
74
74
  command: str = RawCommand(),
75
75
  args: Message = CommandArg(),
76
76
  ):
77
- """例:
78
- 指令: /橘5
79
- start: /(command开头指令)
80
- command: /橘(响应的全部指令)
81
- args: 5(响应的指令后的数字)
77
+ """
78
+ 异步函数,用于处理特定的指令。
79
+
80
+ Args:
81
+ start (str, optional): 指令的开头部分,默认为 CommandStart() 返回的值。
82
+ command (str, optional): 完整的指令字符串,默认为 RawCommand() 返回的值。
83
+ args (Message, optional): 指令后的参数,默认为 CommandArg() 返回的值。
84
+
85
+ Returns:
86
+ None
87
+
88
+ Examples:
89
+ 示例指令:"/橘5"
90
+ - start: "/" (指令的开头部分)
91
+ - command: "/橘" (完整的指令字符串)
92
+ - args: "5" (指令后的参数)
93
+
94
+ Notes:
95
+ 1. 如果 start 存在,会将 command 中的 start 部分替换为空字符串。
96
+ 2. 如果 command 等于 "anne",则将其替换为 "云"。
97
+ 3. 提取 args 中的纯文本内容,如果内容非空且不是数字,则返回。
98
+ 4. 如果 args 为空,则将其设置为 None。
99
+ 5. 使用 logger 记录处理过程中的信息。
100
+ 6. 调用 get_server_detail 函数获取服务器详情,并根据返回结果发送相应的消息。
101
+ 7. 如果 get_server_detail 返回 None,则发送 "服务器无响应" 的文本消息。
82
102
  """
83
103
 
84
104
  if start:
@@ -92,13 +112,15 @@ async def _(
92
112
  _id = None
93
113
  logger.info(f"组:{command} ;数字:{_id}")
94
114
  msg = await get_server_detail(command, _id)
95
- if msg is not None:
96
- if isinstance(msg, str):
97
- await UniMessage.text(msg).finish()
98
- if isinstance(msg, bytes):
99
- await UniMessage.image(raw=msg).finish()
100
- else:
101
- await UniMessage.text("服务器无响应").finish()
115
+ if msg is None:
116
+ await out_msg_out("服务器无响应")
117
+ return
118
+ if _id is None:
119
+ logger.info(f"正在输出组:{command}")
120
+ await out_msg_out(msg)
121
+ if _id:
122
+ logger.info(f"正在输出单服务器:{command} {_id}", is_connect=config.l4_image)
123
+ await out_msg_out(msg)
102
124
 
103
125
 
104
126
  @l4_find_player.handle()
@@ -120,48 +142,41 @@ async def _(
120
142
  if len(tag_list) == 2:
121
143
  group, name = tag_list
122
144
  await UniMessage.text(f"正在查询{group}组").send()
123
- out: List[OutServer] = await get_server_detail(group, is_img=False) # type: ignore
145
+ out: List[OutServer] = await get_server_detail(group=group, is_img=False) # type: ignore
124
146
  out_msg = "未找到玩家"
125
147
  for one in out:
126
148
  for player in one["player"]:
127
149
  if name in player.name:
128
150
  out_msg = await get_ip_server(f"{one['host']}:{one['port']}")
129
151
 
130
- return await UniMessage.text(out_msg).finish()
152
+ return await out_msg_out(out_msg)
131
153
 
132
154
 
133
155
  @l4_all.handle()
134
156
  async def _():
135
- await UniMessage.text(await get_all_server_detail()).finish()
157
+ await out_msg_out(await get_all_server_detail())
136
158
 
137
159
 
138
160
  @l4_connect.handle()
139
161
  async def _(args: Message = CommandArg()):
140
162
  ip: Optional[str] = args.extract_plain_text()
141
163
  if ip is not None:
142
- await UniMessage.text(await get_ip_server(ip)).finish()
143
-
144
-
145
- # anne部分
146
- if config.l4_anne:
147
- logger.info("加载anne功能")
148
- from .l4_anne import * # noqa: F403
164
+ await out_msg_out(await get_ip_server(ip), is_connect=config.l4_image)
149
165
 
150
166
 
151
167
  @l4_reload.handle()
152
168
  async def _(args: Message = CommandArg()):
153
169
  arg = args.extract_plain_text().strip()
154
- print(arg)
155
170
  if not arg:
156
171
  reload_ip()
157
172
  logger.success("重载ip完成")
158
- with (Path(config.l4_path) / "config.json").open("r", encoding="utf-8") as f:
173
+ with (Path(config.l4_path) / "l4d2.json").open("r", encoding="utf-8") as f:
159
174
  content = f.read().strip()
160
175
  ip_json = json.loads(content)
161
176
  for tag, url in ip_json.items():
162
177
  logger.info(f"重载{tag}的ip")
163
178
  await L4API.get_sourceban(tag, url)
164
- await UniMessage.text("重载ip完成").finish()
179
+ await out_msg_out("重载ip完成")
165
180
 
166
181
 
167
182
  l4_add_ban = on_command("l4addban", aliases={"l4添加ban"})
@@ -192,7 +207,7 @@ async def _(args: Message = CommandArg()):
192
207
  await UniMessage.text(f"文件写入失败: {e}").finish()
193
208
 
194
209
  await L4API.get_sourceban(arg[0], arg[1])
195
- await UniMessage.text(f"添加成功\n组名: {arg[0]}\n网址: {arg[1]}").finish()
210
+ await out_msg_out(f"添加成功\n组名: {arg[0]}\n网址: {arg[1]}")
196
211
 
197
212
 
198
213
  l4_del_ban = on_command("l4delban", aliases={"l4删除ban", "l4移除ban"})
@@ -219,7 +234,7 @@ async def _(args: Message = CommandArg()):
219
234
  del config_data[arg[0]]
220
235
  async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
221
236
  json.dump(config_data, f, ensure_ascii=False, indent=4)
222
- await UniMessage.text(f"删除成功,组名:{arg[0]}").finish()
237
+ await out_msg_out(f"删除成功,组名:{arg[0]}")
223
238
  elif len(arg) == 2:
224
239
  if not Path(Path(config.l4_path) / "config.json").is_file():
225
240
  await UniMessage.text("没有添加过组名").finish()
@@ -236,7 +251,7 @@ async def _(args: Message = CommandArg()):
236
251
  config_datas[arg[0]] = arg[1]
237
252
  async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
238
253
  json.dump(config_datas, f, ensure_ascii=False, indent=4)
239
- await UniMessage.text(f"修改成功,组名:{arg[0]},网址:{arg[1]}").finish()
254
+ await out_msg_out(f"修改成功,组名:{arg[0]},网址:{arg[1]}")
240
255
 
241
256
 
242
257
  @ld_tj.handle()
@@ -249,3 +264,21 @@ async def _(matcher: Matcher):
249
264
  async def _(matcher: Matcher):
250
265
  await matcher.send("正在寻找牢房信息")
251
266
  await matcher.finish(await tj_request("云", "zl"))
267
+
268
+
269
+ ## 以下为配置修改
270
+
271
+ img_trung = on_command("l4img", aliases={"l4图片"}, permission=SUPERUSER)
272
+
273
+
274
+ @img_trung.handle()
275
+ async def _(args: Message = CommandArg()):
276
+ arg = args.extract_plain_text().strip().lower()
277
+ if arg == "开启":
278
+ config_manager.update_image_config(enabled=True)
279
+ await out_msg_out("[l4]已开启图片模式")
280
+ elif arg == "关闭":
281
+ config_manager.update_image_config(enabled=False)
282
+ await out_msg_out("[l4]已关闭图片模式")
283
+ else:
284
+ await UniMessage.text("请在参数后加上开启或关闭").finish()
@@ -6,10 +6,10 @@ from pydantic import BaseModel
6
6
 
7
7
  DATAPATH = Path(__file__).parent.joinpath("data")
8
8
  DATAOUT = Path("data/L4D2")
9
+ DATAOUT.mkdir(parents=True, exist_ok=True)
9
10
  if not Path(DATAOUT / "l4d2.json").exists():
10
11
  logger.info("文件 l4d2.json 不存在,已创建并初始化为 {}")
11
12
  Path(DATAOUT / "l4d2.json").write_text("{}", encoding="utf-8")
12
- print(DATAOUT.absolute())
13
13
  server_all_path = DATAOUT / "l4d2"
14
14
  server_all_path.mkdir(parents=True, exist_ok=True)
15
15
 
@@ -20,11 +20,9 @@ map_index = 0
20
20
 
21
21
 
22
22
  class ConfigModel(BaseModel):
23
- l4_anne: bool = False
24
- """是否启用anne电信服相关功能"""
25
23
  l4_enable: bool = True
26
24
  """是否全局启用求生功能"""
27
- l4_image: bool = False
25
+ l4_image: bool = True
28
26
  """是否启用图片"""
29
27
  l4_connect: bool = True
30
28
  """是否在查服命令后加入connect ip"""
@@ -43,3 +41,54 @@ class ConfigModel(BaseModel):
43
41
 
44
42
 
45
43
  config = get_plugin_config(ConfigModel)
44
+
45
+
46
+ class ConfigManager:
47
+ """配置项管理类,提供类型安全的配置更新方法"""
48
+
49
+ def __init__(self):
50
+ self._config = config
51
+
52
+ def update_image_config(self, enabled: bool) -> None:
53
+ """更新图片配置
54
+
55
+ Args:
56
+ enabled: 是否启用图片功能
57
+ """
58
+ self._config.l4_image = enabled
59
+
60
+ def update_style_config(self, style: str) -> None:
61
+ """更新图片风格配置
62
+
63
+ Args:
64
+ style: 图片风格名称
65
+ """
66
+ if not isinstance(style, str):
67
+ raise TypeError("style必须是字符串")
68
+ self._config.l4_style = style
69
+
70
+ def update_connect_config(self, enabled: bool) -> None:
71
+ """更新connect ip配置
72
+
73
+ Args:
74
+ enabled: 是否在查服命令后加入connect ip
75
+ """
76
+ self._config.l4_connect = enabled
77
+
78
+ def update(self, **kwargs) -> None:
79
+ """通用配置更新方法
80
+
81
+ Args:
82
+ **kwargs: 要更新的配置项键值对
83
+
84
+ Raises:
85
+ ValueError: 当传入无效的配置项时
86
+ """
87
+ for key, value in kwargs.items():
88
+ if hasattr(self._config, key):
89
+ setattr(self._config, key, value)
90
+ else:
91
+ raise ValueError(f"无效的配置项: {key}")
92
+
93
+
94
+ config_manager = ConfigManager()
@@ -28,7 +28,7 @@
28
28
  },
29
29
  {
30
30
  "name": "l4全服",
31
- "desc": "返回可以查询的所有服务器组(未完成)",
31
+ "desc": "返回可以查询的所有服务器组",
32
32
  "eg": "/l4全服",
33
33
  "need_ck": false,
34
34
  "need_sk": false,
@@ -36,43 +36,6 @@
36
36
  }
37
37
  ]
38
38
  },
39
- "电信服anne服务": {
40
- "desc": "电信anne服相关服务",
41
- "data": [
42
- {
43
- "name": "Banne xx",
44
- "desc": "绑定昵称/steamid",
45
- "eg": "/Banne 爱丽数码",
46
- "need_ck": false,
47
- "need_sk": false,
48
- "need_admin": false
49
- },
50
- {
51
- "name": "Ranne(玩家)",
52
- "desc": "查询anne个人信息,没有参数查自己",
53
- "eg": "/Ranne 爱丽数码",
54
- "need_ck": false,
55
- "need_sk": false,
56
- "need_admin": false
57
- },
58
- {
59
- "name": "Sanne(玩家)",
60
- "desc": "按昵称查询anne玩家信息",
61
- "eg": "/Sanne 爱丽数码",
62
- "need_ck": false,
63
- "need_sk": false,
64
- "need_admin": false
65
- },
66
- {
67
- "name": "Danne(玩家)",
68
- "desc": "删除anne玩家信息",
69
- "eg": "/Danne 爱丽数码",
70
- "need_ck": false,
71
- "need_sk": false,
72
- "need_admin": false
73
- }
74
- ]
75
- },
76
39
  "管理员服务": {
77
40
  "desc": "管理可以使用的指令",
78
41
  "data": [
@@ -83,7 +46,7 @@
83
46
  "need_ck": false,
84
47
  "need_sk": false,
85
48
  "need_admin": true
86
- },
49
+ },
87
50
  {
88
51
  "name": "l4地图上传",
89
52
  "desc": "进入交互上传地图文件",
@@ -1,8 +1,8 @@
1
+ import json
1
2
  from pathlib import Path
2
3
  from typing import Dict, Union
3
4
 
4
5
  import aiofiles
5
- from msgspec import json as msgjson
6
6
  from PIL import Image
7
7
 
8
8
  from ..config import ICONPATH
@@ -10,18 +10,16 @@ from ..l4_image.convert import core_font
10
10
  from ..l4_image.model import PluginHelp
11
11
  from .draw import get_help
12
12
 
13
- __version__ = "1.0.3"
13
+ __version__ = "1.0.5"
14
14
  TEXT_PATH = Path(__file__).parent / "texture2d"
15
15
  HELP_DATA = Path(__file__).parent / "Help.json"
16
16
 
17
17
 
18
18
  async def get_help_data() -> Union[Dict[str, PluginHelp], None]:
19
19
  if HELP_DATA.exists():
20
- async with aiofiles.open(HELP_DATA, "rb") as file:
21
- return msgjson.decode(
22
- await file.read(),
23
- type=Dict[str, PluginHelp],
24
- )
20
+ async with aiofiles.open(HELP_DATA, "r", encoding="utf-8") as file:
21
+ content = await file.read()
22
+ return json.loads(content)
25
23
  return None
26
24
 
27
25
 
@@ -45,7 +45,7 @@ async def server_ip_pic(server_dict: List[OutServer]):
45
45
  key=lambda x: x.score,
46
46
  reverse=True,
47
47
  )[:max_number]
48
- print(sorted_players)
48
+ logger.debug(sorted_players)
49
49
  server_info["player"] = sorted_players
50
50
  else:
51
51
  server_info["player"] = []
@@ -47,7 +47,6 @@ else:
47
47
  async def _():
48
48
  supath = local_path[map_index] / "addons"
49
49
  vpk_list: list[str] = []
50
- print(supath)
51
50
  if supath.is_dir():
52
51
  for sudir in supath.iterdir():
53
52
  logger.info(f"找到文件:{sudir}")
@@ -2,20 +2,28 @@ import random
2
2
  from typing import Dict, List, Optional, cast
3
3
 
4
4
  from nonebot.log import logger
5
+ from nonebot_plugin_alconna import UniMessage
5
6
 
6
- from ..config import server_all_path
7
- from ..l4_image import msg_to_image
8
- from ..utils.api.models import AllServer, NserverOut, OutServer
7
+ from ..config import config, server_all_path
8
+ from ..utils.api.models import AllServer, NserverOut
9
9
  from ..utils.api.request import L4API
10
10
  from ..utils.utils import split_maohao
11
- from .draw_msg import convert_duration, draw_one_ip, get_much_server
11
+ from .draw_msg import draw_one_ip, get_much_server
12
+ from .utils import (
13
+ _build_message,
14
+ _filter_servers,
15
+ _format_players,
16
+ _get_server_json,
17
+ _handle_group_info,
18
+ _handle_single_server,
19
+ get_single_server_info,
20
+ )
12
21
 
13
22
  try:
14
23
  import ujson as json
15
24
  except ImportError:
16
25
  import json
17
26
 
18
- from ..config import config
19
27
 
20
28
  # 获取全部服务器信息
21
29
  ALLHOST: Dict[str, List[NserverOut]] = {}
@@ -79,52 +87,43 @@ async def get_server_detail(
79
87
  command (str): 服务器组名。
80
88
  _id (Optional[str], optional): 服务器ID。默认为None。
81
89
  is_img (bool, optional): 是否返回图片格式的信息。默认为True。
90
+ return_host_port (bool, optional): 是否返回host和port值。默认为False。
82
91
 
83
92
  Returns:
84
- Union[bytes, List[OutServer], None]: 返回服务器详细信息。如果为图片格式,返回bytes类型;
85
- 如果不是图片格式,返回List[OutServer]类型;如果未找到服务器组,返回None
86
-
93
+ Union[bytes, str, None, Tuple[str, int]]:
94
+ 如果return_host_port为True且_id不为None,返回(host, port)元组;
95
+ 否则返回服务器详细信息(图片格式返回bytes,文本格式返回str);
96
+ 未找到服务器组返回None。
87
97
  """
88
- if command:
89
- server_json = ALLHOST.get(command)
90
- else:
91
- server_json = []
92
- for servers in ALLHOST.values():
93
- server_json.extend(servers)
94
-
98
+ server_json = _get_server_json(command, ALLHOST)
95
99
  logger.info(server_json)
96
100
  if server_json is None:
97
101
  logger.warning("未找到这个组")
98
102
  return None
99
103
 
104
+ # 输出组服务器
100
105
  if _id is None:
101
- # 输出组信息
102
- logger.info(f"正在请求组服务器信息 {command}")
103
- server_dict = await get_much_server(server_json, command)
104
- if is_img:
105
- out_msg = await msg_to_image(server_dict)
106
- else:
107
- out_msg = server_dict
108
- return out_msg
106
+ return await _handle_group_info(server_json, command, is_img)
109
107
 
110
- # 返回单个
111
- logger.info("正在请求单服务器信息")
112
- out_msg = ""
113
- for i in server_json:
114
- if str(_id) == str(i["id"]):
115
- out_msg = await draw_one_ip(i["host"], i["port"])
116
- if is_img:
117
- return cast(bytes, out_msg)
118
- if not is_img:
119
- return cast(List[OutServer], out_msg)
120
- # print(out_msg)
108
+ _ip = await get_single_server_info(server_json, _id)
109
+ if _ip is None:
110
+ logger.warning("未找到这个服务器")
111
+ return None
112
+
113
+ out_msg = await _handle_single_server(server_json, _id, is_img)
114
+ if isinstance(out_msg, bytes):
115
+ return UniMessage.image(raw=out_msg) + UniMessage.text(
116
+ f"connect {_ip[0]}:{_ip[1]}",
117
+ )
118
+ if isinstance(out_msg, str):
119
+ return UniMessage.text(out_msg)
121
120
  return None
122
121
 
123
122
 
124
123
  async def get_group_detail(
125
124
  command: str,
126
125
  ):
127
- server_json = ALLHOST.get(command)
126
+ server_json = _get_server_json(command, ALLHOST)
128
127
  logger.info(server_json)
129
128
  if server_json is None:
130
129
  logger.warning("未找到这个组")
@@ -142,7 +141,6 @@ async def get_ip_server(ip: str):
142
141
  # 以下是重载ip
143
142
  def reload_ip():
144
143
  global COMMAND
145
- # print("正在读取json文件")
146
144
  group_ip = []
147
145
  for item in server_all_path.iterdir():
148
146
  if item.is_file() and item.name.endswith("json"):
@@ -186,74 +184,8 @@ async def tj_request(command: str = "云", tj="tj"):
186
184
  player_msg = ""
187
185
  right_ip = []
188
186
 
189
- async def _filter_servers(servers: list, tj_mode: str) -> list:
190
- """筛选符合条件的服务器
191
- Args:
192
- servers: 服务器列表
193
- tj_mode: 筛选模式('tj'或'zl')
194
- Returns:
195
- 符合条件的服务器列表
196
- """
197
- filtered = []
198
- for i in servers:
199
- ser_list = await L4API.a2s_info([(i["host"], i["port"])], is_player=True)
200
- if not ser_list:
201
- continue
202
-
203
- srv = ser_list[0][0]
204
- players = ser_list[0][1]
205
-
206
- if tj_mode == "tj" and map_type in srv.map_name:
207
- score = sum(p.score for p in players[:4])
208
- t = srv.map_name.split("[")[-1].split("特")[0]
209
- if t.isdigit() and int(t) * 50 < score:
210
- logger.info(
211
- f"符合TJ条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 分数: {score}",
212
- )
213
- filtered.append(i)
214
- elif tj_mode == "zl" and map_type in srv.map_name and len(players) <= 4:
215
- logger.info(
216
- f"符合ZL条件的服务器: {i['host']}:{i['port']}, 地图: {srv.map_name}, 玩家数: {len(players)}",
217
- )
218
- filtered.append(i)
219
- return filtered
220
-
221
- async def _format_players(player_list: list) -> str:
222
- """格式化玩家信息
223
- Args:
224
- player_list: 玩家对象列表
225
- Returns:
226
- 格式化后的玩家信息字符串
227
- """
228
- durations = [await convert_duration(p.duration) for p in player_list]
229
- max_duration_len = max(len(str(d)) for d in durations)
230
- max_score_len = max(len(str(p.score)) for p in player_list)
231
- return "\n".join(
232
- f"[{p.score:>{max_score_len}}] | {durations[i]:^{max_duration_len}} | {p.name[0]}***{p.name[-1]}"
233
- for i, p in enumerate(player_list)
234
- )
235
-
236
- def _build_message(srv_info, players_msg: str, selected_srv: dict) -> str:
237
- """构建服务器信息消息
238
- Args:
239
- srv_info: 服务器信息对象
240
- players_msg: 格式化后的玩家信息
241
- selected_srv: 选中的服务器信息
242
- Returns:
243
- 完整的消息字符串
244
- """
245
- msg = f"""*{srv_info.server_name}*
246
- 游戏: {srv_info.folder}
247
- 地图: {srv_info.map_name}
248
- 人数: {srv_info.player_count}/{srv_info.max_players}"""
249
- if srv_info.ping is not None:
250
- msg += f"\nping: {srv_info.ping * 1000:.0f}ms\n{players_msg}"
251
- if config.l4_show_ip:
252
- msg += f"\nconnect {selected_srv['host']}:{selected_srv['port']}"
253
- return msg
254
-
255
187
  try:
256
- right_ip = await _filter_servers(server_json, tj)
188
+ right_ip = await _filter_servers(server_json, tj, map_type)
257
189
 
258
190
  if not right_ip:
259
191
  logger.warning("没有找到符合条件的服务器")
@@ -276,7 +208,7 @@ async def tj_request(command: str = "云", tj="tj"):
276
208
  else:
277
209
  player_msg = "服务器感觉很安静啊"
278
210
 
279
- return _build_message(one_server, player_msg, s)
211
+ return _build_message(one_server, player_msg, s, config)
280
212
 
281
213
  except Exception as e:
282
214
  logger.error(f"tj_request error: {e}")