選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

plugin_manager.py 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. # encoding:utf-8
  2. import importlib
  3. import json
  4. import os
  5. from common.singleton import singleton
  6. from common.sorted_dict import SortedDict
  7. from .event import *
  8. from common.log import logger
  9. from config import conf
  10. @singleton
  11. class PluginManager:
  12. def __init__(self):
  13. self.plugins = SortedDict(lambda k,v: v.priority,reverse=True)
  14. self.listening_plugins = {}
  15. self.instances = {}
  16. self.pconf = {}
  17. def register(self, name: str, desc: str, version: str, author: str, desire_priority: int = 0):
  18. def wrapper(plugincls):
  19. plugincls.name = name
  20. plugincls.desc = desc
  21. plugincls.version = version
  22. plugincls.author = author
  23. plugincls.priority = desire_priority
  24. plugincls.enabled = True
  25. self.plugins[name.upper()] = plugincls
  26. logger.info("Plugin %s_v%s registered" % (name, version))
  27. return plugincls
  28. return wrapper
  29. def save_config(self):
  30. with open("./plugins/plugins.json", "w", encoding="utf-8") as f:
  31. json.dump(self.pconf, f, indent=4, ensure_ascii=False)
  32. def load_config(self):
  33. logger.info("Loading plugins config...")
  34. modified = False
  35. if os.path.exists("./plugins/plugins.json"):
  36. with open("./plugins/plugins.json", "r", encoding="utf-8") as f:
  37. pconf = json.load(f)
  38. pconf['plugins'] = SortedDict(lambda k,v: v["priority"],pconf['plugins'],reverse=True)
  39. else:
  40. modified = True
  41. pconf = {"plugins": SortedDict(lambda k,v: v["priority"],reverse=True)}
  42. self.pconf = pconf
  43. if modified:
  44. self.save_config()
  45. return pconf
  46. def scan_plugins(self):
  47. logger.info("Scaning plugins ...")
  48. plugins_dir = "./plugins"
  49. for plugin_name in os.listdir(plugins_dir):
  50. plugin_path = os.path.join(plugins_dir, plugin_name)
  51. if os.path.isdir(plugin_path):
  52. # 判断插件是否包含同名.py文件
  53. main_module_path = os.path.join(plugin_path, plugin_name+".py")
  54. if os.path.isfile(main_module_path):
  55. # 导入插件
  56. import_path = "plugins.{}.{}".format(plugin_name, plugin_name)
  57. try:
  58. main_module = importlib.import_module(import_path)
  59. except Exception as e:
  60. logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
  61. continue
  62. pconf = self.pconf
  63. new_plugins = []
  64. modified = False
  65. for name, plugincls in self.plugins.items():
  66. rawname = plugincls.name
  67. if rawname not in pconf["plugins"]:
  68. new_plugins.append(plugincls)
  69. modified = True
  70. logger.info("Plugin %s not found in pconfig, adding to pconfig..." % name)
  71. pconf["plugins"][rawname] = {"enabled": plugincls.enabled, "priority": plugincls.priority}
  72. else:
  73. self.plugins[name].enabled = pconf["plugins"][rawname]["enabled"]
  74. self.plugins[name].priority = pconf["plugins"][rawname]["priority"]
  75. self.plugins._update_heap(name) # 更新下plugins中的顺序
  76. if modified:
  77. self.save_config()
  78. return new_plugins
  79. def refresh_order(self):
  80. for event in self.listening_plugins.keys():
  81. self.listening_plugins[event].sort(key=lambda name: self.plugins[name].priority, reverse=True)
  82. def activate_plugins(self): # 生成新开启的插件实例
  83. for name, plugincls in self.plugins.items():
  84. if plugincls.enabled:
  85. if name not in self.instances:
  86. instance = plugincls()
  87. self.instances[name] = instance
  88. for event in instance.handlers:
  89. if event not in self.listening_plugins:
  90. self.listening_plugins[event] = []
  91. self.listening_plugins[event].append(name)
  92. self.refresh_order()
  93. def reload_plugin(self, name:str):
  94. name = name.upper()
  95. if name in self.instances:
  96. for event in self.listening_plugins:
  97. if name in self.listening_plugins[event]:
  98. self.listening_plugins[event].remove(name)
  99. del self.instances[name]
  100. self.activate_plugins()
  101. return True
  102. return False
  103. def load_plugins(self):
  104. self.load_config()
  105. self.scan_plugins()
  106. pconf = self.pconf
  107. logger.debug("plugins.json config={}".format(pconf))
  108. for name,plugin in pconf["plugins"].items():
  109. if name.upper() not in self.plugins:
  110. logger.error("Plugin %s not found, but found in plugins.json" % name)
  111. self.activate_plugins()
  112. def emit_event(self, e_context: EventContext, *args, **kwargs):
  113. if e_context.event in self.listening_plugins:
  114. for name in self.listening_plugins[e_context.event]:
  115. if self.plugins[name].enabled and e_context.action == EventAction.CONTINUE:
  116. logger.debug("Plugin %s triggered by event %s" % (name,e_context.event))
  117. instance = self.instances[name]
  118. instance.handlers[e_context.event](e_context, *args, **kwargs)
  119. return e_context
  120. def set_plugin_priority(self, name:str, priority:int):
  121. name = name.upper()
  122. if name not in self.plugins:
  123. return False
  124. if self.plugins[name].priority == priority:
  125. return True
  126. self.plugins[name].priority = priority
  127. self.plugins._update_heap(name)
  128. rawname = self.plugins[name].name
  129. self.pconf["plugins"][rawname]["priority"] = priority
  130. self.pconf["plugins"]._update_heap(rawname)
  131. self.save_config()
  132. self.refresh_order()
  133. return True
  134. def enable_plugin(self, name:str):
  135. name = name.upper()
  136. if name not in self.plugins:
  137. return False
  138. if not self.plugins[name].enabled :
  139. self.plugins[name].enabled = True
  140. rawname = self.plugins[name].name
  141. self.pconf["plugins"][rawname]["enabled"] = True
  142. self.save_config()
  143. self.activate_plugins()
  144. return True
  145. return True
  146. def disable_plugin(self, name:str):
  147. name = name.upper()
  148. if name not in self.plugins:
  149. return False
  150. if self.plugins[name].enabled :
  151. self.plugins[name].enabled = False
  152. rawname = self.plugins[name].name
  153. self.pconf["plugins"][rawname]["enabled"] = False
  154. self.save_config()
  155. return True
  156. return True
  157. def list_plugins(self):
  158. return self.plugins