Add configuration for plugins
This commit is contained in:
parent
ac5f059ef4
commit
b29a7d186e
7 changed files with 57 additions and 9 deletions
|
@ -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 = []
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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} "
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue