xonotic-bridge/xonotic-bridge.py

115 lines
4.3 KiB
Python

"""
Copyright (C) 2024 Skylar Widulski <cobra@vern.cc>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import nio
import asyncio
import aiofiles
from promise import Promise
import json
import os
import sys
from xrcon.client import XRcon
import subprocess
from config import (mx_room_id, mx_user_id, mx_homeserver, mx_pass,
xon_host, xon_port, xon_name, xon_pass)
source_url = 'http://git.vern.cc/cobra/xonotic-bridge'
def esc(string):
return string.replace('\n', ' ')
class XonoticBridge:
def __init__(self, *args, **kwargs):
self.xon = XRcon(xon_host, xon_port, xon_pass)
self.client = nio.AsyncClient(mx_homeserver, mx_user_id)
self.xon.connect()
if not os.path.exists("xonotic.json"):
response = self.client.login(mx_pass)
print(response)
if isinstance(response, nio.LoginResponse):
write_creds(response, mx_homeserver)
print("Logged in. Restart the program")
self.client.close()
return
else:
with open("xonotic.json", "r") as f:
contents = f.read()
config = json.loads(contents)
self.client = nio.AsyncClient(config["homeserver"])
self.client.access_token = config["access_token"]
self.client.user_id = config["user_id"]
self.client.device_id = config["device_id"]
async def watch_xon(self):
lastdata = ''
if not os.path.exists('logpipe'):
os.mkfifo('logpipe', 0o600)
async with aiofiles.open('logpipe') as fifo:
while (True):
if (self.client.logged_in):
try:
async for data in fifo:
print(data)
if data != '' and data != lastdata:
if not data.startswith(f"<{xon_name}> @"):
await self.client.room_send(mx_room_id, message_type="m.room.message", content={"msgtype": "m.text", "body": data})
lastdata = data
except Exception as e:
raise e
continue
await asyncio.sleep(0)
async def watch_matrix(self):
with open("next_batch","r") as next_batch_token:
self.client.next_batch = next_batch_token.read()
await self.client.room_send(mx_room_id, message_type="m.room.message", content={"msgtype": "m.text", "body": f"Starting Xonotic bridge. Source code: {source_url}"})
while (True):
sync_response = await self.client.sync(30000)
with open("next_batch","w+") as next_batch_token:
next_batch_token.write(sync_response.next_batch)
if len(sync_response.rooms.join) > 0:
joins = sync_response.rooms.join
for room_id in joins:
for event in joins[room_id].timeline.events:
if isinstance(event, nio.RoomMessageText) and event.sender != self.client.user_id:
print(f"{event.sender}: {event.body}")
self.xon.send(f'say "{event.sender}: {esc(event.body)}"')
def write_creds(resp: nio.LoginResponse, homeserver) -> None:
with open("xonotic.json", "w") as f:
json.dump(
{
"homeserver": homeserver,
"user_id": resp.user_id,
"device_id": resp.device_id,
"access_token": resp.access_token,
},
f,
)
async def main():
print("Starting...")
bridge = XonoticBridge()
await Promise.all([bridge.watch_xon(), bridge.watch_matrix()]);
asyncio.run(main())