import http.client, re, socket, sys, time, _thread, threading, os RECBUF = 1024 def getargv(arg, default="", n=1, args=sys.argv): if arg in args and len(args) > args.index(arg)+n: return args[args.index(arg)+n] else: return default p_clen = re.compile("\r?\ncontent-length: *(\d+)\r?\n?", re.IGNORECASE) def handle(client): # Get request paquet = b"" header = b"" content = b"" content_len = 0 resp = {} lf = 0 while True: raw = client.recv(RECBUF) if raw: paquet += raw if lf >= 0: for c in raw: if c == 10:# LF lf += 1 elif c != 13:# CR lf = 0 if lf > 1: parts = paquet.split(b"\r\n\r\n") header = parts[0] content = parts[1] try: content_len = int(p_clen.search(header.decode()).group(1)) except (AttributeError, ValueError): content_len = 0 break if lf > 1: break else: break while len(content) < content_len: raw = client.recv(RECBUF) paquet += raw content += raw httpreq = paquet.split(b" ", 2) if len(httpreq) != 3: client.close() return method = httpreq[0] url = httpreq[1] rest = httpreq[2] if b"/send/m.room.message/" in url: method = b"PUT" matrix_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if matrix_https: matrix_sock = ssl_ctx.wrap_socket(matrix_sock, server_hostname=matrix_addr) matrix_sock.settimeout(60) try: matrix_sock.connect((matrix_addr, matrix_port)) except socket.timeout: sys.stderr.write("timeout connecting to matrix") return matrix_sock.settimeout(None) matrix_sock.sendall(b" ".join([method, url, rest])) paquet = b"" header = b"" content = b"" content_len = 0 resp = {} lf = 0 while True: raw = matrix_sock.recv(RECBUF) if raw: paquet += raw if lf >= 0: for c in raw: if c == 10:# LF lf += 1 elif c != 13:# CR lf = 0 if lf > 1: parts = paquet.split(b"\r\n\r\n") header = parts[0] content = parts[1] try: content_len = int(p_clen.search(header.decode()).group(1)) except AttributeError: content_len = 0 break if lf > 1: break else: break while len(content) < content_len: raw = matrix_sock.recv(RECBUF) paquet += raw content += raw client.sendall(paquet) client.close() def run_watchdog(service_name, timeout): while True: if time.time() > last_request + timeout: os.system("systemctl restart {}".format(service_name)) last_request = time.time() time.sleep(60) if __name__ == "__main__": if "--help" in sys.argv or "-h" in sys.argv: print("""MineTest Matrix Bridge mod proxy GNU AGPLv3, CopyLeft 2022 Pascal Engélibert This program is useful for <5.4.0 MineTest servers using the mod matrix_bridge. For security reasons, please listen to a local address (default value is OK) and use a firewall if needed to prevent public access. Options: (with defaults) -a 127.0.0.1 Listen address -p 18448 Listen port -A matrix.txmn.tk Matrix address (without protocol and port) -P 8448 Matrix port -s Use HTTP instead of HTTPS (default: no) -w Enable watchdog Restarts the given systemd service when no request from the minetest server after a given time. Needs root. --wtime 600 Watchdog timeout (seconds) """) exit() listen_addr = getargv("-a", "127.0.0.1") listen_port = int(getargv("-p", 18448)) matrix_addr = getargv("-A", "matrix.txmn.tk") matrix_port = int(getargv("-P", 8448)) matrix_https = not "-s" in sys.argv watchdog = getargv("-w", None) watchdog_timeout = int(getargv("--wtime", 600)) last_request = time.time() if watchdog: t = threading.Thread(target=run_watchdog, args=(watchdog, watchdog_timeout,)) t.start() if matrix_https: import ssl ssl_ctx = ssl.create_default_context() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(60) sock.bind((listen_addr, listen_port)) sock.listen(1) try: while True: try: client, addr = sock.accept() except socket.timeout: last_request = time.time() continue last_request = time.time() _thread.start_new_thread(handle, (client,)) sock.close() except KeyboardInterrupt: sock.shutdown(socket.SHUT_WR)