Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

200 linhas
7.5KB

  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. "debug": {
  49. "alias": ["debug", "调试模式", "DEBUG"],
  50. "desc": "开启机器调试日志",
  51. },
  52. }
  53. # 定义帮助函数
  54. def get_help_text(isadmin, isgroup):
  55. help_text = "可用指令:\n"
  56. for cmd, info in COMMANDS.items():
  57. if cmd=="auth" and (isadmin or isgroup): # 群聊不可认证
  58. continue
  59. alias=["#"+a for a in info['alias']]
  60. help_text += f"{','.join(alias)} "
  61. if 'args' in info:
  62. args=["{"+a+"}" for a in info['args']]
  63. help_text += f"{' '.join(args)} "
  64. help_text += f": {info['desc']}\n"
  65. if ADMIN_COMMANDS and isadmin:
  66. help_text += "\n管理员指令:\n"
  67. for cmd, info in ADMIN_COMMANDS.items():
  68. alias=["#"+a for a in info['alias']]
  69. help_text += f"{','.join(alias)} "
  70. help_text += f": {info['desc']}\n"
  71. return help_text
  72. @plugins.register(name="Godcmd", desc="为你的机器人添加指令集,有用户和管理员两种角色,加载顺序请放在首位,初次运行后插件目录会生成配置文件, 填充管理员密码后即可认证", version="1.0", author="lanvent")
  73. class Godcmd(Plugin):
  74. def __init__(self):
  75. super().__init__()
  76. curdir=os.path.dirname(__file__)
  77. config_path=os.path.join(curdir,"config.json")
  78. gconf=None
  79. if not os.path.exists(config_path):
  80. gconf={"password":"","admin_users":[]}
  81. with open(config_path,"w") as f:
  82. json.dump(gconf,f,indent=4)
  83. else:
  84. with open(config_path,"r") as f:
  85. gconf=json.load(f)
  86. self.password = gconf["password"]
  87. self.admin_users = gconf["admin_users"] # 预存的管理员账号,这些账号不需要认证 TODO: 用户名每次都会变,目前不可用
  88. self.isrunning = True # 机器人是否运行中
  89. self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
  90. logger.info("[Godcmd] inited")
  91. def on_handle_context(self, e_context: EventContext):
  92. context_type = e_context['context']['type']
  93. if context_type != "TEXT":
  94. if not self.isrunning:
  95. e_context.action = EventAction.BREAK_PASS
  96. return
  97. content = e_context['context']['content']
  98. logger.debug("[Godcmd] on_handle_context. content: %s" % content)
  99. if content.startswith("#"):
  100. # msg = e_context['context']['msg']
  101. user = e_context['context']['receiver']
  102. session_id = e_context['context']['session_id']
  103. isgroup = e_context['context']['isgroup']
  104. bottype = Bridge().get_bot_type("chat")
  105. bot = Bridge().get_bot("chat")
  106. # 将命令和参数分割
  107. command_parts = content[1:].split(" ")
  108. cmd = command_parts[0]
  109. args = command_parts[1:]
  110. isadmin=False
  111. if user in self.admin_users:
  112. isadmin=True
  113. ok=False
  114. result="string"
  115. if any(cmd in info['alias'] for info in COMMANDS.values()):
  116. cmd = next(c for c, info in COMMANDS.items() if cmd in info['alias'])
  117. if cmd == "auth":
  118. ok, result = self.authenticate(user, args, isadmin, isgroup)
  119. elif cmd == "help":
  120. ok, result = True, get_help_text(isadmin, isgroup)
  121. elif cmd == "id":
  122. ok, result = True, f"用户id=\n{user}"
  123. elif cmd == "reset":
  124. if bottype == "chatGPT":
  125. bot.sessions.clear_session(session_id)
  126. ok, result = True, "会话已重置"
  127. else:
  128. ok, result = False, "当前机器人不支持重置会话"
  129. logger.debug("[Godcmd] command: %s by %s" % (cmd, user))
  130. elif any(cmd in info['alias'] for info in ADMIN_COMMANDS.values()):
  131. if isadmin:
  132. if isgroup:
  133. ok, result = False, "群聊不可执行管理员指令"
  134. else:
  135. cmd = next(c for c, info in ADMIN_COMMANDS.items() if cmd in info['alias'])
  136. if cmd == "stop":
  137. self.isrunning = False
  138. ok, result = True, "服务已暂停"
  139. elif cmd == "resume":
  140. self.isrunning = True
  141. ok, result = True, "服务已恢复"
  142. elif cmd == "reconf":
  143. load_config()
  144. ok, result = True, "配置已重载"
  145. elif cmd == "resetall":
  146. if bottype == "chatGPT":
  147. bot.sessions.clear_all_session()
  148. ok, result = True, "重置所有会话成功"
  149. else:
  150. ok, result = False, "当前机器人不支持重置会话"
  151. elif cmd == "debug":
  152. logger.setLevel('DEBUG')
  153. ok, result = True, "DEBUG模式已开启"
  154. logger.debug("[Godcmd] admin command: %s by %s" % (cmd, user))
  155. else:
  156. ok, result = False, "需要管理员权限才能执行该指令"
  157. else:
  158. ok, result = False, f"未知指令:{cmd}\n查看指令列表请输入#help \n"
  159. reply = {}
  160. if ok:
  161. reply["type"] = "INFO"
  162. else:
  163. reply["type"] = "ERROR"
  164. reply["content"] = result
  165. e_context['reply'] = reply
  166. e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
  167. elif not self.isrunning:
  168. e_context.action = EventAction.BREAK_PASS
  169. def authenticate(self, userid, args, isadmin, isgroup) -> Tuple[bool,str] :
  170. if isgroup:
  171. return False,"请勿在群聊中认证"
  172. if isadmin:
  173. return False,"管理员账号无需认证"
  174. if len(args) != 1:
  175. return False,"请提供口令"
  176. password = args[0]
  177. if password == self.password:
  178. self.admin_users.append(userid)
  179. return True,"认证成功"
  180. else:
  181. return False,"认证失败"