Add configuration for plugins

This commit is contained in:
Tulir Asokan 2018-10-20 18:39:16 +03:00
parent ac5f059ef4
commit b29a7d186e
7 changed files with 57 additions and 9 deletions

View file

@ -70,6 +70,7 @@ class ParsedCommand:
def _init_active(self, command: Command) -> None:
self.name = command.syntax
self.is_passive = False
self.arguments = []
regex_builder = []
sw_builder = []

View file

@ -16,10 +16,10 @@
import random
import string
from mautrix.util import BaseConfig
from mautrix.util import BaseFileConfig
class Config(BaseConfig):
class Config(BaseFileConfig):
@staticmethod
def _new_token() -> str:
return "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(64))

View file

@ -58,6 +58,7 @@ class DBPlugin(Base):
primary_user: UserID = Column(String(255),
ForeignKey("client.id", onupdate="CASCADE", ondelete="RESTRICT"),
nullable=False)
config: str = Column(Text, nullable=False, default='')
class DBClient(Base):

View file

@ -47,6 +47,10 @@ class PluginLoader(ABC):
def source(self) -> str:
pass
@abstractmethod
def read_file(self, path: str) -> bytes:
pass
@abstractmethod
def load(self) -> Type[PluginClass]:
pass

View file

@ -41,6 +41,7 @@ class ZippedPluginLoader(PluginLoader):
main_module: str
_loaded: Type[PluginClass]
_importer: zipimporter
_file: ZipFile
def __init__(self, path: str) -> None:
super().__init__()
@ -76,10 +77,13 @@ class ZippedPluginLoader(PluginLoader):
f"id='{self.id}' "
f"loaded={self._loaded is not None}>")
def read_file(self, path: str) -> bytes:
return self._file.read(path)
def _load_meta(self) -> None:
try:
file = ZipFile(self.path)
data = file.read("maubot.ini")
self._file = ZipFile(self.path)
data = self._file.read("maubot.ini")
except FileNotFoundError as e:
raise MaubotZipImportError("Maubot plugin not found") from e
except BadZipFile as e:

View file

@ -14,8 +14,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Dict, List, Optional
from ruamel.yaml.comments import CommentedMap
from ruamel.yaml import YAML
import logging
import io
from mautrix.util import BaseProxyConfig, RecursiveDict
from mautrix.types import UserID
from .db import DBPlugin
@ -25,6 +29,9 @@ from .plugin_base import Plugin
log = logging.getLogger("maubot.plugin")
yaml = YAML()
yaml.indent(4)
class PluginInstance:
cache: Dict[str, 'PluginInstance'] = {}
@ -34,10 +41,12 @@ class PluginInstance:
loader: PluginLoader
client: Client
plugin: Plugin
config: BaseProxyConfig
def __init__(self, db_instance: DBPlugin):
self.db_instance = db_instance
self.log = logging.getLogger(f"maubot.plugin.{self.id}")
self.config = None
self.cache[self.id] = self
def load(self) -> None:
@ -53,12 +62,31 @@ class PluginInstance:
self.enabled = False
self.log.debug("Plugin instance dependencies loaded")
def load_config(self) -> CommentedMap:
return yaml.load(self.db_instance.config)
def load_config_base(self) -> Optional[RecursiveDict[CommentedMap]]:
try:
base = self.loader.read_file("base-config.yaml")
return yaml.load(base.decode("utf-8"))
except (FileNotFoundError, KeyError):
return None
def save_config(self, data: RecursiveDict[CommentedMap]) -> None:
buf = io.StringIO()
yaml.dump(data, buf)
self.db_instance.config = buf.getvalue()
async def start(self) -> None:
if not self.enabled:
self.log.warn(f"Plugin disabled, not starting.")
self.log.warning(f"Plugin disabled, not starting.")
return
cls = self.loader.load()
self.plugin = cls(self.client.client, self.id, self.log)
config_class = cls.get_config_class()
if config_class:
self.config = config_class(self.load_config, self.load_config_base,
self.save_config)
self.plugin = cls(self.client.client, self.id, self.log, self.config)
self.loader.references |= {self}
await self.plugin.start()
self.log.info(f"Started instance of {self.loader.id} v{self.loader.version} "

View file

@ -13,30 +13,40 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING
from typing import Type, Optional, TYPE_CHECKING
from logging import Logger
from abc import ABC
from abc import ABC, abstractmethod
if TYPE_CHECKING:
from .client import MaubotMatrixClient
from .command_spec import CommandSpec
from mautrix.util import BaseProxyConfig
class Plugin(ABC):
client: 'MaubotMatrixClient'
id: str
log: Logger
config: Optional['BaseProxyConfig']
def __init__(self, client: 'MaubotMatrixClient', plugin_instance_id: str, log: Logger) -> None:
def __init__(self, client: 'MaubotMatrixClient', plugin_instance_id: str, log: Logger,
config: Optional['BaseProxyConfig']) -> None:
self.client = client
self.id = plugin_instance_id
self.log = log
self.config = config
def set_command_spec(self, spec: 'CommandSpec') -> None:
self.client.set_command_spec(self.id, spec)
@abstractmethod
async def start(self) -> None:
pass
@abstractmethod
async def stop(self) -> None:
pass
@classmethod
def get_config_class(cls) -> Optional[Type['BaseProxyConfig']]:
return None