diff --git a/README.md b/README.md index 1b98a90..3ee6ba0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ basic structure: todo before it's basically finished: * basic rate limiting -* plugin manager & hook integration +* ~~plugin manager & hook integration~~ * make sure broken sockets are properly addressed with a resume or reconnect * default plugins so the bot does _something_ out of the box - * plugin reloading, user (command) authentication, etc. will also probably be written in plugin form \ No newline at end of file + * plugin reloading, user (command) authentication, etc. will also probably be written in plugin form +* initial presence in config \ No newline at end of file diff --git a/client.py b/client.py index ede78e3..81f0ae9 100644 --- a/client.py +++ b/client.py @@ -1,7 +1,9 @@ -import websockets, asyncio, json +import websockets, asyncio, json, sys, requests from random import randint import disc_api from grim_logger import glog, glog_level +from plugin_manager import plugin_manager + class client(): def __init__(self, config_path = "config.json"): self.logger = glog(level = glog_level.TRACE) @@ -11,6 +13,7 @@ class client(): self.user = None with open(config_path, "r") as conf_fd: self.config = json.loads(conf_fd.read()) + self.plugman = plugin_manager(self.logger, plugin_path = self.config["plugin_path"]) async def shit(self): # https://discord.com/developers/docs/topics/gateway#connecting-to-the-gateway # you're supposed to ask an HTTP endpoint what the ws gateway is but the docs didnt tell me the domain after 1sec so HAHA NOPE @@ -45,5 +48,12 @@ class client(): if res["t"] == "READY": self.session_id = res["d"]["session_id"] self.user = res["d"]["user"] + self.plugman.handle(res["t"], res["d"], self) def run(self): - asyncio.run(self.shit()) \ No newline at end of file + asyncio.run(self.shit()) + def send_msg(self, id, message): + endpoint = f"https://discordapp.com/api/channels/{id}/messages" + # fstring wasn't working for the auth + headers = {"Authorization": "Bot {0}".format(self.config["token"]), "User-Agent": "mbdf (cynic.moe, v1)", "Content-Type": "application/json"} + res = requests.post(endpoint, headers = headers, data = json.dumps({"content": message})) + self.logger.write(headers) \ No newline at end of file diff --git a/config.json b/config.json index 97a8a12..07569d2 100644 --- a/config.json +++ b/config.json @@ -1,3 +1,4 @@ { - "token": "YOUR_TOKEN_HERE" + "token": "YOUR_TOKEN_HERE", + "plugin_path": "./plugins" } \ No newline at end of file diff --git a/plugin_manager.py b/plugin_manager.py new file mode 100644 index 0000000..710590a --- /dev/null +++ b/plugin_manager.py @@ -0,0 +1,18 @@ +import os +import sys + +class plugin_manager(): + def __init__(self, logger, plugin_path = "./plugins"): + sys.path.append(plugin_path) # needed to __import__ scripts without a hassle, shouldn't cause an issue + plugins = [name.split(".py")[0] for name in os.listdir(plugin_path) if name.endswith(".py")] + self.plugins_loaded = [] + for plugin in plugins: + module = __import__(plugin) + if not(hasattr(module, "run")) or not(hasattr(module, "hooks")): + self.logger.write("plugin {plugin} is invalid: crucial attribute missing!") + else: + self.plugins_loaded.append(module) + def handle(self, event, ctx, bot): + for plugin in self.plugins_loaded: + if event in plugin.hooks: + getattr(plugin, "run")(event, ctx, bot) \ No newline at end of file diff --git a/plugins/dango.py b/plugins/dango.py new file mode 100644 index 0000000..c398761 --- /dev/null +++ b/plugins/dango.py @@ -0,0 +1,19 @@ +""" +the "hello world" (if you will) of the plugin system. +there are only two required parts: +* 'hooks': a list of dispatch events to run() on +* run(event, ctx, bot): the function to run on-event, where event is the trigger, + ctx is the 'd'(data) key of the response, and 'bot' is the current bot + instance. +the rest is up to you. +this particular example listens for a message that contains the string 'dango' and + returns a response, similar to the traditional 'hello' -> 'hello, world!' + test interaction +""" + +hooks = ["MESSAGE_CREATE"] # run() will be called when client.dispatch() gets a MESSAGE_CREATE +def run(event, ctx, bot): + if not(ctx["author"]["id"] == bot.user["id"]): # if the message author is not our bot... + if ctx["content"] == "dango": # and if the message body matches... + bot.logger.write("d/a/ngo") + bot.send_msg(ctx["channel_id"], "to all the motherfuckers that shed a tear") \ No newline at end of file