Lib.utils.QQDataCacher
QQ数据缓存
1""" 2QQ数据缓存 3""" 4import time 5import threading 6 7from ..core import OnebotAPI, ConfigManager 8from . import Logger 9 10NotFetched = type("NotFetched", (), {"__getattr__": lambda _, __: NotFetched, 11 "__repr__": lambda _: "NotFetched", 12 "__bool__": lambda _: False}) 13api = OnebotAPI.api 14logger = Logger.get_logger() 15 16if ConfigManager.GlobalConfig().qq_data_cache.enable: 17 expire_time = ConfigManager.GlobalConfig().qq_data_cache.expire_time 18else: 19 expire_time = 0 20 21 22class QQDataItem: 23 """ 24 QQ数据缓存类 25 """ 26 27 def __init__(self): 28 self._data = NotFetched # 数据 29 self.last_update = time.time() # 最后刷新时间 30 self.last_use = -1 # 最后被使用时间(数据被使用) 31 32 def refresh_cache(self): 33 """ 34 刷新缓存 35 Returns: 36 None 37 """ 38 self.last_update = time.time() 39 40 41class UserData(QQDataItem): 42 """ 43 QQ用户数据缓存类 44 """ 45 46 def __init__( 47 self, 48 user_id: int, 49 nickname: str = NotFetched, 50 sex: str = NotFetched, 51 age: int = NotFetched, 52 is_friend: bool = NotFetched, 53 remark: str | None = NotFetched # 此值仅在是好友的时候会存在 54 ): 55 super().__init__() 56 self._user_id = user_id 57 self._data = { 58 "user_id": user_id, 59 "nickname": nickname, 60 "sex": sex, 61 "age": age, 62 "is_friend": is_friend, 63 "remark": remark 64 } 65 66 def refresh_cache(self): 67 """ 68 刷新缓存 69 Returns: 70 None 71 """ 72 if int(self._user_id) <= 0: 73 logger.warn(f"获取用户{self._user_id}缓存信息失败: user_id小于等于0") 74 return 75 try: 76 data = api.get_stranger_info(self._user_id) 77 for k in data: 78 self._data[k] = data[k] 79 self._data["is_friend"] = NotFetched 80 self._data["remark"] = NotFetched 81 except Exception as e: 82 logger.warn(f"获取用户{self._user_id}缓存信息失败: {repr(e)}") 83 return 84 85 def __getattr__(self, item): 86 if item == "_data" or item == "data": 87 return self._data 88 89 if item in ["remark", "is_friend"] and self._data.get(item) != NotFetched: 90 try: 91 res = api.get_friend_list() 92 for friend in res: 93 if friend["user_id"] == self._user_id: 94 self._data["remark"] = friend["remark"] 95 self._data["is_friend"] = True 96 break 97 else: 98 self._data["is_friend"] = False 99 self._data["remark"] = None 100 except Exception as e: 101 logger.warn(f"获取用户{self._user_id}是否为好友失败: {repr(e)}") 102 return None 103 104 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 105 self.refresh_cache() 106 107 if self._data.get(item) == NotFetched: 108 return None 109 110 if item in self._data: 111 self.last_use = time.time() 112 113 return self._data.get(item) 114 115 def get_nickname(self) -> str: 116 """ 117 获取昵称(如果有备注名优先返回备注名) 118 Returns: 119 昵称 120 """ 121 return self.remark or self.nickname 122 123 def __repr__(self): 124 return f"UserData(user_id={self._user_id})" 125 126 127class GroupMemberData(QQDataItem): 128 """ 129 QQ群成员数据缓存类 130 """ 131 132 def __init__( 133 self, 134 group_id: int, 135 user_id: int, 136 nickname: str = NotFetched, 137 card: str = NotFetched, 138 sex: str = NotFetched, 139 age: int = NotFetched, 140 area: str = NotFetched, 141 join_time: int = NotFetched, 142 last_sent_time: int = NotFetched, 143 level: str = NotFetched, 144 role: str = NotFetched, 145 unfriendly: bool = NotFetched, 146 title: str = NotFetched, 147 title_expire_time: int = NotFetched, 148 card_changeable: bool = NotFetched, 149 ): 150 super().__init__() 151 self._group_id = group_id 152 self._user_id = user_id 153 self._data = { 154 "group_id": group_id, 155 "user_id": user_id, 156 "nickname": nickname, 157 "card": card, 158 "sex": sex, 159 "age": age, 160 "area": area, 161 "join_time": join_time, 162 "last_sent_time": last_sent_time, 163 "level": level, 164 "role": role, 165 "unfriendly": unfriendly, 166 "title": title, 167 "title_expire_time": title_expire_time, 168 "card_changeable": card_changeable, 169 } 170 171 def refresh_cache(self): 172 """ 173 刷新缓存 174 Returns: 175 None 176 """ 177 if int(self._group_id) <= 0 or int(self._user_id) <= 0: 178 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: group_id或user_id小于等于0") 179 return 180 try: 181 data = api.get_group_member_info(self._group_id, self._user_id, no_cache=True) 182 for k in data: 183 self._data[k] = data[k] 184 except Exception as e: 185 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: {repr(e)}") 186 user_data = get_user_info(self._user_id) 187 self._data["nickname"] = user_data.nickname if user_data.nickname else NotFetched 188 self._data["sex"] = user_data.sex if user_data.sex else NotFetched 189 self._data["age"] = user_data.age if user_data.age else NotFetched 190 super().refresh_cache() 191 192 def __getattr__(self, item): 193 if item == "_data" or item == "data": 194 return self._data 195 196 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 197 self.refresh_cache() 198 199 if self._data.get(item) == NotFetched: 200 return None 201 202 if item in self._data: 203 self.last_use = time.time() 204 205 return self._data.get(item) 206 207 def __repr__(self): 208 return f"GroupMemberData(group_id={self._group_id}, user_id={self._user_id})" 209 210 def get_nickname(self): 211 """ 212 获取群名片(如果有群名片优先返回群名片) 213 Returns: 214 群名片 215 """ 216 return self.card or self.nickname 217 218 219class GroupData(QQDataItem): 220 """ 221 QQ群数据缓存类 222 """ 223 224 def __init__( 225 self, 226 group_id: int, 227 group_name: str = NotFetched, 228 member_count: int = NotFetched, 229 max_member_count: int = NotFetched 230 ): 231 super().__init__() 232 self._group_id = group_id 233 self._data = { 234 "group_id": group_id, 235 "group_name": group_name, 236 "member_count": member_count, 237 "max_member_count": max_member_count, 238 "group_member_list": NotFetched 239 } 240 241 def refresh_cache(self): 242 """ 243 刷新缓存 244 Returns: 245 None 246 """ 247 if int(self._group_id) <= 0: 248 logger.warn(f"获取群{self._group_id}缓存信息失败: group_id小于等于0") 249 return 250 try: 251 data = api.get_group_info(group_id=self._group_id, no_cache=True) 252 for k in data: 253 self._data[k] = data[k] 254 self._data["group_member_list"] = NotFetched 255 except Exception as e: 256 logger.warn(f"获取群{self._group_id}缓存信息失败: {repr(e)}") 257 return 258 super().refresh_cache() 259 260 def __getattr__(self, item): 261 if item == "_data" or item == "data": 262 return self._data 263 264 if item == "group_member_list" and self._data.get(item) == NotFetched: 265 try: 266 res = api.get_group_member_list(self._group_id) 267 member_list = [GroupMemberData(**{k: (v if v is not None else NotFetched) 268 for k, v in member.items()}) 269 for member in res] 270 self._data[item] = member_list 271 except Exception as e: 272 logger.warn(f"获取群{self._group_id}成员列表信息失败: {repr(e)}") 273 return 274 275 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 276 self.refresh_cache() 277 278 if self._data.get(item) == NotFetched: 279 return None 280 281 if item in self._data: 282 self.last_use = time.time() 283 284 return self._data.get(item) 285 286 def __repr__(self): 287 return f"GroupData(group_id={self._group_id})" 288 289 290group_info = {} 291group_member_info = {} 292user_info = {} 293 294group_info_lock = threading.Lock() 295group_member_info_lock = threading.Lock() 296user_info_lock = threading.Lock() 297 298max_cache_size = ConfigManager.GlobalConfig().qq_data_cache.max_cache_size 299expire_time = expire_time 300 301 302def get_user_info(user_id: int, *args, **kwargs) -> UserData: 303 """ 304 获取用户信息 305 Args: 306 user_id: 用户ID 307 Returns: 308 None 309 """ 310 with user_info_lock: 311 if user_id not in user_info: 312 data = UserData(user_id, *args, **kwargs) 313 user_info[user_id] = data 314 315 data = user_info[user_id] 316 return data 317 318 319def get_group_info(group_id: int, *args, **kwargs) -> GroupData: 320 """ 321 获取群信息 322 Args: 323 group_id: 群号 324 Returns: 325 None 326 """ 327 with group_info_lock: 328 if group_id not in group_info: 329 data = GroupData(group_id, *args, **kwargs) 330 group_info[group_id] = data 331 332 data = group_info[group_id] 333 return data 334 335 336def get_group_member_info(group_id: int, user_id: int, *args, **kwargs) -> GroupMemberData: 337 """ 338 获取群成员信息 339 Args: 340 group_id: 群号 341 user_id: 用户ID 342 Returns: 343 None 344 """ 345 with group_member_info_lock: 346 if group_id not in group_member_info: 347 group_member_info[group_id] = {} 348 349 if user_id not in group_member_info[group_id]: 350 data = GroupMemberData(group_id, user_id, *args, **kwargs) 351 group_member_info[group_id][user_id] = data 352 353 data = group_member_info[group_id][user_id] 354 return data 355 356 357def garbage_collection(): 358 """ 359 垃圾回收 360 Returns: 361 None 362 """ 363 counter = 0 364 365 with group_member_info_lock: 366 for k in list(group_member_info.keys()): 367 group_member_items = list(zip(group_member_info[k].keys(), group_member_info[k].values())) 368 max_last_use_time = max([item[1].last_use for item in group_member_items]) 369 370 if max_last_use_time < time.time() - expire_time * 2: 371 del group_member_info[k] 372 counter += 1 373 continue 374 375 group_member_items.sort(key=lambda x: x[1].last_use) 376 if len(group_member_items) > max_cache_size * (2 / 3): 377 for user_id, _ in group_member_items[:int(max_cache_size * (1 / 3))]: 378 del group_member_info[k][user_id] 379 counter += 1 380 del group_member_items, max_last_use_time 381 382 with group_info_lock: 383 group_items = list(zip(group_info.keys(), group_info.values())) 384 group_items.sort(key=lambda x: x[1].last_use) 385 if len(group_items) > max_cache_size * (2 / 3): 386 for group_id, _ in group_items[:int(max_cache_size * (1 / 3))]: 387 del group_info[group_id] 388 counter += 1 389 del group_items 390 391 with user_info_lock: 392 user_items = list(zip(user_info.keys(), user_info.values())) 393 user_items.sort(key=lambda x: x[1].last_use) 394 if len(user_items) > max_cache_size * (2 / 3): 395 for user_id, _ in user_items[:int(max_cache_size * (1 / 3))]: 396 del user_info[user_id] 397 counter += 1 398 del user_items 399 400 return counter 401 402 403def scheduled_garbage_collection(): 404 """ 405 定时垃圾回收 406 Returns: 407 None 408 """ 409 t = 0 410 while True: 411 time.sleep(60) 412 t += 1 413 if ( 414 t > 4 or ( 415 t > 1 and ( 416 len(group_info) > max_cache_size or 417 len(user_info) > max_cache_size or 418 len(group_member_info) > max_cache_size 419 ) 420 ) 421 ): 422 t = 0 423 logger.debug("QQ数据缓存清理开始...") 424 try: 425 counter = garbage_collection() 426 logger.debug(f"QQ数据缓存清理完成,共清理了 {counter} 项信息。") 427 except Exception as e: 428 logger.warn(f"QQ数据缓存清理时出现异常: {repr(e)}") 429 430 431# 启动垃圾回收线程 432threading.Thread(target=scheduled_garbage_collection, daemon=True).start()
class
NotFetched:
api =
<Lib.core.OnebotAPI.OnebotAPI object>
logger =
<RootLogger root (INFO)>
class
QQDataItem:
23class QQDataItem: 24 """ 25 QQ数据缓存类 26 """ 27 28 def __init__(self): 29 self._data = NotFetched # 数据 30 self.last_update = time.time() # 最后刷新时间 31 self.last_use = -1 # 最后被使用时间(数据被使用) 32 33 def refresh_cache(self): 34 """ 35 刷新缓存 36 Returns: 37 None 38 """ 39 self.last_update = time.time()
QQ数据缓存类
42class UserData(QQDataItem): 43 """ 44 QQ用户数据缓存类 45 """ 46 47 def __init__( 48 self, 49 user_id: int, 50 nickname: str = NotFetched, 51 sex: str = NotFetched, 52 age: int = NotFetched, 53 is_friend: bool = NotFetched, 54 remark: str | None = NotFetched # 此值仅在是好友的时候会存在 55 ): 56 super().__init__() 57 self._user_id = user_id 58 self._data = { 59 "user_id": user_id, 60 "nickname": nickname, 61 "sex": sex, 62 "age": age, 63 "is_friend": is_friend, 64 "remark": remark 65 } 66 67 def refresh_cache(self): 68 """ 69 刷新缓存 70 Returns: 71 None 72 """ 73 if int(self._user_id) <= 0: 74 logger.warn(f"获取用户{self._user_id}缓存信息失败: user_id小于等于0") 75 return 76 try: 77 data = api.get_stranger_info(self._user_id) 78 for k in data: 79 self._data[k] = data[k] 80 self._data["is_friend"] = NotFetched 81 self._data["remark"] = NotFetched 82 except Exception as e: 83 logger.warn(f"获取用户{self._user_id}缓存信息失败: {repr(e)}") 84 return 85 86 def __getattr__(self, item): 87 if item == "_data" or item == "data": 88 return self._data 89 90 if item in ["remark", "is_friend"] and self._data.get(item) != NotFetched: 91 try: 92 res = api.get_friend_list() 93 for friend in res: 94 if friend["user_id"] == self._user_id: 95 self._data["remark"] = friend["remark"] 96 self._data["is_friend"] = True 97 break 98 else: 99 self._data["is_friend"] = False 100 self._data["remark"] = None 101 except Exception as e: 102 logger.warn(f"获取用户{self._user_id}是否为好友失败: {repr(e)}") 103 return None 104 105 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 106 self.refresh_cache() 107 108 if self._data.get(item) == NotFetched: 109 return None 110 111 if item in self._data: 112 self.last_use = time.time() 113 114 return self._data.get(item) 115 116 def get_nickname(self) -> str: 117 """ 118 获取昵称(如果有备注名优先返回备注名) 119 Returns: 120 昵称 121 """ 122 return self.remark or self.nickname 123 124 def __repr__(self): 125 return f"UserData(user_id={self._user_id})"
QQ用户数据缓存类
UserData( user_id: int, nickname: str = <class 'NotFetched'>, sex: str = <class 'NotFetched'>, age: int = <class 'NotFetched'>, is_friend: bool = <class 'NotFetched'>, remark: str | None = <class 'NotFetched'>)
47 def __init__( 48 self, 49 user_id: int, 50 nickname: str = NotFetched, 51 sex: str = NotFetched, 52 age: int = NotFetched, 53 is_friend: bool = NotFetched, 54 remark: str | None = NotFetched # 此值仅在是好友的时候会存在 55 ): 56 super().__init__() 57 self._user_id = user_id 58 self._data = { 59 "user_id": user_id, 60 "nickname": nickname, 61 "sex": sex, 62 "age": age, 63 "is_friend": is_friend, 64 "remark": remark 65 }
def
refresh_cache(self) -> None:
67 def refresh_cache(self): 68 """ 69 刷新缓存 70 Returns: 71 None 72 """ 73 if int(self._user_id) <= 0: 74 logger.warn(f"获取用户{self._user_id}缓存信息失败: user_id小于等于0") 75 return 76 try: 77 data = api.get_stranger_info(self._user_id) 78 for k in data: 79 self._data[k] = data[k] 80 self._data["is_friend"] = NotFetched 81 self._data["remark"] = NotFetched 82 except Exception as e: 83 logger.warn(f"获取用户{self._user_id}缓存信息失败: {repr(e)}") 84 return
刷新缓存
Returns:
None
def
get_nickname(self) -> str:
116 def get_nickname(self) -> str: 117 """ 118 获取昵称(如果有备注名优先返回备注名) 119 Returns: 120 昵称 121 """ 122 return self.remark or self.nickname
获取昵称(如果有备注名优先返回备注名)
Returns:
昵称
Inherited Members
128class GroupMemberData(QQDataItem): 129 """ 130 QQ群成员数据缓存类 131 """ 132 133 def __init__( 134 self, 135 group_id: int, 136 user_id: int, 137 nickname: str = NotFetched, 138 card: str = NotFetched, 139 sex: str = NotFetched, 140 age: int = NotFetched, 141 area: str = NotFetched, 142 join_time: int = NotFetched, 143 last_sent_time: int = NotFetched, 144 level: str = NotFetched, 145 role: str = NotFetched, 146 unfriendly: bool = NotFetched, 147 title: str = NotFetched, 148 title_expire_time: int = NotFetched, 149 card_changeable: bool = NotFetched, 150 ): 151 super().__init__() 152 self._group_id = group_id 153 self._user_id = user_id 154 self._data = { 155 "group_id": group_id, 156 "user_id": user_id, 157 "nickname": nickname, 158 "card": card, 159 "sex": sex, 160 "age": age, 161 "area": area, 162 "join_time": join_time, 163 "last_sent_time": last_sent_time, 164 "level": level, 165 "role": role, 166 "unfriendly": unfriendly, 167 "title": title, 168 "title_expire_time": title_expire_time, 169 "card_changeable": card_changeable, 170 } 171 172 def refresh_cache(self): 173 """ 174 刷新缓存 175 Returns: 176 None 177 """ 178 if int(self._group_id) <= 0 or int(self._user_id) <= 0: 179 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: group_id或user_id小于等于0") 180 return 181 try: 182 data = api.get_group_member_info(self._group_id, self._user_id, no_cache=True) 183 for k in data: 184 self._data[k] = data[k] 185 except Exception as e: 186 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: {repr(e)}") 187 user_data = get_user_info(self._user_id) 188 self._data["nickname"] = user_data.nickname if user_data.nickname else NotFetched 189 self._data["sex"] = user_data.sex if user_data.sex else NotFetched 190 self._data["age"] = user_data.age if user_data.age else NotFetched 191 super().refresh_cache() 192 193 def __getattr__(self, item): 194 if item == "_data" or item == "data": 195 return self._data 196 197 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 198 self.refresh_cache() 199 200 if self._data.get(item) == NotFetched: 201 return None 202 203 if item in self._data: 204 self.last_use = time.time() 205 206 return self._data.get(item) 207 208 def __repr__(self): 209 return f"GroupMemberData(group_id={self._group_id}, user_id={self._user_id})" 210 211 def get_nickname(self): 212 """ 213 获取群名片(如果有群名片优先返回群名片) 214 Returns: 215 群名片 216 """ 217 return self.card or self.nickname
QQ群成员数据缓存类
GroupMemberData( group_id: int, user_id: int, nickname: str = <class 'NotFetched'>, card: str = <class 'NotFetched'>, sex: str = <class 'NotFetched'>, age: int = <class 'NotFetched'>, area: str = <class 'NotFetched'>, join_time: int = <class 'NotFetched'>, last_sent_time: int = <class 'NotFetched'>, level: str = <class 'NotFetched'>, role: str = <class 'NotFetched'>, unfriendly: bool = <class 'NotFetched'>, title: str = <class 'NotFetched'>, title_expire_time: int = <class 'NotFetched'>, card_changeable: bool = <class 'NotFetched'>)
133 def __init__( 134 self, 135 group_id: int, 136 user_id: int, 137 nickname: str = NotFetched, 138 card: str = NotFetched, 139 sex: str = NotFetched, 140 age: int = NotFetched, 141 area: str = NotFetched, 142 join_time: int = NotFetched, 143 last_sent_time: int = NotFetched, 144 level: str = NotFetched, 145 role: str = NotFetched, 146 unfriendly: bool = NotFetched, 147 title: str = NotFetched, 148 title_expire_time: int = NotFetched, 149 card_changeable: bool = NotFetched, 150 ): 151 super().__init__() 152 self._group_id = group_id 153 self._user_id = user_id 154 self._data = { 155 "group_id": group_id, 156 "user_id": user_id, 157 "nickname": nickname, 158 "card": card, 159 "sex": sex, 160 "age": age, 161 "area": area, 162 "join_time": join_time, 163 "last_sent_time": last_sent_time, 164 "level": level, 165 "role": role, 166 "unfriendly": unfriendly, 167 "title": title, 168 "title_expire_time": title_expire_time, 169 "card_changeable": card_changeable, 170 }
def
refresh_cache(self) -> None:
172 def refresh_cache(self): 173 """ 174 刷新缓存 175 Returns: 176 None 177 """ 178 if int(self._group_id) <= 0 or int(self._user_id) <= 0: 179 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: group_id或user_id小于等于0") 180 return 181 try: 182 data = api.get_group_member_info(self._group_id, self._user_id, no_cache=True) 183 for k in data: 184 self._data[k] = data[k] 185 except Exception as e: 186 logger.warn(f"获取群{self._group_id}中成员{self._user_id}缓存信息失败: {repr(e)}") 187 user_data = get_user_info(self._user_id) 188 self._data["nickname"] = user_data.nickname if user_data.nickname else NotFetched 189 self._data["sex"] = user_data.sex if user_data.sex else NotFetched 190 self._data["age"] = user_data.age if user_data.age else NotFetched 191 super().refresh_cache()
刷新缓存
Returns:
None
def
get_nickname(self) -> str:
211 def get_nickname(self): 212 """ 213 获取群名片(如果有群名片优先返回群名片) 214 Returns: 215 群名片 216 """ 217 return self.card or self.nickname
获取群名片(如果有群名片优先返回群名片)
Returns:
群名片
Inherited Members
220class GroupData(QQDataItem): 221 """ 222 QQ群数据缓存类 223 """ 224 225 def __init__( 226 self, 227 group_id: int, 228 group_name: str = NotFetched, 229 member_count: int = NotFetched, 230 max_member_count: int = NotFetched 231 ): 232 super().__init__() 233 self._group_id = group_id 234 self._data = { 235 "group_id": group_id, 236 "group_name": group_name, 237 "member_count": member_count, 238 "max_member_count": max_member_count, 239 "group_member_list": NotFetched 240 } 241 242 def refresh_cache(self): 243 """ 244 刷新缓存 245 Returns: 246 None 247 """ 248 if int(self._group_id) <= 0: 249 logger.warn(f"获取群{self._group_id}缓存信息失败: group_id小于等于0") 250 return 251 try: 252 data = api.get_group_info(group_id=self._group_id, no_cache=True) 253 for k in data: 254 self._data[k] = data[k] 255 self._data["group_member_list"] = NotFetched 256 except Exception as e: 257 logger.warn(f"获取群{self._group_id}缓存信息失败: {repr(e)}") 258 return 259 super().refresh_cache() 260 261 def __getattr__(self, item): 262 if item == "_data" or item == "data": 263 return self._data 264 265 if item == "group_member_list" and self._data.get(item) == NotFetched: 266 try: 267 res = api.get_group_member_list(self._group_id) 268 member_list = [GroupMemberData(**{k: (v if v is not None else NotFetched) 269 for k, v in member.items()}) 270 for member in res] 271 self._data[item] = member_list 272 except Exception as e: 273 logger.warn(f"获取群{self._group_id}成员列表信息失败: {repr(e)}") 274 return 275 276 if self._data.get(item) == NotFetched or time.time() - self.last_update > expire_time: 277 self.refresh_cache() 278 279 if self._data.get(item) == NotFetched: 280 return None 281 282 if item in self._data: 283 self.last_use = time.time() 284 285 return self._data.get(item) 286 287 def __repr__(self): 288 return f"GroupData(group_id={self._group_id})"
QQ群数据缓存类
GroupData( group_id: int, group_name: str = <class 'NotFetched'>, member_count: int = <class 'NotFetched'>, max_member_count: int = <class 'NotFetched'>)
225 def __init__( 226 self, 227 group_id: int, 228 group_name: str = NotFetched, 229 member_count: int = NotFetched, 230 max_member_count: int = NotFetched 231 ): 232 super().__init__() 233 self._group_id = group_id 234 self._data = { 235 "group_id": group_id, 236 "group_name": group_name, 237 "member_count": member_count, 238 "max_member_count": max_member_count, 239 "group_member_list": NotFetched 240 }
def
refresh_cache(self) -> None:
242 def refresh_cache(self): 243 """ 244 刷新缓存 245 Returns: 246 None 247 """ 248 if int(self._group_id) <= 0: 249 logger.warn(f"获取群{self._group_id}缓存信息失败: group_id小于等于0") 250 return 251 try: 252 data = api.get_group_info(group_id=self._group_id, no_cache=True) 253 for k in data: 254 self._data[k] = data[k] 255 self._data["group_member_list"] = NotFetched 256 except Exception as e: 257 logger.warn(f"获取群{self._group_id}缓存信息失败: {repr(e)}") 258 return 259 super().refresh_cache()
刷新缓存
Returns:
None
Inherited Members
group_info: dict =
{}
group_member_info: dict =
{}
user_info: dict =
{}
group_info_lock =
<unlocked _thread.lock object>
group_member_info_lock =
<unlocked _thread.lock object>
user_info_lock =
<unlocked _thread.lock object>
max_cache_size: int =
500
expire_time: int =
300
303def get_user_info(user_id: int, *args, **kwargs) -> UserData: 304 """ 305 获取用户信息 306 Args: 307 user_id: 用户ID 308 Returns: 309 None 310 """ 311 with user_info_lock: 312 if user_id not in user_info: 313 data = UserData(user_id, *args, **kwargs) 314 user_info[user_id] = data 315 316 data = user_info[user_id] 317 return data
获取用户信息
Arguments:
- user_id: 用户ID
Returns:
None
320def get_group_info(group_id: int, *args, **kwargs) -> GroupData: 321 """ 322 获取群信息 323 Args: 324 group_id: 群号 325 Returns: 326 None 327 """ 328 with group_info_lock: 329 if group_id not in group_info: 330 data = GroupData(group_id, *args, **kwargs) 331 group_info[group_id] = data 332 333 data = group_info[group_id] 334 return data
获取群信息
Arguments:
- group_id: 群号
Returns:
None
337def get_group_member_info(group_id: int, user_id: int, *args, **kwargs) -> GroupMemberData: 338 """ 339 获取群成员信息 340 Args: 341 group_id: 群号 342 user_id: 用户ID 343 Returns: 344 None 345 """ 346 with group_member_info_lock: 347 if group_id not in group_member_info: 348 group_member_info[group_id] = {} 349 350 if user_id not in group_member_info[group_id]: 351 data = GroupMemberData(group_id, user_id, *args, **kwargs) 352 group_member_info[group_id][user_id] = data 353 354 data = group_member_info[group_id][user_id] 355 return data
获取群成员信息
Arguments:
- group_id: 群号
- user_id: 用户ID
Returns:
None
def
garbage_collection() -> int:
358def garbage_collection(): 359 """ 360 垃圾回收 361 Returns: 362 None 363 """ 364 counter = 0 365 366 with group_member_info_lock: 367 for k in list(group_member_info.keys()): 368 group_member_items = list(zip(group_member_info[k].keys(), group_member_info[k].values())) 369 max_last_use_time = max([item[1].last_use for item in group_member_items]) 370 371 if max_last_use_time < time.time() - expire_time * 2: 372 del group_member_info[k] 373 counter += 1 374 continue 375 376 group_member_items.sort(key=lambda x: x[1].last_use) 377 if len(group_member_items) > max_cache_size * (2 / 3): 378 for user_id, _ in group_member_items[:int(max_cache_size * (1 / 3))]: 379 del group_member_info[k][user_id] 380 counter += 1 381 del group_member_items, max_last_use_time 382 383 with group_info_lock: 384 group_items = list(zip(group_info.keys(), group_info.values())) 385 group_items.sort(key=lambda x: x[1].last_use) 386 if len(group_items) > max_cache_size * (2 / 3): 387 for group_id, _ in group_items[:int(max_cache_size * (1 / 3))]: 388 del group_info[group_id] 389 counter += 1 390 del group_items 391 392 with user_info_lock: 393 user_items = list(zip(user_info.keys(), user_info.values())) 394 user_items.sort(key=lambda x: x[1].last_use) 395 if len(user_items) > max_cache_size * (2 / 3): 396 for user_id, _ in user_items[:int(max_cache_size * (1 / 3))]: 397 del user_info[user_id] 398 counter += 1 399 del user_items 400 401 return counter
垃圾回收
Returns:
None
def
scheduled_garbage_collection() -> None:
404def scheduled_garbage_collection(): 405 """ 406 定时垃圾回收 407 Returns: 408 None 409 """ 410 t = 0 411 while True: 412 time.sleep(60) 413 t += 1 414 if ( 415 t > 4 or ( 416 t > 1 and ( 417 len(group_info) > max_cache_size or 418 len(user_info) > max_cache_size or 419 len(group_member_info) > max_cache_size 420 ) 421 ) 422 ): 423 t = 0 424 logger.debug("QQ数据缓存清理开始...") 425 try: 426 counter = garbage_collection() 427 logger.debug(f"QQ数据缓存清理完成,共清理了 {counter} 项信息。") 428 except Exception as e: 429 logger.warn(f"QQ数据缓存清理时出现异常: {repr(e)}")
定时垃圾回收
Returns:
None