diff --git a/examples/command_bot.py b/examples/command_bot.py new file mode 100644 index 0000000..4f9da59 --- /dev/null +++ b/examples/command_bot.py @@ -0,0 +1,130 @@ +""" +This example implements Matrix bot that can execute some commands. + +It uses environment variables to specify authorization data. Use Ctrl+C to stop +the bot. +""" + +import asyncio +import time +import html +import os +import traceback +import logging + +from mab import * + +from _environment import check_environment + +async def on_help_command(ctx: EventContext) -> None: + """!help""" + HELP_MESSAGE = ( + "Here is the list of the commands:
" + "" + ) + await ctx.bot.send_text(ctx.room, HELP_MESSAGE) + +async def on_time_command(ctx: EventContext) -> None: + """!time""" + await ctx.bot.send_text( + ctx.room, + f"Current UNIX timestamp is {int(time.time())}" + ) + +async def on_raise_command(ctx: EventContext) -> None: + """!raise""" + await ctx.bot.send_text( + ctx.room, + "Executing raise RuntimeError()..." + ) + raise RuntimeError() + +async def on_assert_command(ctx: EventContext) -> None: + """!assert""" + await ctx.bot.send_text( + ctx.room, + "Executing assert False..." + ) + assert False + +async def on_mul_command(ctx: EventContext) -> None: + """!mul""" + try: + numbers = [float(v) for v in ctx[CTX_CMD_ARGS]] + v = numbers[0] + for n in numbers[1:]: + v *= n + response = " * ".join(html.escape("%.2f" % n) for n in numbers) + response += f" = {html.escape(str(v))}" + await ctx.bot.send_text(ctx.room, response) + except Exception as e: + await ctx.bot.send_text(ctx.room, f"Could not process the command: {e}") + +async def on_args_command(ctx: EventContext) -> None: + """!args""" + try: + response = ( + f"Prefix: {ctx[CTX_CMD_PREFIX]}
" + f"Verb: {ctx[CTX_CMD_VERB]}
" + f"Arguments: {len(ctx[CTX_CMD_ARGS])}
" + f"Arguments are:
    " + ) + for arg in ctx[CTX_CMD_ARGS]: + response += f"
  1. {html.escape(arg)}
  2. " + response += "
" + await ctx.bot.send_text( + ctx.room, + response + ) + except: + await ctx.bot.send_text( + ctx.room, + f"Could not process the command: {traceback.format_exc()}" + ) + +async def invalid_usage(ctx: EventContext) -> None: + """This callback is called when the bot used incorrectly.""" + await ctx.bot.send_text(ctx.room, "Use !help") + + +async def main() -> None: + """Application entry point""" + logging.basicConfig(level=logging.INFO) + logging.getLogger("nio").setLevel(logging.CRITICAL+1) + check_environment() + + config = MatrixBotConfig( + matrix_homeserver_url=os.environ["MATRIX_HOMESERVER"], + matrix_username_localpart=os.environ["MATRIX_USERNAME"], + storage_directory="session_storage" + ) + bot = MatrixBot(config) + + COMMANDS = { + on_help_command: BodyCommandFilter(["help", "?"]), + on_time_command: BodyCommandFilter("time"), + on_raise_command: BodyCommandFilter("raise"), + on_assert_command: BodyCommandFilter("assert"), + on_mul_command: BodyCommandFilter("mul", min_args=2), + on_args_command: BodyCommandFilter("args", min_args=1, max_args=5), + } + for callback, filter in COMMANDS.items(): + f = ~SenderIsBotFilter() & filter + bot.add_callback(f, callback) + bot.add_callback(~SenderIsBotFilter() & NewMessageFilter(), invalid_usage) + + # run until Ctrl+C + try: + await bot.run() + except asyncio.CancelledError: + pass + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file