This commit releases a custom Matrix Python SDK. This means that the most important classes---MatrixClient, Room, and MatrixHttpApi---are inherited by Custom classes. This enables us to change behaviour or add new features in a well structured and predictable way. The first issue that is solved with this new custom SDK is the problem that was introduced in #2.
This commit is contained in:
parent
e4d325955c
commit
9e139a0f3e
10
matrix_bot_api/custom_matrix_client/api.py
Normal file
10
matrix_bot_api/custom_matrix_client/api.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from matrix_client.api import MatrixHttpApi
|
||||||
|
|
||||||
|
class CustomMatrixHttpApi(MatrixHttpApi):
|
||||||
|
def __init__(
|
||||||
|
self, base_url, token=None, identity=None,
|
||||||
|
default_429_wait_ms=5000,
|
||||||
|
use_authorization_header=True
|
||||||
|
):
|
||||||
|
|
||||||
|
super().__init__(base_url, token, identity, default_429_wait_ms)
|
76
matrix_bot_api/custom_matrix_client/client.py
Normal file
76
matrix_bot_api/custom_matrix_client/client.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import os
|
||||||
|
import hjson
|
||||||
|
|
||||||
|
from matrix_client.client import MatrixClient
|
||||||
|
|
||||||
|
from .api import CustomMatrixHttpApi
|
||||||
|
from .room import CustomRoom
|
||||||
|
|
||||||
|
MESSAGES_DIR = os.path.join(os.path.dirname(__file__), 'messages')
|
||||||
|
MESSAGES_LOCATION = MESSAGES_DIR + '/messages.dutch.hjson'
|
||||||
|
|
||||||
|
class CustomMatrixClient(MatrixClient):
|
||||||
|
def __init__(self, base_url, token=None):
|
||||||
|
super().__init__(base_url, token)
|
||||||
|
|
||||||
|
self.api = CustomMatrixHttpApi(base_url, token)
|
||||||
|
|
||||||
|
# Load messages
|
||||||
|
with open(MESSAGES_LOCATION) as hjson_data:
|
||||||
|
self.messages = hjson.load(hjson_data)
|
||||||
|
|
||||||
|
|
||||||
|
def _mkroom(self, room_id):
|
||||||
|
room = CustomRoom(self, room_id)
|
||||||
|
|
||||||
|
self.rooms[room_id] = room
|
||||||
|
return self.rooms[room_id]
|
||||||
|
|
||||||
|
def create_direct_room(self, invitees=None):
|
||||||
|
content = {
|
||||||
|
"visibility": "private",
|
||||||
|
"is_direct": True,
|
||||||
|
"invite": [invitees]
|
||||||
|
}
|
||||||
|
|
||||||
|
room_dict = self.api._send("POST", "/createRoom", content)
|
||||||
|
|
||||||
|
return self._mkroom(room_dict["room_id"])
|
||||||
|
|
||||||
|
|
||||||
|
def send_message_private_public(self, room, event, message):
|
||||||
|
"""This method takes a room, event, and message and makes sure
|
||||||
|
that the message is sent in a private room and not in a public
|
||||||
|
room. If no private room exists, it will create a private room
|
||||||
|
with the sender of the event.
|
||||||
|
"""
|
||||||
|
|
||||||
|
orig_room = room
|
||||||
|
found_room = False
|
||||||
|
|
||||||
|
for room_id, room in self.rooms.items():
|
||||||
|
joined_members = room.get_joined_members()
|
||||||
|
|
||||||
|
# Check for rooms with only two members
|
||||||
|
if len(joined_members) == 2:
|
||||||
|
# Check if sender is in that room
|
||||||
|
for member in joined_members:
|
||||||
|
if event['sender'] == member.user_id:
|
||||||
|
found_room = True
|
||||||
|
|
||||||
|
if found_room:
|
||||||
|
# If the flag is set, we do not need to check further rooms
|
||||||
|
break
|
||||||
|
|
||||||
|
# Send help message to an existing room or to a new room
|
||||||
|
if found_room:
|
||||||
|
room.send_html(message)
|
||||||
|
else:
|
||||||
|
room = self.create_direct_room(event['sender']);
|
||||||
|
room.send_html(message)
|
||||||
|
|
||||||
|
if room != orig_room:
|
||||||
|
display_name_sender = self.api.get_display_name(event['sender'])
|
||||||
|
orig_room.send_text(self.messages['private_message'].format(
|
||||||
|
display_name_sender))
|
||||||
|
|
6
matrix_bot_api/custom_matrix_client/room.py
Normal file
6
matrix_bot_api/custom_matrix_client/room.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from matrix_client.room import Room
|
||||||
|
|
||||||
|
|
||||||
|
class CustomRoom(Room):
|
||||||
|
def __init__(self, client, room_id):
|
||||||
|
super().__init__(client, room_id)
|
@ -9,17 +9,16 @@ import datetime as dt
|
|||||||
|
|
||||||
from pip._internal import main as pipmain
|
from pip._internal import main as pipmain
|
||||||
|
|
||||||
from matrix_client.client import MatrixClient
|
from matrix_client.api import MatrixRequestError
|
||||||
from matrix_client.api import MatrixRequestError, MatrixHttpApi
|
|
||||||
from matrix_client.user import User
|
|
||||||
|
|
||||||
from matrix_bot_api.mregex_handler import MRegexHandler
|
from matrix_bot_api.mregex_handler import MRegexHandler
|
||||||
|
|
||||||
|
from .custom_matrix_client.api import CustomMatrixHttpApi
|
||||||
|
from .custom_matrix_client.client import CustomMatrixClient
|
||||||
|
|
||||||
MESSAGES_DIR = os.path.join(os.path.dirname(__file__), 'messages')
|
MESSAGES_DIR = os.path.join(os.path.dirname(__file__), 'messages')
|
||||||
DATA_LOCATION = os.path.join(os.path.dirname(__file__), '../data/bot.db')
|
DATA_LOCATION = os.path.join(os.path.dirname(__file__), '../data/bot.db')
|
||||||
|
|
||||||
HELP_LOCATION = MESSAGES_DIR + '/help'
|
HELP_LOCATION = MESSAGES_DIR + '/help'
|
||||||
MESSAGES_LOCATION = MESSAGES_DIR + '/messages.dutch.hjson'
|
|
||||||
|
|
||||||
def eprint(*args, **kwargs):
|
def eprint(*args, **kwargs):
|
||||||
"""Print error messages to stderr"""
|
"""Print error messages to stderr"""
|
||||||
@ -32,7 +31,8 @@ class MatrixBotAPI:
|
|||||||
self.username = self.config['bot_credentials']['username']
|
self.username = self.config['bot_credentials']['username']
|
||||||
|
|
||||||
# Authenticate with given credentials
|
# Authenticate with given credentials
|
||||||
self.client = MatrixClient(self.config['bot_credentials']['server'])
|
self.client = CustomMatrixClient(
|
||||||
|
self.config['bot_credentials']['server'])
|
||||||
try:
|
try:
|
||||||
self.token = self.client.login_with_password(
|
self.token = self.client.login_with_password(
|
||||||
self.config['bot_credentials']['username'],
|
self.config['bot_credentials']['username'],
|
||||||
@ -41,13 +41,11 @@ class MatrixBotAPI:
|
|||||||
print(e)
|
print(e)
|
||||||
if e.code == 403:
|
if e.code == 403:
|
||||||
print("Bad username/password")
|
print("Bad username/password")
|
||||||
|
sys.exit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Invalid server URL")
|
print("Invalid server URL")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
sys.exit()
|
||||||
self.api = MatrixHttpApi(
|
|
||||||
self.config['bot_credentials']['server'],
|
|
||||||
token=self.token)
|
|
||||||
|
|
||||||
# Store allowed rooms
|
# Store allowed rooms
|
||||||
self.rooms = rooms
|
self.rooms = rooms
|
||||||
@ -63,7 +61,7 @@ class MatrixBotAPI:
|
|||||||
|
|
||||||
# Add all rooms we're currently in to self.rooms and add their
|
# Add all rooms we're currently in to self.rooms and add their
|
||||||
# callbacks
|
# callbacks
|
||||||
for room_id, room in self.client.get_rooms().items():
|
for room_id, room in self.client.rooms.items():
|
||||||
room.add_listener(self.handle_message)
|
room.add_listener(self.handle_message)
|
||||||
self.rooms.append(room_id)
|
self.rooms.append(room_id)
|
||||||
else:
|
else:
|
||||||
@ -86,10 +84,6 @@ class MatrixBotAPI:
|
|||||||
self.config['triggers']['help'], self.help)
|
self.config['triggers']['help'], self.help)
|
||||||
self.add_handler(self.help_handler)
|
self.add_handler(self.help_handler)
|
||||||
|
|
||||||
# Load messages
|
|
||||||
with open(MESSAGES_LOCATION) as hjson_data:
|
|
||||||
self.messages = hjson.load(hjson_data)
|
|
||||||
|
|
||||||
|
|
||||||
def add_plugins(self):
|
def add_plugins(self):
|
||||||
"""Acquire list of plugins from configuration, load them,
|
"""Acquire list of plugins from configuration, load them,
|
||||||
@ -103,30 +97,31 @@ class MatrixBotAPI:
|
|||||||
# ./plugins directory
|
# ./plugins directory
|
||||||
modules = []
|
modules = []
|
||||||
|
|
||||||
#try:
|
try:
|
||||||
# Loop through the available plugins, install their requirements,
|
# Loop through the available plugins, install their requirements,
|
||||||
# load them as module, run their setup, append them to a list,
|
# load them as module, run their setup, append them to a list,
|
||||||
# and add their handler variables
|
# and add their handler variables
|
||||||
for i, plugin in enumerate(self.config['plugins']):
|
for i, plugin in enumerate(self.config['plugins']):
|
||||||
# Install requirements
|
# Install requirements
|
||||||
self.install_requirements(plugin)
|
self.install_requirements(plugin)
|
||||||
|
|
||||||
# Dynamically load the module
|
# Dynamically load the module
|
||||||
modules.append(
|
modules.append(
|
||||||
importlib.import_module(
|
importlib.import_module(
|
||||||
"plugins.{0}.{0}".format(plugin), package = None))
|
"plugins.{0}.{0}".format(plugin), package = None))
|
||||||
|
|
||||||
# Run the module's setup function and save that it got installed
|
# Run the module's setup function and save that it got installed
|
||||||
self.setup_plugin(modules[i])
|
self.setup_plugin(modules[i])
|
||||||
|
|
||||||
# Create new instance of plugin and append to plugin_objects array
|
# Create new instance of plugin and append to plugin_objects array
|
||||||
self.plugin_objects.append(modules[i].Plugin(self))
|
self.plugin_objects.append(modules[i].Plugin(self))
|
||||||
|
|
||||||
# Add handler of newly created instance to bot
|
# Add handler of newly created instance to bot
|
||||||
self.add_handler(self.plugin_objects[i].handler)
|
self.add_handler(self.plugin_objects[i].handler)
|
||||||
#except:
|
except:
|
||||||
# eprint("Importing one or more of the plugins did not go well!")
|
eprint("Importing one or more of the plugins did not go well!")
|
||||||
# sys.exit()
|
traceback.print_exc()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
def check_installation_plugin(self, module_name):
|
def check_installation_plugin(self, module_name):
|
||||||
"""Function returns 0 if a plugin with that name is not
|
"""Function returns 0 if a plugin with that name is not
|
||||||
@ -175,10 +170,10 @@ class MatrixBotAPI:
|
|||||||
print(f"Running installation of {module_name}.")
|
print(f"Running installation of {module_name}.")
|
||||||
|
|
||||||
# Run module's install method
|
# Run module's install method
|
||||||
#try:
|
try:
|
||||||
module.setup()
|
module.setup()
|
||||||
#except:
|
except:
|
||||||
# print(f"{module_name} did not specify setup(). Skipping...")
|
print(f"{module_name} did not specify setup(). Skipping...")
|
||||||
|
|
||||||
# Save in database that we installed this plugin
|
# Save in database that we installed this plugin
|
||||||
datetime_added = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
datetime_added = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
@ -238,42 +233,6 @@ class MatrixBotAPI:
|
|||||||
# Do nothing, data directory already exists
|
# Do nothing, data directory already exists
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def send_message_private_public(self, room, event, message):
|
|
||||||
"""This method takes a room, event, and message and makes sure
|
|
||||||
that the message is sent in a private room and not in a public
|
|
||||||
room. If no private room exists, it will create a private room
|
|
||||||
with the sender of the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
orig_room = room
|
|
||||||
found_room = False
|
|
||||||
|
|
||||||
for room_id, room in self.client.get_rooms().items():
|
|
||||||
joined_members = room.get_joined_members()
|
|
||||||
|
|
||||||
# Check for rooms with only two members
|
|
||||||
if len(joined_members) == 2:
|
|
||||||
# Check if sender is in that room
|
|
||||||
for member in joined_members:
|
|
||||||
if event['sender'] == member.user_id:
|
|
||||||
found_room = True
|
|
||||||
|
|
||||||
if found_room:
|
|
||||||
# If the flag is set, we do not need to check further rooms
|
|
||||||
break
|
|
||||||
|
|
||||||
# Send help message to an existing room or to a new room
|
|
||||||
if found_room:
|
|
||||||
room.send_html(message)
|
|
||||||
else:
|
|
||||||
room = self.client.create_room(invitees=[event['sender']]);
|
|
||||||
room.send_html(message)
|
|
||||||
|
|
||||||
if room != orig_room:
|
|
||||||
display_name_sender = self.api.get_display_name(event['sender'])
|
|
||||||
orig_room.send_text(self.messages['private_message'].format(
|
|
||||||
display_name_sender))
|
|
||||||
|
|
||||||
def help(self, room, event):
|
def help(self, room, event):
|
||||||
"""Prints a general help message and then grabs all help
|
"""Prints a general help message and then grabs all help
|
||||||
messages from the different plugins
|
messages from the different plugins
|
||||||
@ -288,7 +247,7 @@ class MatrixBotAPI:
|
|||||||
# The plugin probably returned 0, ignore it
|
# The plugin probably returned 0, ignore it
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.send_message_private_public(room, event, help_text)
|
self.client.send_message_private_public(room, event, help_text)
|
||||||
|
|
||||||
def add_handler(self, handler):
|
def add_handler(self, handler):
|
||||||
try:
|
try:
|
||||||
@ -327,4 +286,5 @@ class MatrixBotAPI:
|
|||||||
def start_polling(self):
|
def start_polling(self):
|
||||||
# Starts polling for messages
|
# Starts polling for messages
|
||||||
self.client.start_listener_thread()
|
self.client.start_listener_thread()
|
||||||
|
|
||||||
return self.client.sync_thread
|
return self.client.sync_thread
|
||||||
|
@ -146,7 +146,7 @@ class Plugin:
|
|||||||
if row[1] in mapping[0]:
|
if row[1] in mapping[0]:
|
||||||
# We got a winner!
|
# We got a winner!
|
||||||
|
|
||||||
for i, room in self.bot.client.get_rooms().items():
|
for i, room in self.bot.client.rooms.items():
|
||||||
if room.display_name in mapping[1]:
|
if room.display_name in mapping[1]:
|
||||||
room.send_html(
|
room.send_html(
|
||||||
self.messages["new_event"].format(
|
self.messages["new_event"].format(
|
||||||
|
Loading…
Reference in New Issue
Block a user