diff --git a/libcommon.py b/libcommon.py index b6d1dcf..a7fc960 100644 --- a/libcommon.py +++ b/libcommon.py @@ -1,9 +1,13 @@ +from typing import Callable, Dict, List, Optional, Tuple from subprocess import PIPE, STDOUT, Popen, run -from typing import Callable, List, Optional, Tuple +from importlib import import_module +from typing import List, Tuple +from pathlib import Path +from sys import modules as _modules from re import Pattern -minecraftOutputBinds: List[Tuple[Pattern, Callable]] = [] +minecraftOutputBinds: Dict[str, List[Tuple[Pattern, Callable]]] = {} minecraftProc = None @@ -22,10 +26,47 @@ class Group: return f'' -signalMessageBinds: List[Tuple[Optional[Group], Callable]] = [] +signalMessageBinds: Dict[str, List[Tuple[Optional[Group], Callable]]] = {} signalProc = None def signalInit(cmd: str) -> None: global signalProc signalProc = run(cmd.split(), stdout=PIPE) + + +loadedMods = [] + + +def listModules() -> Tuple[List[str], List[str], List[str]]: + modules = [] + loaded_modules = [] + unloaded_modules = [] + for file in Path("modules").iterdir(): + if file.name.endswith(".py"): + modules.append(file.name[:-3]) + if file.name[:-3] in loadedMods: + loaded_modules.append(file.name[:-3]) + else: + unloaded_modules.append(file.name[:-3]) + return modules, loaded_modules, unloaded_modules + + +def loadModule(module: str): + global loadedMods + + if module in listModules()[2]: + minecraftOutputBinds[module] = [] + signalMessageBinds[module] = [] + import_module("modules."+module) + loadedMods.append(module) + + +def unloadModule(module: str): + global loadedMods + + if module in listModules()[1]: + del _modules["modules."+module] + loadedMods.remove(module) + del minecraftOutputBinds[module] + del signalMessageBinds[module] diff --git a/libminecraft.py b/libminecraft.py index 083e668..f785e40 100644 --- a/libminecraft.py +++ b/libminecraft.py @@ -1,5 +1,6 @@ from threading import Thread from typing import Callable +from inspect import stack from re import compile import libcommon @@ -10,16 +11,19 @@ def reader() -> None: for line in libcommon.minecraftProc.stdout: line = line.rstrip("\n") print(line) - for pattern, func in libcommon.minecraftOutputBinds: - match = pattern.match(line) - if match: - func(*match.groups()) - break + for module in libcommon.loadedMods: + if module in libcommon.minecraftOutputBinds: + for pattern, func in libcommon.minecraftOutputBinds[module]: + match = pattern.match(line) + if match: + func(*match.groups()) + break def onConsoleOutput(pattern: str) -> Callable: def decorator(func: Callable) -> Callable: - libcommon.minecraftOutputBinds.append((compile(pattern), func)) + module = stack()[1].filename.split("/")[-1][:-3] + libcommon.minecraftOutputBinds[module].append((compile(pattern), func)) return func return decorator diff --git a/libsignal.py b/libsignal.py index 4f1cbb8..6ed567c 100644 --- a/libsignal.py +++ b/libsignal.py @@ -2,6 +2,7 @@ from typing import Callable, List, Optional from requests import post as _post from sseclient import SSEClient from threading import Thread +from inspect import stack from time import sleep from json import loads from uuid import uuid4 @@ -31,7 +32,8 @@ def listGroups() -> List[libcommon.Group]: def onMessage(group: Optional[libcommon.Group] = None) -> Callable: def decorator(func: Callable) -> Callable: - libcommon.signalMessageBinds.append((group, func)) + module = stack()[1].filename.split("/")[-1][:-3] + libcommon.signalMessageBinds[module].append((group, func)) return func return decorator @@ -44,9 +46,13 @@ def main(): sleep(5) for msg in SSEClient(url+"/api/v1/events"): - data = loads(msg.data) + try: + data = loads(msg.data) + except: + data = {} envelope = data.get("envelope", None) if envelope: + dataMessage = envelope.get("dataMessage", None) if dataMessage: groupInfo = dataMessage.get("groupInfo", None) @@ -55,10 +61,27 @@ def main(): body = dataMessage["message"] groupId = groupInfo["groupId"] if body is not None: - for group, func in libcommon.signalMessageBinds: - if group is None or group.id == groupId: - func(name, body) - break + for module in libcommon.loadedMods: + if module in libcommon.signalMessageBinds: + for group, func in libcommon.signalMessageBinds[module]: + if group is None or group.id == groupId: + func(name, body) + + syncMessage = envelope.get("syncMessage", None) + if syncMessage: + sentMessage = syncMessage.get("sentMessage", None) + if sentMessage: + groupInfo = sentMessage.get("groupInfo", None) + if groupInfo: + name = envelope["sourceName"] + body = sentMessage["message"] + groupId = groupInfo["groupId"] + if body is not None: + for module in libcommon.loadedMods: + if module in libcommon.signalMessageBinds: + for group, func in libcommon.signalMessageBinds[module]: + if group is None or group.id == groupId: + func(name, body) if __name__ == "__main__": diff --git a/modules/control.py b/modules/control.py new file mode 100644 index 0000000..0ae9f3d --- /dev/null +++ b/modules/control.py @@ -0,0 +1,47 @@ +import libminecraft +import libsignal +import libcommon + +RetardsServer = libcommon.Group( + "Retards Server", "5PlbXaPmWZQkhmuyyC/fkWTy8K+BqomjK7byVDyxmpo=") + + +@libsignal.onMessage(RetardsServer) +def signalControl(usr: str, msg: str): + if usr == "Malasaur" and msg.startswith("!"): + match msg.split(): + case ["!modules", "list"]: + available_modules, loaded_modules, unloaded_modules = libcommon.listModules() + libsignal.sendMessage( + f"""Available modules: {" ".join(available_modules)} + Loaded modules: {" ".join(loaded_modules)} + Unloaded modules: {" ".join(unloaded_modules)}""", RetardsServer + ) + case ["!modules", "load", *modules]: + for module in modules: + try: + libcommon.loadModule(module) + libsignal.sendMessage( + f"[Serve] '{module}' successfully loaded.", RetardsServer) + except Exception as e: + libsignal.sendMessage( + f"[Serve] Error loading '{module}': {e}", RetardsServer) + case ["!modules", "unload", *modules]: + for module in modules: + try: + libcommon.unloadModule(module) + libsignal.sendMessage( + f"[Serve] '{module}' successfully unloaded.", RetardsServer) + except Exception as e: + libsignal.sendMessage( + f"[Serve] Error unloading '{module}': {e}", RetardsServer) + case ["!modules", "reload", *modules]: + for module in modules: + try: + libcommon.unloadModule(module) + libcommon.loadModule(module) + libsignal.sendMessage( + f"[Serve] '{module}' successfully reloaded.", RetardsServer) + except Exception as e: + libsignal.sendMessage( + f"[Serve] Error reloading '{module}': {e}", RetardsServer) diff --git a/modules/shazam.py b/modules/shazam.py new file mode 100644 index 0000000..c1b96bc --- /dev/null +++ b/modules/shazam.py @@ -0,0 +1,5 @@ + +@libminecraft.onConsoleOutput(r"\[.*\] \[Server thread\/INFO\]: Set Malasaur's game mode to (.*) Mode") +def malasaurSetGamemode(gamemode: str): + global malasaurGamemode + malasaurGamemode = gamemode.lower() diff --git a/main.py b/serve.py similarity index 54% rename from main.py rename to serve.py index b858138..8cf46c8 100644 --- a/main.py +++ b/serve.py @@ -1,10 +1,8 @@ -from importlib import import_module from threading import Thread -from subprocess import run -from pathlib import Path import libminecraft import libsignal +import libcommon minecraftThread = Thread(target=libminecraft.main) @@ -13,9 +11,8 @@ signalThread = Thread(target=libsignal.main) minecraftThread.start() signalThread.start() -for file in Path("modules").iterdir(): - if file.name.endswith(".py"): - import_module("modules."+file.name[:-3]) + +libcommon.loadModule("control") minecraftThread.join() signalThread.join()