import atexit from logging.config import dictConfig from threading import Thread import random import os import os.path from flask import Flask, request import requests import requests.exceptions import toml from rollbot import RollbotConfig, Rollbot, RollbotMessage, RollbotPlugin import plugins # Configure loggers dictConfig({ "version": 1, "formatters": {"default": { "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", }}, "handlers": {"wsgi": { "class": "logging.StreamHandler", "stream": "ext://flask.logging.wsgi_errors_stream", "formatter": "default" }}, "root": { "level": "INFO", "handlers": ["wsgi"] } }) # Read bot configuration config_dir = os.environ.get("ROLLBOT_CFG_DIR", ".") with open(os.path.join(config_dir, "config.toml")) as infile: raw_config = toml.load(infile) with open(os.path.join(config_dir, "secrets.toml")) as infile: raw_secrets = toml.load(infile) auths = raw_secrets["auths"] global_admins = auths["global"] group_admins = auths["group"] bots_lookup = raw_secrets["groupme_bots"] # Define Flask app app = Flask(__name__) app.config["PROPAGATE_EXCEPTIONS"] = True # Define reply logic max_msg_len = 1000 split_text = "\n..." msg_slice = max_msg_len - len(split_text) def post_groupme_message(msg, group_id): bot_id = bots_lookup[group_id] msgs = [] rem = msg while len(rem) > max_msg_len: msgs.append(rem[:msg_slice] + split_text) rem = rem[msg_slice:] msgs.append(rem) for msg in msgs: try: requests.post( "https://api.groupme.com/v3/bots/post", json={ "bot_id": bot_id, "text": msg }, timeout=10 ) except requests.exceptions.Timeout as t: app.logger.error(f"GroupMe timed out sending {msg} as {bot_id}", exc_info=t) except requests.exceptions.HTTPError as h: app.log_exception(h) # Create bot config = RollbotConfig( plugins=RollbotPlugin.find_all_plugins(), db_url="sqlite:///" + os.path.abspath(raw_config["database"]), reply_callback=post_groupme_message, aliases=raw_config.get("aliases", []), responses=raw_config.get("responses", []), sleep_time=raw_config.get("sleep_time", 0.0), other={ **{k: v for k, v in raw_config.items() if k not in ("database", "aliases", "responses", "sleep_time")}, **{k: v for k, v in raw_secrets.items() if k not in ("auths", "groupme_bots")}, }, ) rollbot = Rollbot(config, logger=app.logger) # Init db app.logger.info("Initializing database tables") rollbot.init_db() app.logger.info("Finished initializing database") # Setup plugins rollbot.start_plugins() atexit.register(rollbot.shutdown_plugins) # Routing @app.route("/", methods=["POST"]) def execute(): json = request.get_json() msg = RollbotMessage.from_groupme(json, global_admins=global_admins, group_admins=group_admins) if msg.group_id not in bots_lookup: app.logger.warning(f"Received message from unknown group ID {msg.group_id}") return "", 400 t = Thread(target=lambda: rollbot.handle_command(msg)) t.start() return "", 204 @app.route("/health") def health(): return "", 204 if __name__ == "__main__": app.run(host="0.0.0.0", port=6070)