Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

270 lines
11KB

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