bumper/bumper/web/plugins/__init__.py
2022-03-06 22:21:45 +01:00

88 lines
2.4 KiB
Python

"""Webserver plugin module."""
import inspect
import sys
from abc import abstractmethod
from glob import glob
from os.path import dirname, isfile, join
from types import ModuleType
from typing import Any, Iterable
from aiohttp import web
from aiohttp.web_response import Response
from aiohttp.web_routedef import AbstractRouteDef
from bumper.models import RETURN_API_SUCCESS
from bumper.util import get_current_time_as_millis
class WebserverPlugin:
"""Abstract webserver plugin."""
@property
@abstractmethod
def routes(self) -> Iterable[AbstractRouteDef]:
"""Plugin routes."""
raise NotImplementedError
def _add_routes(
app: web.Application, module: ModuleType, plugin_module_name: str
) -> None:
if not module.__name__.startswith(plugin_module_name):
return
if module.__file__.endswith("__init__.py"):
sub_app = web.Application()
else:
sub_app = app
for _, clazz in inspect.getmembers(module, inspect.isclass):
if not issubclass(clazz, WebserverPlugin) or clazz == WebserverPlugin:
continue
obj = clazz()
sub_app.add_routes(obj.routes)
for _, obj in inspect.getmembers(module, inspect.ismodule):
_add_routes(sub_app, obj, plugin_module_name)
if module.__file__.endswith("__init__.py"):
prefix = module.__file__.removesuffix("/__init__.py")
prefix = prefix[prefix.rindex("/") :] + "/"
app.add_subapp(prefix, sub_app)
def _import_plugins(module: ModuleType) -> None:
for file in glob(join(dirname(module.__file__), "**/*.py"), recursive=True):
if not isfile(file) or file == module.__file__:
continue
name = file.replace("/", ".")
name = name[name.find(module.__name__) : -3].removesuffix(".__init__")
__import__(name)
def add_plugins(app: web.Application) -> None:
"""Discover and add all plugin to app."""
module = sys.modules[__name__]
_import_plugins(module)
plugin_module_name = module.__name__
for _, obj in inspect.getmembers(module, inspect.ismodule):
if not obj.__name__.startswith(plugin_module_name):
continue
_add_routes(app, obj, plugin_module_name)
def get_success_response(data: Any) -> Response:
body = {
"code": RETURN_API_SUCCESS,
"data": data,
"msg": "操作成功",
"success": True,
"time": get_current_time_as_millis(),
}
return web.json_response(body)