This commit is contained in:
夜坂雅 2022-09-09 14:47:13 +08:00
parent 5683bafee0
commit 8fd56ade57
11 changed files with 48 additions and 163 deletions

View file

@ -4,8 +4,7 @@ from nio import AsyncClient, MatrixRoom, RoomMessageImage, RoomMessageText, Stic
from nyx_bot.chat_functions import send_quote_image, send_text_to_room, send_user_image
from nyx_bot.config import Config
from nyx_bot.exceptions import NyxBotValueError
from nyx_bot.storage import Storage
from nyx_bot.errors import NyxBotValueError
logger = logging.getLogger(__name__)
@ -14,7 +13,6 @@ class Command:
def __init__(
self,
client: AsyncClient,
store: Storage,
config: Config,
command: str,
room: MatrixRoom,
@ -27,8 +25,6 @@ class Command:
Args:
client: The client to communicate to matrix with.
store: Bot storage.
config: Bot configuration parameters.
command: The command and arguments.
@ -38,7 +34,6 @@ class Command:
event: The event describing the command.
"""
self.client = client
self.store = store
self.config = config
self.command = command
self.room = room
@ -107,7 +102,9 @@ class Command:
f"https://matrix.to/#/{self.room.room_id}/{target_event.event_id}"
)
content["body"] = f"Sticker of {matrixdotto_url}"
content["m.relates_to"] = {"m.in_reply_to": {"event_id": self.event.event_id}}
content["m.relates_to"] = {
"m.in_reply_to": {"event_id": self.event.event_id}
}
await self.client.room_send(
self.room.room_id, message_type="m.sticker", content=content
)

View file

@ -14,25 +14,22 @@ from nio import (
from nyx_bot.bot_commands import Command
from nyx_bot.chat_functions import send_exception, send_jerryxiao
from nyx_bot.config import Config
from nyx_bot.storage import Storage
from nyx_bot.utils import get_reply_to
logger = logging.getLogger(__name__)
class Callbacks:
def __init__(self, client: AsyncClient, store: Storage, config: Config):
def __init__(self, client: AsyncClient, config: Config):
"""
Args:
client: nio client used to interact with matrix.
store: Bot storage.
config: Bot configuration parameters.
"""
self.client = client
self.store = store
self.config = config
self.disable_jerryxiao_for = config.disable_jerryxiao_for
self.command_prefix = config.command_prefix
self.replace_map = {}
@ -85,6 +82,10 @@ class Callbacks:
msg = i
break
if room.room_id in self.disable_jerryxiao_for:
# Stop considering JerryXiao prefix.
has_jerryxiao_prefix = False
if has_jerryxiao_prefix and reply_to:
if msg.startswith("/"):
await send_jerryxiao(self.client, room, event, "/", reply_to, msg)
@ -106,7 +107,6 @@ class Callbacks:
command = Command(
self.client,
self.store,
self.config,
msg,
room,

View file

@ -18,7 +18,7 @@ from nio import (
)
from wand.image import Image
from nyx_bot.exceptions import NyxBotRuntimeError, NyxBotValueError
from nyx_bot.errors import NyxBotRuntimeError, NyxBotValueError
from nyx_bot.parsers import MatrixHTMLParser
from nyx_bot.quote_image import make_quote_image
from nyx_bot.utils import (

View file

@ -105,6 +105,10 @@ class Config:
self.command_prefix = self._get_cfg(["command_prefix"], default="!c") + " "
self.disable_jerryxiao_for = self._get_cfg(['disable_jerryxiao_for'], [])
if isinstance(self.disable_jerryxiao_for, list):
raise ConfigError("disable_jerryxiao_for should be a list of room ID")
def _get_cfg(
self,
path: List[str],
@ -134,3 +138,14 @@ class Config:
# We found the option. Return it.
return config
# Read user-configured options from a config file.
# A different config file path can be specified as the first command line argument
if len(sys.argv) > 1:
config_path = sys.argv[1]
else:
config_path = "config.yaml"
# Read the parsed config file and create a Config object
config = Config(config_path)

View file

@ -10,3 +10,13 @@ class ConfigError(RuntimeError):
def __init__(self, msg: str):
super(ConfigError, self).__init__("%s" % (msg,))
class NyxBotValueError(ValueError):
def __init__(self, reason):
super().__init__(reason)
class NyxBotRuntimeError(RuntimeError):
def __init__(self, reason):
super().__init__(reason)

View file

@ -1,8 +0,0 @@
class NyxBotValueError(ValueError):
def __init__(self, reason):
super().__init__(reason)
class NyxBotRuntimeError(RuntimeError):
def __init__(self, reason):
super().__init__(reason)

View file

@ -1,7 +1,6 @@
#!/usr/bin/env python3
import asyncio
import logging
import sys
from asyncio.exceptions import TimeoutError
from time import sleep
@ -15,10 +14,10 @@ from nio import (
RoomMessageText,
UnknownEvent,
)
from nio.store.database import DefaultStore
from nyx_bot.callbacks import Callbacks
from nyx_bot.config import Config
from nyx_bot.storage import Storage
from nyx_bot.config import config
logger = logging.getLogger(__name__)
@ -26,23 +25,11 @@ logger = logging.getLogger(__name__)
async def main():
"""The first function that is run when starting the bot"""
# Read user-configured options from a config file.
# A different config file path can be specified as the first command line argument
if len(sys.argv) > 1:
config_path = sys.argv[1]
else:
config_path = "config.yaml"
# Read the parsed config file and create a Config object
config = Config(config_path)
# Configure the database
store = Storage(config.database)
# Configuration options for the AsyncClient
client_config = AsyncClientConfig(
max_limit_exceeded=0,
max_timeouts=0,
store=DefaultStore,
store_sync_tokens=True,
encryption_enabled=False,
)
@ -61,7 +48,7 @@ async def main():
client.user_id = config.user_id
# Set up event callbacks
callbacks = Callbacks(client, store, config)
callbacks = Callbacks(client, config)
client.add_event_callback(callbacks.message, (RoomMessageText,))
client.add_event_callback(callbacks.unknown, (UnknownEvent,))
client.add_event_callback(

View file

@ -22,7 +22,7 @@ BORDER_MARGIN = 8
MASK_FILE = os.path.join(nyx_bot.__path__[0], "mask.png")
PANGO_MARKUP_TEMPLATE = """\
<span size="larger" foreground="#065279" weight="bold">{}</span>
<span size="larger" foreground="#1F4788" weight="bold">{}</span>
{}
"""

View file

@ -1,126 +1,5 @@
import logging
from typing import Any, Dict
# The latest migration version of the database.
#
# Database migrations are applied starting from the number specified in the database's
# `migration_version` table + 1 (or from 0 if this table does not yet exist) up until
# the version specified here.
#
# When a migration is performed, the `migration_version` table should be incremented.
latest_migration_version = 0
# from peewee import Model, PostgresqlDatabase, SqliteDatabase, TextField
logger = logging.getLogger(__name__)
class Storage:
def __init__(self, database_config: Dict[str, str]):
"""Setup the database.
Runs an initial setup or migrations depending on whether a database file has already
been created.
Args:
database_config: a dictionary containing the following keys:
* type: A string, one of "sqlite" or "postgres".
* connection_string: A string, featuring a connection string that
be fed to each respective db library's `connect` method.
"""
self.conn = self._get_database_connection(
database_config["type"], database_config["connection_string"]
)
self.cursor = self.conn.cursor()
self.db_type = database_config["type"]
# Try to check the current migration version
migration_level = 0
try:
self._execute("SELECT version FROM migration_version")
row = self.cursor.fetchone()
migration_level = row[0]
except Exception:
self._initial_setup()
finally:
if migration_level < latest_migration_version:
self._run_migrations(migration_level)
logger.info(f"Database initialization of type '{self.db_type}' complete")
def _get_database_connection(
self, database_type: str, connection_string: str
) -> Any:
"""Creates and returns a connection to the database"""
if database_type == "sqlite":
import sqlite3
# Initialize a connection to the database, with autocommit on
return sqlite3.connect(connection_string, isolation_level=None)
elif database_type == "postgres":
import psycopg2
conn = psycopg2.connect(connection_string)
# Autocommit on
conn.set_isolation_level(0)
return conn
def _initial_setup(self) -> None:
"""Initial setup of the database"""
logger.info("Performing initial database setup...")
# Set up the migration_version table
self._execute(
"""
CREATE TABLE migration_version (
version INTEGER PRIMARY KEY
)
"""
)
# Initially set the migration version to 0
self._execute(
"""
INSERT INTO migration_version (
version
) VALUES (?)
""",
(0,),
)
# Set up any other necessary database tables here
logger.info("Database setup complete")
def _run_migrations(self, current_migration_version: int) -> None:
"""Execute database migrations. Migrates the database to the
`latest_migration_version`.
Args:
current_migration_version: The migration version that the database is
currently at.
"""
logger.debug("Checking for necessary database migrations...")
# if current_migration_version < 1:
# logger.info("Migrating the database from v0 to v1...")
#
# # Add new table, delete old ones, etc.
#
# # Update the stored migration version
# self._execute("UPDATE migration_version SET version = 1")
#
# logger.info("Database migrated to v1")
def _execute(self, *args) -> None:
"""A wrapper around cursor.execute that transforms placeholder ?'s to %s for postgres.
This allows for the support of queries that are compatible with both postgres and sqlite.
Args:
args: Arguments passed to cursor.execute.
"""
if self.db_type == "postgres":
self.cursor.execute(args[0].replace("?", "%s"), *args[1:])
else:
self.cursor.execute(*args)

View file

@ -47,3 +47,7 @@ logging:
console_logging:
# Whether logging to the console is enabled
enabled: true
# Disable Jerry Xiao like feature for the following room ID
disable_jerryxiao_for:
- '!XXXXXXXXXXXXXXXXXX:example.com'

View file

@ -31,11 +31,12 @@ setup(
description="A matrix bot to do amazing things!",
packages=find_packages(exclude=["tests", "tests.*"]),
install_requires=[
"matrix-nio>=0.10.0",
"matrix-nio[e2e]>=0.10.0",
"Markdown>=3.1.1",
"PyYAML>=5.1.2",
"Wand",
"python-magic",
"peewee",
],
extras_require={
"postgres": ["psycopg2>=2.8.5"],