Update
This commit is contained in:
parent
5683bafee0
commit
8fd56ade57
11 changed files with 48 additions and 163 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
class NyxBotValueError(ValueError):
|
||||
def __init__(self, reason):
|
||||
super().__init__(reason)
|
||||
|
||||
|
||||
class NyxBotRuntimeError(RuntimeError):
|
||||
def __init__(self, reason):
|
||||
super().__init__(reason)
|
|
@ -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(
|
||||
|
|
|
@ -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>
|
||||
{}
|
||||
"""
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
3
setup.py
3
setup.py
|
@ -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"],
|
||||
|
|
Loading…
Reference in a new issue