您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

256 行
10KB

  1. # encoding:utf-8
  2. import json
  3. import os
  4. import traceback
  5. from typing import Tuple
  6. from bridge.bridge import Bridge
  7. from config import load_config
  8. import plugins
  9. from plugins import *
  10. from common.log import logger
  11. # 定义指令集
  12. COMMANDS = {
  13. "help": {
  14. "alias": ["help", "帮助"],
  15. "desc": "打印指令集合",
  16. },
  17. "auth": {
  18. "alias": ["auth", "认证"],
  19. "args": ["口令"],
  20. "desc": "管理员认证",
  21. },
  22. # "id": {
  23. # "alias": ["id", "用户"],
  24. # "desc": "获取用户id", #目前无实际意义
  25. # },
  26. "reset": {
  27. "alias": ["reset", "重置会话"],
  28. "desc": "重置会话",
  29. },
  30. }
  31. ADMIN_COMMANDS = {
  32. "resume": {
  33. "alias": ["resume", "恢复服务"],
  34. "desc": "恢复服务",
  35. },
  36. "stop": {
  37. "alias": ["stop", "暂停服务"],
  38. "desc": "暂停服务",
  39. },
  40. "reconf": {
  41. "alias": ["reconf", "重载配置"],
  42. "desc": "重载配置(不包含插件配置)",
  43. },
  44. "resetall": {
  45. "alias": ["resetall", "重置所有会话"],
  46. "desc": "重置所有会话",
  47. },
  48. "scanp": {
  49. "alias": ["scanp", "扫描插件"],
  50. "desc": "扫描插件目录是否有新插件",
  51. },
  52. "plist": {
  53. "alias": ["plist", "插件"],
  54. "desc": "打印当前插件列表",
  55. },
  56. "enablep": {
  57. "alias": ["enablep", "启用插件"],
  58. "args": ["插件名"],
  59. "desc": "启用指定插件",
  60. },
  61. "disablep": {
  62. "alias": ["disablep", "禁用插件"],
  63. "args": ["插件名"],
  64. "desc": "禁用指定插件",
  65. },
  66. "debug": {
  67. "alias": ["debug", "调试模式", "DEBUG"],
  68. "desc": "开启机器调试日志",
  69. },
  70. }
  71. # 定义帮助函数
  72. def get_help_text(isadmin, isgroup):
  73. help_text = "可用指令:\n"
  74. for cmd, info in COMMANDS.items():
  75. if cmd=="auth" and (isadmin or isgroup): # 群聊不可认证
  76. continue
  77. alias=["#"+a for a in info['alias']]
  78. help_text += f"{','.join(alias)} "
  79. if 'args' in info:
  80. args=["{"+a+"}" for a in info['args']]
  81. help_text += f"{' '.join(args)} "
  82. help_text += f": {info['desc']}\n"
  83. if ADMIN_COMMANDS and isadmin:
  84. help_text += "\n管理员指令:\n"
  85. for cmd, info in ADMIN_COMMANDS.items():
  86. alias=["#"+a for a in info['alias']]
  87. help_text += f"{','.join(alias)} "
  88. help_text += f": {info['desc']}\n"
  89. return help_text
  90. @plugins.register(name="Godcmd", desc="为你的机器人添加指令集,有用户和管理员两种角色,加载顺序请放在首位,初次运行后插件目录会生成配置文件, 填充管理员密码后即可认证", version="1.0", author="lanvent")
  91. class Godcmd(Plugin):
  92. def __init__(self):
  93. super().__init__()
  94. curdir=os.path.dirname(__file__)
  95. config_path=os.path.join(curdir,"config.json")
  96. gconf=None
  97. if not os.path.exists(config_path):
  98. gconf={"password":"","admin_users":[]}
  99. with open(config_path,"w") as f:
  100. json.dump(gconf,f,indent=4)
  101. else:
  102. with open(config_path,"r") as f:
  103. gconf=json.load(f)
  104. self.password = gconf["password"]
  105. self.admin_users = gconf["admin_users"] # 预存的管理员账号,这些账号不需要认证 TODO: 用户名每次都会变,目前不可用
  106. self.isrunning = True # 机器人是否运行中
  107. self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
  108. logger.info("[Godcmd] inited")
  109. def on_handle_context(self, e_context: EventContext):
  110. context_type = e_context['context']['type']
  111. if context_type != "TEXT":
  112. if not self.isrunning:
  113. e_context.action = EventAction.BREAK_PASS
  114. return
  115. content = e_context['context']['content']
  116. logger.debug("[Godcmd] on_handle_context. content: %s" % content)
  117. if content.startswith("#"):
  118. # msg = e_context['context']['msg']
  119. user = e_context['context']['receiver']
  120. session_id = e_context['context']['session_id']
  121. isgroup = e_context['context']['isgroup']
  122. bottype = Bridge().get_bot_type("chat")
  123. bot = Bridge().get_bot("chat")
  124. # 将命令和参数分割
  125. command_parts = content[1:].split(" ")
  126. cmd = command_parts[0]
  127. args = command_parts[1:]
  128. isadmin=False
  129. if user in self.admin_users:
  130. isadmin=True
  131. ok=False
  132. result="string"
  133. if any(cmd in info['alias'] for info in COMMANDS.values()):
  134. cmd = next(c for c, info in COMMANDS.items() if cmd in info['alias'])
  135. if cmd == "auth":
  136. ok, result = self.authenticate(user, args, isadmin, isgroup)
  137. elif cmd == "help":
  138. ok, result = True, get_help_text(isadmin, isgroup)
  139. elif cmd == "id":
  140. ok, result = True, f"用户id=\n{user}"
  141. elif cmd == "reset":
  142. if bottype == "chatGPT":
  143. bot.sessions.clear_session(session_id)
  144. ok, result = True, "会话已重置"
  145. else:
  146. ok, result = False, "当前机器人不支持重置会话"
  147. logger.debug("[Godcmd] command: %s by %s" % (cmd, user))
  148. elif any(cmd in info['alias'] for info in ADMIN_COMMANDS.values()):
  149. if isadmin:
  150. if isgroup:
  151. ok, result = False, "群聊不可执行管理员指令"
  152. else:
  153. cmd = next(c for c, info in ADMIN_COMMANDS.items() if cmd in info['alias'])
  154. if cmd == "stop":
  155. self.isrunning = False
  156. ok, result = True, "服务已暂停"
  157. elif cmd == "resume":
  158. self.isrunning = True
  159. ok, result = True, "服务已恢复"
  160. elif cmd == "reconf":
  161. load_config()
  162. ok, result = True, "配置已重载"
  163. elif cmd == "resetall":
  164. if bottype == "chatGPT":
  165. bot.sessions.clear_all_session()
  166. ok, result = True, "重置所有会话成功"
  167. else:
  168. ok, result = False, "当前机器人不支持重置会话"
  169. elif cmd == "debug":
  170. logger.setLevel('DEBUG')
  171. ok, result = True, "DEBUG模式已开启"
  172. elif cmd == "plist":
  173. plugins = PluginManager().list_plugins()
  174. ok = True
  175. result = "插件列表:\n"
  176. for name,plugincls in plugins.items():
  177. result += f"{name}_v{plugincls.version} - "
  178. if plugincls.enabled:
  179. result += "已启用\n"
  180. else:
  181. result += "未启用\n"
  182. elif cmd == "scanp":
  183. new_plugins = PluginManager().scan_plugins()
  184. ok, result = True, "插件扫描完成"
  185. if len(new_plugins) >0 :
  186. PluginManager().activate_plugins()
  187. result += "\n发现新插件:\n"
  188. result += "\n".join([f"{p.name}_v{p.version}" for p in new_plugins])
  189. else :
  190. result +=", 未发现新插件"
  191. elif cmd == "enablep":
  192. if len(args) != 1:
  193. ok, result = False, "请提供插件名"
  194. else:
  195. ok = PluginManager().enable_plugin(args[0])
  196. if ok:
  197. result = "插件已启用"
  198. else:
  199. result = "插件不存在"
  200. elif cmd == "disablep":
  201. if len(args) != 1:
  202. ok, result = False, "请提供插件名"
  203. else:
  204. ok = PluginManager().disable_plugin(args[0])
  205. if ok:
  206. result = "插件已禁用"
  207. else:
  208. result = "插件不存在"
  209. logger.debug("[Godcmd] admin command: %s by %s" % (cmd, user))
  210. else:
  211. ok, result = False, "需要管理员权限才能执行该指令"
  212. else:
  213. ok, result = False, f"未知指令:{cmd}\n查看指令列表请输入#help \n"
  214. reply = {}
  215. if ok:
  216. reply["type"] = "INFO"
  217. else:
  218. reply["type"] = "ERROR"
  219. reply["content"] = result
  220. e_context['reply'] = reply
  221. e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
  222. elif not self.isrunning:
  223. e_context.action = EventAction.BREAK_PASS
  224. def authenticate(self, userid, args, isadmin, isgroup) -> Tuple[bool,str] :
  225. if isgroup:
  226. return False,"请勿在群聊中认证"
  227. if isadmin:
  228. return False,"管理员账号无需认证"
  229. if len(args) != 1:
  230. return False,"请提供口令"
  231. password = args[0]
  232. if password == self.password:
  233. self.admin_users.append(userid)
  234. return True,"认证成功"
  235. else:
  236. return False,"认证失败"