2021-02-01 15:13:11 +00:00
|
|
|
|
import importlib
|
|
|
|
|
import os
|
|
|
|
|
import re
|
2023-01-26 07:31:13 +00:00
|
|
|
|
import sys
|
2023-01-28 05:53:11 +00:00
|
|
|
|
import traceback
|
2021-11-12 14:25:53 +00:00
|
|
|
|
from typing import Dict, Union
|
2021-02-01 15:13:11 +00:00
|
|
|
|
|
2023-07-06 08:56:57 +00:00
|
|
|
|
from config import Config
|
|
|
|
|
|
2023-02-05 14:33:33 +00:00
|
|
|
|
from core.builtins import PrivateAssets
|
2021-08-07 07:56:48 +00:00
|
|
|
|
from core.logger import Logger
|
2023-03-04 08:51:56 +00:00
|
|
|
|
from core.types import Module
|
|
|
|
|
from core.types.module.component_meta import CommandMeta, RegexMeta, ScheduleMeta
|
2023-04-19 07:41:39 +00:00
|
|
|
|
from core.utils.i18n import load_locale_file
|
2021-02-03 14:43:24 +00:00
|
|
|
|
|
2021-07-10 17:05:07 +00:00
|
|
|
|
load_dir_path = os.path.abspath('./modules/')
|
|
|
|
|
|
2021-02-03 14:43:24 +00:00
|
|
|
|
|
2021-07-07 16:00:24 +00:00
|
|
|
|
def load_modules():
|
2023-07-06 08:56:57 +00:00
|
|
|
|
unloaded_modules = Config('unloaded_modules')
|
2021-10-14 15:18:47 +00:00
|
|
|
|
err_prompt = []
|
2023-04-08 17:47:11 +00:00
|
|
|
|
locale_err = load_locale_file()
|
|
|
|
|
if locale_err:
|
|
|
|
|
locale_err.append('i18n:')
|
|
|
|
|
err_prompt.append('\n'.join(locale_err))
|
2021-07-07 16:00:24 +00:00
|
|
|
|
fun_file = None
|
|
|
|
|
dir_list = os.listdir(load_dir_path)
|
|
|
|
|
for file_name in dir_list:
|
|
|
|
|
try:
|
2022-08-16 18:52:46 +00:00
|
|
|
|
file_path = os.path.join(load_dir_path, file_name)
|
2021-07-10 17:05:07 +00:00
|
|
|
|
fun_file = None
|
2021-04-07 15:18:41 +00:00
|
|
|
|
if os.path.isdir(file_path):
|
2022-04-23 14:22:56 +00:00
|
|
|
|
if file_name[0] != '_':
|
2021-04-07 15:18:41 +00:00
|
|
|
|
fun_file = file_name
|
2022-08-16 18:52:46 +00:00
|
|
|
|
elif os.path.isfile(file_path):
|
|
|
|
|
if file_name[0] != '_' and file_name.endswith('.py'):
|
|
|
|
|
fun_file = file_name[:-3]
|
2021-07-06 18:00:26 +00:00
|
|
|
|
if fun_file is not None:
|
2021-07-07 16:00:24 +00:00
|
|
|
|
Logger.info(f'Loading modules.{fun_file}...')
|
2023-07-06 08:56:57 +00:00
|
|
|
|
if fun_file in unloaded_modules:
|
|
|
|
|
Logger.info(f'Skipped modules.{fun_file}!')
|
|
|
|
|
continue
|
2021-07-06 18:00:26 +00:00
|
|
|
|
modules = 'modules.' + fun_file
|
|
|
|
|
importlib.import_module(modules)
|
2021-07-07 16:00:24 +00:00
|
|
|
|
Logger.info(f'Succeeded loaded modules.{fun_file}!')
|
2023-06-02 18:12:42 +00:00
|
|
|
|
except Exception:
|
2021-07-07 16:00:24 +00:00
|
|
|
|
tb = traceback.format_exc()
|
2022-07-30 08:21:00 +00:00
|
|
|
|
errmsg = f'Failed to load modules.{fun_file}: \n{tb}'
|
2022-08-04 07:52:42 +00:00
|
|
|
|
Logger.error(errmsg)
|
2022-07-30 08:21:00 +00:00
|
|
|
|
err_prompt.append(errmsg)
|
2021-10-14 15:18:47 +00:00
|
|
|
|
loadercache = os.path.abspath(PrivateAssets.path + '/.cache_loader')
|
|
|
|
|
openloadercache = open(loadercache, 'w')
|
|
|
|
|
if err_prompt:
|
2022-07-30 08:21:00 +00:00
|
|
|
|
err_prompt = re.sub(r' File \"<frozen importlib.*?>\", .*?\n', '', '\n'.join(err_prompt))
|
|
|
|
|
openloadercache.write(err_prompt)
|
2021-10-14 15:18:47 +00:00
|
|
|
|
else:
|
2022-07-30 08:21:00 +00:00
|
|
|
|
openloadercache.write('')
|
2021-10-14 15:18:47 +00:00
|
|
|
|
openloadercache.close()
|
2021-07-07 16:00:24 +00:00
|
|
|
|
|
2023-04-19 08:29:46 +00:00
|
|
|
|
modules = ModulesManager.modules
|
|
|
|
|
for m in modules:
|
|
|
|
|
module = modules[m]
|
|
|
|
|
if module.alias:
|
|
|
|
|
ModulesManager.modules_aliases.update(module.alias)
|
|
|
|
|
|
2021-08-07 07:56:48 +00:00
|
|
|
|
|
2021-07-09 09:35:23 +00:00
|
|
|
|
class ModulesManager:
|
2023-03-04 08:51:56 +00:00
|
|
|
|
modules: Dict[str, Module] = {}
|
2023-04-19 08:29:46 +00:00
|
|
|
|
modules_aliases: Dict[str, str] = {}
|
|
|
|
|
modules_origin: Dict[str, str] = {}
|
2021-07-07 16:00:24 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def add_module(cls, module: Module, py_module_name: str):
|
2021-10-24 10:55:45 +00:00
|
|
|
|
if module.bind_prefix not in ModulesManager.modules:
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cls.modules.update({module.bind_prefix: module})
|
|
|
|
|
cls.modules_origin.update({module.bind_prefix: py_module_name})
|
2021-10-24 10:55:45 +00:00
|
|
|
|
else:
|
|
|
|
|
raise ValueError(f'Duplicate bind prefix "{module.bind_prefix}"')
|
2021-07-07 16:00:24 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def remove_modules(cls, modules):
|
2023-01-26 13:21:46 +00:00
|
|
|
|
for module in modules:
|
2023-06-09 10:39:39 +00:00
|
|
|
|
if module in cls.modules:
|
2023-01-26 13:21:46 +00:00
|
|
|
|
Logger.info(f'Removing...{module}')
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cls.modules.pop(module)
|
|
|
|
|
cls.modules_origin.pop(module)
|
2023-01-26 13:21:46 +00:00
|
|
|
|
else:
|
|
|
|
|
raise ValueError(f'Module "{module}" is not exist')
|
2023-01-26 07:31:13 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def search_related_module(cls, module, includeSelf=True):
|
|
|
|
|
if module in cls.modules_origin:
|
2023-01-26 13:21:46 +00:00
|
|
|
|
modules = []
|
2023-06-09 10:39:39 +00:00
|
|
|
|
py_module = cls.return_py_module(module)
|
|
|
|
|
for m in cls.modules_origin:
|
|
|
|
|
if cls.modules_origin[m].startswith(py_module):
|
2023-01-26 13:21:46 +00:00
|
|
|
|
modules.append(m)
|
|
|
|
|
if not includeSelf:
|
|
|
|
|
modules.remove(module)
|
|
|
|
|
return modules
|
|
|
|
|
else:
|
2023-04-19 08:34:16 +00:00
|
|
|
|
raise ValueError(f'Could not find "{module}" in modules_origin dict')
|
2023-01-28 05:53:11 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def return_py_module(cls, module):
|
|
|
|
|
if module in cls.modules_origin:
|
|
|
|
|
return re.match(r'^modules(\.[a-zA-Z0-9_]*)?', cls.modules_origin[module]).group()
|
2023-01-26 13:21:46 +00:00
|
|
|
|
else:
|
|
|
|
|
return None
|
2023-01-28 05:53:11 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def bind_to_module(cls, bind_prefix: str, meta: Union[CommandMeta, RegexMeta, ScheduleMeta]):
|
|
|
|
|
if bind_prefix in cls.modules:
|
2023-03-04 08:51:56 +00:00
|
|
|
|
if isinstance(meta, CommandMeta):
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cls.modules[bind_prefix].command_list.add(meta)
|
2023-03-04 08:51:56 +00:00
|
|
|
|
elif isinstance(meta, RegexMeta):
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cls.modules[bind_prefix].regex_list.add(meta)
|
2023-03-04 08:51:56 +00:00
|
|
|
|
elif isinstance(meta, ScheduleMeta):
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cls.modules[bind_prefix].schedule_list.add(meta)
|
2021-02-01 15:13:11 +00:00
|
|
|
|
|
2023-06-29 11:19:49 +00:00
|
|
|
|
_return_cache = {}
|
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def return_modules_list(cls, targetFrom: str = None) -> \
|
2023-04-30 03:30:59 +00:00
|
|
|
|
Dict[str, Module]:
|
2022-01-26 13:45:17 +00:00
|
|
|
|
if targetFrom is not None:
|
2023-06-29 11:19:49 +00:00
|
|
|
|
if targetFrom in cls._return_cache:
|
|
|
|
|
return cls._return_cache[targetFrom]
|
2022-01-26 13:45:17 +00:00
|
|
|
|
returns = {}
|
2023-06-09 10:39:39 +00:00
|
|
|
|
for m in cls.modules:
|
|
|
|
|
if isinstance(cls.modules[m], Module):
|
|
|
|
|
if targetFrom in cls.modules[m].exclude_from:
|
2022-01-26 13:45:17 +00:00
|
|
|
|
continue
|
2023-06-09 10:39:39 +00:00
|
|
|
|
available = cls.modules[m].available_for
|
2022-01-26 13:45:17 +00:00
|
|
|
|
if targetFrom in available or '*' in available:
|
2023-06-09 10:39:39 +00:00
|
|
|
|
returns.update({m: cls.modules[m]})
|
2023-06-29 11:19:49 +00:00
|
|
|
|
cls._return_cache.update({targetFrom: returns})
|
2022-01-26 13:45:17 +00:00
|
|
|
|
return returns
|
2023-06-09 10:39:39 +00:00
|
|
|
|
return cls.modules
|
2023-04-19 08:34:16 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def reload_module(cls, module_name: str):
|
2023-01-26 07:31:13 +00:00
|
|
|
|
"""
|
2023-01-26 13:21:46 +00:00
|
|
|
|
重载该小可模块(以及该模块所在文件的其它模块)
|
|
|
|
|
"""
|
2023-06-09 10:39:39 +00:00
|
|
|
|
py_module = cls.return_py_module(module_name)
|
|
|
|
|
unbind_modules = cls.search_related_module(module_name)
|
|
|
|
|
cls.remove_modules(unbind_modules)
|
2023-06-29 11:24:40 +00:00
|
|
|
|
cls._return_cache.clear()
|
2023-06-09 10:39:39 +00:00
|
|
|
|
return cls.reload_py_module(py_module)
|
2023-01-28 05:53:11 +00:00
|
|
|
|
|
2023-06-09 10:39:39 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def reload_py_module(cls, module_name: str):
|
2023-01-26 13:21:46 +00:00
|
|
|
|
"""
|
|
|
|
|
重载该py模块
|
2023-01-26 07:31:13 +00:00
|
|
|
|
"""
|
|
|
|
|
try:
|
2023-01-28 05:44:03 +00:00
|
|
|
|
Logger.info(f'Reloading {module_name} ...')
|
2023-01-26 13:21:46 +00:00
|
|
|
|
module = sys.modules[module_name]
|
2023-01-26 07:31:13 +00:00
|
|
|
|
cnt = 0
|
|
|
|
|
loadedModList = list(sys.modules.keys())
|
|
|
|
|
for mod in loadedModList:
|
2023-01-26 13:21:46 +00:00
|
|
|
|
if mod.startswith(f'{module_name}.'):
|
2023-06-09 10:39:39 +00:00
|
|
|
|
cnt += cls.reload_py_module(mod)
|
2023-01-26 07:31:13 +00:00
|
|
|
|
importlib.reload(module)
|
2023-01-26 13:21:46 +00:00
|
|
|
|
Logger.info(f'Succeeded reloaded {module_name}')
|
|
|
|
|
return cnt + 1
|
2023-04-30 03:30:59 +00:00
|
|
|
|
except BaseException:
|
2023-01-26 07:31:13 +00:00
|
|
|
|
tb = traceback.format_exc()
|
|
|
|
|
errmsg = f'Failed to reload {module_name}: \n{tb}'
|
|
|
|
|
Logger.error(errmsg)
|
2023-01-28 05:44:03 +00:00
|
|
|
|
return -999
|