Fix things in standalone mode
This commit is contained in:
parent
7c9668d8bc
commit
61711e8329
6 changed files with 140 additions and 29 deletions
|
@ -1,5 +1,5 @@
|
||||||
# supportportal - A maubot plugin to manage customer support on Matrix.
|
# 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
|
||||||
|
@ -13,12 +13,13 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
from typing import Optional
|
from typing import Optional, Type, cast
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
import logging.config
|
import logging.config
|
||||||
import importlib
|
import importlib
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import os.path
|
||||||
import signal
|
import signal
|
||||||
import copy
|
import copy
|
||||||
import sys
|
import sys
|
||||||
|
@ -29,22 +30,26 @@ import sqlalchemy as sql
|
||||||
|
|
||||||
from mautrix.util.config import RecursiveDict, BaseMissingError
|
from mautrix.util.config import RecursiveDict, BaseMissingError
|
||||||
from mautrix.util.db import Base
|
from mautrix.util.db import Base
|
||||||
from mautrix.types import (UserID, Filter, RoomFilter, RoomEventFilter, StrippedStateEvent,
|
from mautrix.util.logging import TraceLogger
|
||||||
EventType, Membership)
|
from mautrix.types import (Filter, RoomFilter, RoomEventFilter, StrippedStateEvent,
|
||||||
|
EventType, Membership, FilterID, SyncToken)
|
||||||
|
|
||||||
from .config import Config
|
|
||||||
from ..plugin_base import Plugin
|
from ..plugin_base import Plugin
|
||||||
from ..loader import PluginMeta
|
from ..loader import PluginMeta
|
||||||
from ..matrix import MaubotMatrixClient
|
from ..matrix import MaubotMatrixClient
|
||||||
from ..lib.store_proxy import SyncStoreProxy
|
from ..lib.store_proxy import SyncStoreProxy
|
||||||
from ..__meta__ import __version__
|
from ..__meta__ import __version__
|
||||||
|
from .config import Config
|
||||||
|
from .loader import FileSystemLoader
|
||||||
|
from .database import NextBatch
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="A plugin-based Matrix bot system -- standalone mode.",
|
description="A plugin-based Matrix bot system -- standalone mode.",
|
||||||
prog="python -m maubot.standalone")
|
prog="python -m maubot.standalone")
|
||||||
parser.add_argument("-c", "--config", type=str, default="config.yaml",
|
parser.add_argument("-c", "--config", type=str, default="config.yaml",
|
||||||
metavar="<path>", help="the path to your config file")
|
metavar="<path>", help="the path to your config file")
|
||||||
parser.add_argument("-b", "--base-config", type=str, default="example-config.yaml",
|
parser.add_argument("-b", "--base-config", type=str,
|
||||||
|
default="pkg://maubot.standalone/example-config.yaml",
|
||||||
metavar="<path>", help="the path to the example config "
|
metavar="<path>", help="the path to the example config "
|
||||||
"(for automatic config updates)")
|
"(for automatic config updates)")
|
||||||
parser.add_argument("-m", "--meta", type=str, default="maubot.yaml",
|
parser.add_argument("-m", "--meta", type=str, default="maubot.yaml",
|
||||||
|
@ -75,23 +80,11 @@ else:
|
||||||
module = meta.modules[0]
|
module = meta.modules[0]
|
||||||
main_class = meta.main_class
|
main_class = meta.main_class
|
||||||
bot_module = importlib.import_module(module)
|
bot_module = importlib.import_module(module)
|
||||||
plugin = getattr(bot_module, main_class)
|
plugin: Type[Plugin] = getattr(bot_module, main_class)
|
||||||
|
loader = FileSystemLoader(os.path.dirname(args.meta))
|
||||||
|
|
||||||
log.info(f"Initializing standalone {meta.id} v{meta.version} on maubot {__version__}")
|
log.info(f"Initializing standalone {meta.id} v{meta.version} on maubot {__version__}")
|
||||||
|
|
||||||
|
|
||||||
class NextBatch(Base):
|
|
||||||
__tablename__ = "standalone_next_batch"
|
|
||||||
|
|
||||||
user_id: str = sql.Column(sql.String(255), primary_key=True)
|
|
||||||
next_batch: str = sql.Column(sql.String(255))
|
|
||||||
filter_id: str = sql.Column(sql.String(255))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, user_id: UserID) -> Optional['NextBatch']:
|
|
||||||
return cls._select_one_or_none(cls.c.user_id == user_id)
|
|
||||||
|
|
||||||
|
|
||||||
log.debug("Opening database")
|
log.debug("Opening database")
|
||||||
db = sql.create_engine(config["database"])
|
db = sql.create_engine(config["database"])
|
||||||
Base.metadata.bind = db
|
Base.metadata.bind = db
|
||||||
|
@ -104,7 +97,7 @@ access_token = config["user.credentials.access_token"]
|
||||||
|
|
||||||
nb = NextBatch.get(user_id)
|
nb = NextBatch.get(user_id)
|
||||||
if not nb:
|
if not nb:
|
||||||
nb = NextBatch(user_id=user_id, next_batch="", filter_id="")
|
nb = NextBatch(user_id=user_id, next_batch=SyncToken(""), filter_id=FilterID(""))
|
||||||
nb.insert()
|
nb.insert()
|
||||||
|
|
||||||
bot_config = None
|
bot_config = None
|
||||||
|
@ -135,8 +128,8 @@ if meta.config:
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
client: MaubotMatrixClient = None
|
client: Optional[MaubotMatrixClient] = None
|
||||||
bot: Plugin = None
|
bot: Optional[Plugin] = None
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
@ -144,9 +137,10 @@ async def main():
|
||||||
|
|
||||||
global client, bot
|
global client, bot
|
||||||
|
|
||||||
|
client_log = logging.getLogger("maubot.client").getChild(user_id)
|
||||||
client = MaubotMatrixClient(mxid=user_id, base_url=homeserver, token=access_token,
|
client = MaubotMatrixClient(mxid=user_id, base_url=homeserver, token=access_token,
|
||||||
client_session=http_client, loop=loop, store=SyncStoreProxy(nb),
|
client_session=http_client, loop=loop, log=client_log,
|
||||||
log=logging.getLogger("maubot.client").getChild(user_id))
|
sync_store=SyncStoreProxy(nb))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -181,9 +175,10 @@ async def main():
|
||||||
if displayname != "disable":
|
if displayname != "disable":
|
||||||
await client.set_displayname(displayname)
|
await client.set_displayname(displayname)
|
||||||
|
|
||||||
|
plugin_log = cast(TraceLogger, logging.getLogger("maubot.instance.__main__"))
|
||||||
bot = plugin(client=client, loop=loop, http=http_client, instance_id="__main__",
|
bot = plugin(client=client, loop=loop, http=http_client, instance_id="__main__",
|
||||||
log=logging.getLogger("maubot.instance.__main__"), config=bot_config,
|
log=plugin_log, config=bot_config, database=db if meta.database else None,
|
||||||
database=db if meta.database else None, webapp=None, webapp_url=None)
|
webapp=None, webapp_url=None, loader=loader)
|
||||||
|
|
||||||
await bot.internal_start()
|
await bot.internal_start()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
33
maubot/standalone/database.py
Normal file
33
maubot/standalone/database.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# maubot - A plugin-based Matrix bot system.
|
||||||
|
# Copyright (C) 2021 Tulir Asokan
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# 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 Optional
|
||||||
|
|
||||||
|
import sqlalchemy as sql
|
||||||
|
|
||||||
|
from mautrix.util.db import Base
|
||||||
|
from mautrix.types import UserID, SyncToken, FilterID
|
||||||
|
|
||||||
|
|
||||||
|
class NextBatch(Base):
|
||||||
|
__tablename__ = "standalone_next_batch"
|
||||||
|
|
||||||
|
user_id: UserID = sql.Column(sql.String(255), primary_key=True)
|
||||||
|
next_batch: SyncToken = sql.Column(sql.String(255))
|
||||||
|
filter_id: FilterID = sql.Column(sql.String(255))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls, user_id: UserID) -> Optional['NextBatch']:
|
||||||
|
return cls._select_one_or_none(cls.c.user_id == user_id)
|
41
maubot/standalone/example-config.yaml
Normal file
41
maubot/standalone/example-config.yaml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# Bot account details
|
||||||
|
user:
|
||||||
|
credentials:
|
||||||
|
id: "@bot:example.com"
|
||||||
|
homeserver: https://example.com
|
||||||
|
access_token: foo
|
||||||
|
# Enable /sync? This is not needed for purely unencrypted webhook-based bots, but is necessary in most other cases.
|
||||||
|
sync: true
|
||||||
|
# Automatically accept invites?
|
||||||
|
autojoin: false
|
||||||
|
# The displayname and avatar URL to set for the bot on startup.
|
||||||
|
displayname: Standalone Bot
|
||||||
|
avatar_url: mxc://maunium.net/AKwRzQkTbggfVZGEqexbYLIO
|
||||||
|
|
||||||
|
# The database for the plugin. Also used to store the sync token.
|
||||||
|
database: sqlite:///bot.db
|
||||||
|
|
||||||
|
# Config for the plugin. Refer to the plugin's base-config.yaml to find what (if anything) to put here.
|
||||||
|
plugin_config: {}
|
||||||
|
|
||||||
|
# Standard Python logging configuration
|
||||||
|
logging:
|
||||||
|
version: 1
|
||||||
|
formatters:
|
||||||
|
colored:
|
||||||
|
(): maubot.lib.color_log.ColorFormatter
|
||||||
|
format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s"
|
||||||
|
handlers:
|
||||||
|
console:
|
||||||
|
class: logging.StreamHandler
|
||||||
|
formatter: colored
|
||||||
|
loggers:
|
||||||
|
maubot:
|
||||||
|
level: DEBUG
|
||||||
|
mau:
|
||||||
|
level: DEBUG
|
||||||
|
aiohttp:
|
||||||
|
level: INFO
|
||||||
|
root:
|
||||||
|
level: DEBUG
|
||||||
|
handlers: [console]
|
41
maubot/standalone/loader.py
Normal file
41
maubot/standalone/loader.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# maubot - A plugin-based Matrix bot system.
|
||||||
|
# Copyright (C) 2021 Tulir Asokan
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# 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 List
|
||||||
|
import os.path
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ..loader import BasePluginLoader
|
||||||
|
|
||||||
|
class FileSystemLoader(BasePluginLoader):
|
||||||
|
def __init__(self, path: str) -> None:
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source(self) -> str:
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
def sync_read_file(self, path: str) -> bytes:
|
||||||
|
with open(os.path.join(self.path, path), "rb") as file:
|
||||||
|
return file.read()
|
||||||
|
|
||||||
|
async def read_file(self, path: str) -> bytes:
|
||||||
|
return self.sync_read_file(path)
|
||||||
|
|
||||||
|
def sync_list_files(self, directory: str) -> List[str]:
|
||||||
|
return os.listdir(os.path.join(self.path, directory))
|
||||||
|
|
||||||
|
async def list_files(self, directory: str) -> List[str]:
|
||||||
|
return self.sync_list_files(directory)
|
1
setup.py
1
setup.py
|
@ -70,5 +70,6 @@ setuptools.setup(
|
||||||
"management/frontend/build/static/media/*",
|
"management/frontend/build/static/media/*",
|
||||||
],
|
],
|
||||||
"maubot.cli": ["res/*"],
|
"maubot.cli": ["res/*"],
|
||||||
|
"maubot.standalone": ["example-config.yaml"],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue