Let plugins read their own files directly
This commit is contained in:
parent
8f806a2594
commit
6487a7a8a5
6 changed files with 52 additions and 22 deletions
|
@ -16,6 +16,7 @@
|
||||||
from typing import Optional, Union, IO
|
from typing import Optional, Union, IO
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import zipfile
|
import zipfile
|
||||||
|
import glob
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ruamel.yaml import YAML, YAMLError
|
from ruamel.yaml import YAML, YAMLError
|
||||||
|
@ -94,8 +95,9 @@ def write_plugin(meta: PluginMeta, output: Union[str, IO]) -> None:
|
||||||
else:
|
else:
|
||||||
print(Fore.YELLOW + f"Module {module} not found, skipping" + Fore.RESET)
|
print(Fore.YELLOW + f"Module {module} not found, skipping" + Fore.RESET)
|
||||||
|
|
||||||
for file in meta.extra_files:
|
for pattern in meta.extra_files:
|
||||||
zip.write(file)
|
for file in glob.iglob(pattern):
|
||||||
|
zip.write(file)
|
||||||
|
|
||||||
|
|
||||||
def upload_plugin(output: Union[str, IO], server: str) -> None:
|
def upload_plugin(output: Union[str, IO], server: str) -> None:
|
||||||
|
|
|
@ -199,7 +199,7 @@ class PluginInstance:
|
||||||
self.config = config_class(self.load_config, base_cfg_func, self.save_config)
|
self.config = config_class(self.load_config, base_cfg_func, self.save_config)
|
||||||
self.plugin = cls(client=self.client.client, loop=self.loop, http=self.client.http_client,
|
self.plugin = cls(client=self.client.client, loop=self.loop, http=self.client.http_client,
|
||||||
instance_id=self.id, log=self.log, config=self.config,
|
instance_id=self.id, log=self.log, config=self.config,
|
||||||
database=self.inst_db, webapp=self.inst_webapp,
|
database=self.inst_db, loader=self.loader, webapp=self.inst_webapp,
|
||||||
webapp_url=self.inst_webapp_url)
|
webapp_url=self.inst_webapp_url)
|
||||||
try:
|
try:
|
||||||
await self.plugin.internal_start()
|
await self.plugin.internal_start()
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
from .abc import PluginLoader, PluginClass, IDConflictError, PluginMeta
|
from .abc import BasePluginLoader, PluginLoader, PluginClass, IDConflictError, PluginMeta
|
||||||
from .zip import ZippedPluginLoader, MaubotZipImportError
|
from .zip import ZippedPluginLoader, MaubotZipImportError
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# maubot - A plugin-based Matrix bot system.
|
# maubot - A plugin-based Matrix bot system.
|
||||||
# Copyright (C) 2019 Tulir Asokan
|
# Copyright (C) 2021 Tulir Asokan
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -65,7 +65,30 @@ class PluginMeta(SerializableAttrs['PluginMeta']):
|
||||||
soft_dependencies: List[str] = []
|
soft_dependencies: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
class PluginLoader(ABC):
|
class BasePluginLoader(ABC):
|
||||||
|
meta: PluginMeta
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def source(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sync_read_file(self, path: str) -> bytes:
|
||||||
|
raise NotImplementedError("This loader doesn't support synchronous operations")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def read_file(self, path: str) -> bytes:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sync_list_files(self, directory: str) -> List[str]:
|
||||||
|
raise NotImplementedError("This loader doesn't support synchronous operations")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_files(self, directory: str) -> List[str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PluginLoader(BasePluginLoader, ABC):
|
||||||
id_cache: Dict[str, 'PluginLoader'] = {}
|
id_cache: Dict[str, 'PluginLoader'] = {}
|
||||||
|
|
||||||
meta: PluginMeta
|
meta: PluginMeta
|
||||||
|
@ -85,15 +108,6 @@ class PluginLoader(ABC):
|
||||||
"instances": [instance.to_dict() for instance in self.references],
|
"instances": [instance.to_dict() for instance in self.references],
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def source(self) -> str:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def read_file(self, path: str) -> bytes:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def stop_instances(self) -> None:
|
async def stop_instances(self) -> None:
|
||||||
await asyncio.gather(*[instance.stop() for instance
|
await asyncio.gather(*[instance.stop() for instance
|
||||||
in self.references if instance.started])
|
in self.references if instance.started])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# maubot - A plugin-based Matrix bot system.
|
# maubot - A plugin-based Matrix bot system.
|
||||||
# Copyright (C) 2019 Tulir Asokan
|
# Copyright (C) 2021 Tulir Asokan
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -106,9 +106,20 @@ class ZippedPluginLoader(PluginLoader):
|
||||||
f"meta={self.meta} "
|
f"meta={self.meta} "
|
||||||
f"loaded={self._loaded is not None}>")
|
f"loaded={self._loaded is not None}>")
|
||||||
|
|
||||||
async def read_file(self, path: str) -> bytes:
|
def sync_read_file(self, path: str) -> bytes:
|
||||||
return self._file.read(path)
|
return self._file.read(path)
|
||||||
|
|
||||||
|
async def read_file(self, path: str) -> bytes:
|
||||||
|
return self.sync_read_file(path)
|
||||||
|
|
||||||
|
def sync_list_files(self, directory: str) -> List[str]:
|
||||||
|
directory = directory.rstrip("/")
|
||||||
|
return [file.filename for file in self._file.filelist
|
||||||
|
if os.path.dirname(file.filename) == directory]
|
||||||
|
|
||||||
|
async def list_files(self, directory: str) -> List[str]:
|
||||||
|
return self.sync_list_files(directory)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _read_meta(source) -> Tuple[ZipFile, PluginMeta]:
|
def _read_meta(source) -> Tuple[ZipFile, PluginMeta]:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# maubot - A plugin-based Matrix bot system.
|
# maubot - A plugin-based Matrix bot system.
|
||||||
# Copyright (C) 2019 Tulir Asokan
|
# Copyright (C) 2021 Tulir Asokan
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
from typing import Type, Optional, TYPE_CHECKING
|
from typing import Type, Optional, TYPE_CHECKING
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from logging import Logger
|
|
||||||
from asyncio import AbstractEventLoop
|
from asyncio import AbstractEventLoop
|
||||||
|
|
||||||
from sqlalchemy.engine.base import Engine
|
from sqlalchemy.engine.base import Engine
|
||||||
|
@ -23,26 +22,29 @@ from aiohttp import ClientSession
|
||||||
from yarl import URL
|
from yarl import URL
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from mautrix.util.logging import TraceLogger
|
||||||
from mautrix.util.config import BaseProxyConfig
|
from mautrix.util.config import BaseProxyConfig
|
||||||
from .client import MaubotMatrixClient
|
from .client import MaubotMatrixClient
|
||||||
from .plugin_server import PluginWebApp
|
from .plugin_server import PluginWebApp
|
||||||
|
from .loader import BasePluginLoader
|
||||||
|
|
||||||
|
|
||||||
class Plugin(ABC):
|
class Plugin(ABC):
|
||||||
client: 'MaubotMatrixClient'
|
client: 'MaubotMatrixClient'
|
||||||
http: ClientSession
|
http: ClientSession
|
||||||
id: str
|
id: str
|
||||||
log: Logger
|
log: 'TraceLogger'
|
||||||
loop: AbstractEventLoop
|
loop: AbstractEventLoop
|
||||||
|
loader: 'BasePluginLoader'
|
||||||
config: Optional['BaseProxyConfig']
|
config: Optional['BaseProxyConfig']
|
||||||
database: Optional[Engine]
|
database: Optional[Engine]
|
||||||
webapp: Optional['PluginWebApp']
|
webapp: Optional['PluginWebApp']
|
||||||
webapp_url: Optional[URL]
|
webapp_url: Optional[URL]
|
||||||
|
|
||||||
def __init__(self, client: 'MaubotMatrixClient', loop: AbstractEventLoop, http: ClientSession,
|
def __init__(self, client: 'MaubotMatrixClient', loop: AbstractEventLoop, http: ClientSession,
|
||||||
instance_id: str, log: Logger, config: Optional['BaseProxyConfig'],
|
instance_id: str, log: 'TraceLogger', config: Optional['BaseProxyConfig'],
|
||||||
database: Optional[Engine], webapp: Optional['PluginWebApp'],
|
database: Optional[Engine], webapp: Optional['PluginWebApp'],
|
||||||
webapp_url: Optional[str]) -> None:
|
webapp_url: Optional[str], loader: 'BasePluginLoader') -> None:
|
||||||
self.client = client
|
self.client = client
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
self.http = http
|
self.http = http
|
||||||
|
@ -52,6 +54,7 @@ class Plugin(ABC):
|
||||||
self.database = database
|
self.database = database
|
||||||
self.webapp = webapp
|
self.webapp = webapp
|
||||||
self.webapp_url = URL(webapp_url) if webapp_url else None
|
self.webapp_url = URL(webapp_url) if webapp_url else None
|
||||||
|
self.loader = loader
|
||||||
self._handlers_at_startup = []
|
self._handlers_at_startup = []
|
||||||
|
|
||||||
def register_handler_class(self, obj) -> None:
|
def register_handler_class(self, obj) -> None:
|
||||||
|
|
Loading…
Reference in a new issue