registry.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #!/usr/bin/env python
  2. # -- coding: utf-8 --
  3. # @Time : 2024/09/18
  4. import os.path
  5. from importlib import import_module
  6. from pathlib import Path
  7. import sys
  8. from types import ModuleType
  9. from flask import Blueprint, Flask
  10. from ..base.signal import module_initailize
  11. from .config import CONFIG_CACHE
  12. def path_to_module(file_path:str, root_path:str) -> str:
  13. """
  14. 文件路径转为模块名称
  15. Args:
  16. file_path (str): 文件路径
  17. root_path (str): 根路径
  18. Returns:
  19. str: 模块名称
  20. """
  21. file_path = Path(file_path)
  22. root_path = Path(root_path).resolve()
  23. file_relative = file_path.relative_to(root_path)
  24. module_path = str(file_relative.with_suffix('')).replace(os.sep, '.').replace('\\', '.')
  25. return module_path
  26. class RuoYiModuleRegistry(object):
  27. module_prefix = "ruoyi_"
  28. controller_name = "controller"
  29. exclude_modules = ["ruoyi_ui"]
  30. def __init__(self, app:Flask=None, proot:str=None):
  31. self.app = app
  32. self.proot = proot
  33. url_prefix = CONFIG_CACHE["ruoyi.api.version"]
  34. if not url_prefix.startswith("/"):
  35. raise ValueError("url_prefix must start with /")
  36. self.api = Blueprint(
  37. "api",
  38. __name__,
  39. url_prefix=url_prefix
  40. )
  41. def register_modules(self):
  42. '''
  43. 注册所有模块
  44. '''
  45. self.import_modules()
  46. self.register_controllers()
  47. def import_modules(self):
  48. '''
  49. 导入所有模块
  50. '''
  51. for modname in os.listdir(self.proot):
  52. if not modname.startswith(self.module_prefix):
  53. continue
  54. if modname in self.exclude_modules:
  55. continue
  56. if not os.path.exists(
  57. os.path.join(self.proot,modname,"__init__.py")
  58. ):
  59. self.app.logger.warning(f"模块路径不存在__init__.py文件: {modname}")
  60. continue
  61. self.import_module(modname)
  62. def import_module(self, modname:str):
  63. '''
  64. 导入模块
  65. Args:
  66. modname (str): 模块名称
  67. '''
  68. modpath = os.path.join(self.proot,modname)
  69. mod = import_module(path_to_module(modpath,self.proot))
  70. module_initailize.send(mod,registry=self)
  71. def is_registered_module(self, modname:str) -> bool:
  72. '''
  73. 检查模块是否已经注册
  74. Args:
  75. modname (str): 模块名称
  76. Returns:
  77. bool: 是否已经注册
  78. '''
  79. flag = modname in sys.modules
  80. return flag
  81. def unregister_module(self, mod:ModuleType):
  82. '''
  83. 注销模块
  84. Args:
  85. mod (ModuleType): 模块对象
  86. '''
  87. if mod in self.default_modules:
  88. return
  89. # todo
  90. def register_controllers(self):
  91. '''
  92. 注册所有控制层路由
  93. '''
  94. for modname in os.listdir(self.proot):
  95. if not modname.startswith(self.module_prefix):
  96. continue
  97. if modname in self.exclude_modules:
  98. continue
  99. if not self.is_registered_module(modname):
  100. continue
  101. self.register_controller(modname)
  102. self.app.register_blueprint(self.api)
  103. def register_controller(self, modname:str):
  104. '''
  105. 注册控制层路由
  106. Args:
  107. mod (str): 模块名称
  108. '''
  109. modpath = os.path.join(self.proot,modname)
  110. mod_con_path = os.path.join(modpath,self.controller_name)
  111. if not os.path.exists(mod_con_path):
  112. return
  113. try:
  114. self._register_rules(mod_con_path)
  115. except Exception as e:
  116. raise Exception(
  117. "在模块中的路由,注册失败: {},原因: {}".format(modname,str(e))
  118. )
  119. def unregister_controller(self, modname:str):
  120. '''
  121. 注销控制层路由
  122. Args:
  123. modname (str): 模块名称
  124. '''
  125. # todo
  126. def _register_rules(self,path:str):
  127. '''
  128. 注册路由规则
  129. Args:
  130. path (str): 路由路径
  131. '''
  132. for rule_name in os.listdir(path):
  133. con_path = os.path.join(path,rule_name)
  134. if os.path.isfile(con_path) and rule_name.endswith(".py") \
  135. and rule_name != "__init__.py":
  136. rule_path = path_to_module(con_path,self.proot)
  137. import_module(rule_path)
  138. elif os.path.isdir(con_path) and \
  139. os.path.exists(os.path.join(con_path,"__init__.py")):
  140. for sub_rule_name in os.listdir(con_path):
  141. sub_path = os.path.join(con_path,sub_rule_name)
  142. if os.path.isfile(sub_path) and sub_rule_name.endswith(".py") \
  143. and sub_rule_name != "__init__.py":
  144. rule_path = path_to_module(sub_path,self.proot)
  145. import_module(path_to_module(sub_path,self.proot))
  146. else:
  147. continue