diff --git a/.gitignore b/.gitignore index aa95aa6..384466b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ __pycache__ -modules -program.py +venv +program.py \ No newline at end of file diff --git a/data.py b/data.py deleted file mode 100644 index 282eada..0000000 --- a/data.py +++ /dev/null @@ -1,12 +0,0 @@ -from subprocess import PIPE, STDOUT, Popen -from typing import Callable, List, Tuple -from re import Pattern - -output_binds: List[Tuple[Pattern, Callable]] = [] -proc = None - - -def initializeProc(cmd): - global proc - proc = Popen(cmd.split(), stdin=PIPE, stdout=PIPE, - stderr=STDOUT, text=True, bufsize=1) diff --git a/libcommon.py b/libcommon.py new file mode 100644 index 0000000..b6d1dcf --- /dev/null +++ b/libcommon.py @@ -0,0 +1,31 @@ +from subprocess import PIPE, STDOUT, Popen, run +from typing import Callable, List, Optional, Tuple +from re import Pattern + + +minecraftOutputBinds: List[Tuple[Pattern, Callable]] = [] +minecraftProc = None + + +def minecraftInit(cmd: str) -> None: + global minecraftProc + minecraftProc = Popen(cmd.split(), stdin=PIPE, stdout=PIPE, + stderr=STDOUT, text=True, bufsize=1) + + +class Group: + def __init__(self, name: str, id: str): + self.name = name + self.id = id + + def __repr__(self) -> str: + return f'' + + +signalMessageBinds: List[Tuple[Optional[Group], Callable]] = [] +signalProc = None + + +def signalInit(cmd: str) -> None: + global signalProc + signalProc = run(cmd.split(), stdout=PIPE) diff --git a/minecraft.py b/libminecraft.py similarity index 51% rename from minecraft.py rename to libminecraft.py index 3593de7..3c28887 100644 --- a/minecraft.py +++ b/libminecraft.py @@ -1,19 +1,16 @@ -from subprocess import PIPE, STDOUT, Popen -from importlib import import_module from threading import Thread from typing import Callable -from pathlib import Path from re import compile -import data +import libcommon def reader() -> None: - if data.proc.stdout: - for line in data.proc.stdout: + if libcommon.minecraftProc.stdout: + for line in libcommon.minecraftProc.stdout: line = line.rstrip("\n") print(line) - for pattern, func in data.output_binds: + for pattern, func in libcommon.minecraftOutputBinds: match = pattern.match(line) if match: func(*match.groups()) @@ -22,30 +19,30 @@ def reader() -> None: def onConsoleOutput(pattern: str) -> Callable: def decorator(func: Callable) -> Callable: - data.output_binds.append((compile(pattern), func)) + libcommon.minecraftOutputBinds.append((compile(pattern), func)) return func return decorator def sendCommand(cmd: str) -> None: - if data.proc.stdin: - data.proc.stdin.write(cmd+"\n") - data.proc.stdin.flush() + if libcommon.minecraftProc.stdin: + libcommon.minecraftProc.stdin.write(cmd+"\n") + libcommon.minecraftProc.stdin.flush() -if __name__ == "__main__": - data.initializeProc("python -u program.py") - - for file in Path("modules").iterdir(): - if file.name.endswith(".py"): - import_module("modules."+file.name[:-3]) +def main() -> None: + libcommon.minecraftInit("python -u program.py") t = Thread(target=reader, daemon=True) t.start() try: - while data.proc.poll() is None: + while libcommon.minecraftProc.poll() is None: sendCommand(input()) except KeyboardInterrupt: sendCommand("stop") - data.proc.wait() + libcommon.minecraftProc.wait() + + +if __name__ == "__main__": + main() diff --git a/libsignal.py b/libsignal.py new file mode 100644 index 0000000..79782c9 --- /dev/null +++ b/libsignal.py @@ -0,0 +1,63 @@ +from typing import Callable, List, Optional +from requests import post as _post +from sseclient import SSEClient +from threading import Thread +from time import sleep +from json import loads +from uuid import uuid4 + +import libcommon + +url = "http://localhost:42069" + + +def post(method: str, **params): + return _post(url+"/api/v1/rpc", json={"jsonrpc": "2.0", "method": method, "params": params, "id": str(uuid4())}).json() + + +def sendMessage(message: str, recipient: str | libcommon.Group): + if isinstance(recipient, libcommon.Group): + return post("send", message=message, groupId=recipient.id) + return post("send", message=message, recipient=recipient) + + +def listGroups() -> List[libcommon.Group]: + grps = post("listGroups")["result"] + groups = [] + for group in grps: + groups.append(libcommon.Group(group["name"], group["id"])) + return groups + + +def onMessage(group: Optional[libcommon.Group] = None) -> Callable: + def decorator(func: Callable) -> Callable: + libcommon.signalMessageBinds.append((group, func)) + return func + return decorator + + +def main(): + cli = Thread(target=libcommon.signalInit, args=( + "signal-cli daemon --http localhost:42069",)) + cli.start() + + sleep(5) + + for msg in SSEClient(url+"/api/v1/events"): + data = loads(msg.data) + envelope = data.get("envelope", None) + if envelope: + dataMessage = envelope.get("dataMessage", None) + if dataMessage: + name = envelope["sourceName"] + body = dataMessage["message"] + groupId = dataMessage["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 + + +if __name__ == "__main__": + main() diff --git a/main.py b/main.py new file mode 100644 index 0000000..b858138 --- /dev/null +++ b/main.py @@ -0,0 +1,21 @@ +from importlib import import_module +from threading import Thread +from subprocess import run +from pathlib import Path + +import libminecraft +import libsignal + + +minecraftThread = Thread(target=libminecraft.main) +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]) + +minecraftThread.join() +signalThread.join() diff --git a/modules/minecraft_signal_bridge.py b/modules/minecraft_signal_bridge.py new file mode 100644 index 0000000..db63b87 --- /dev/null +++ b/modules/minecraft_signal_bridge.py @@ -0,0 +1,17 @@ +import libminecraft +import libsignal +import libcommon + +RSBeta = libcommon.Group( + "RS Beta", "25a58sEeccxAs7Ka27HZW5Sm3R8zJQcyndLKR6FO7sM=") + + +@libminecraft.onConsoleOutput(r"\[.*\] \[Server thread\/INFO\]: <(.*)> (.*)") +def minecraftToSignal(usr: str, msg: str): + libsignal.sendMessage(f"[{usr}] {msg}", RSBeta) + + +@libsignal.onMessage(RSBeta) +def signalToMinecraft(usr: str, msg: str): + print(usr, msg) + libminecraft.sendCommand(f"say [{usr}] {msg}")