from werobot.session import SessionStorage # WeRoBot 框架的会话存储基类 from werobot.utils import json_loads, json_dumps # WeRoBot 提供的 JSON 序列化/反序列化工具 from djangoblog.utils import cache # 项目中封装的缓存对象(如 Redis 或 Memcached) class MemcacheStorage(SessionStorage): """ 自定义的会话存储类,基于缓存系统(如 Redis/Memcached)实现 WeRoBot 微信机器人的会话管理。 用于在微信消息处理过程中持久化用户会话数据(如上下文、状态等)。 通过将用户 ID 作为键,会话数据作为值,存储在缓存中,实现跨请求的会话跟踪。 """ def __init__(self, prefix='ws_'): """ 初始化 MemcacheStorage 实例。 参数: prefix (str): 缓存键的前缀,默认为 'ws_'(weobot session 的缩写),用于避免键名冲突。 功能: - 设置键名前缀 - 绑定项目全局的缓存实例(cache) """ self.prefix = prefix # 设置键名前缀 self.cache = cache # 使用项目中已配置的缓存后端(如 Redis) @property def is_available(self): """ 检查当前会话存储是否可用(即缓存系统是否正常工作)。 实现方式: 1. 尝试写入一个测试键值对('checkavaliable': '1') 2. 立即读取该键的值 3. 如果读取的值与写入的值一致,则认为存储可用 返回: bool: True 表示缓存可用;False 表示不可用(如缓存服务宕机) """ value = "1" self.set('checkavaliable', value=value) # 写入测试数据 return value == self.get('checkavaliable') # 验证能否正确读取 def key_name(self, s): """ 为给定的会话 ID 生成带前缀的完整缓存键名。 参数: s (str): 原始会话 ID(通常是微信用户的 OpenID) 返回: str: 格式为 '{prefix}{s}' 的完整键名,用于避免命名冲突。 示例: key_name('abc123') -> 'ws_abc123' """ return '{prefix}{s}'.format(prefix=self.prefix, s=s) def get(self, id): """ 根据会话 ID 从缓存中获取会话数据。 参数: id (str): 会话 ID(如用户 OpenID) 返回: dict: 会话数据的字典;如果缓存中不存在,则返回空字典 {} 流程: 1. 使用 key_name() 生成带前缀的键 2. 从缓存中获取 JSON 字符串 3. 使用 json_loads 将 JSON 字符串反序列化为 Python 字典 """ id = self.key_name(id) session_json = self.cache.get(id) or '{}' # 如果未找到,返回空 JSON 字符串 return json_loads(session_json) def set(self, id, value): """ 将会话数据存储到缓存中。 参数: id (str): 会话 ID value (dict): 要存储的会话数据(Python 字典) 流程: 1. 使用 key_name() 生成带前缀的键 2. 将字典序列化为 JSON 字符串 3. 存入缓存(使用默认过期时间) """ id = self.key_name(id) self.cache.set(id, json_dumps(value)) # 序列化并存储 def delete(self, id): """ 根据会话 ID 从缓存中删除会话数据。 参数: id (str): 会话 ID 流程: 1. 使用 key_name() 生成带前缀的键 2. 调用缓存的 delete 方法删除该键 """ id = self.key_name(id) self.cache.delete(id)