diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6149762 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3 + +WORKDIR /bot +RUN pip install pipenv +COPY Pipfile . +RUN pipenv install --skip-lock --system + +COPY bot.py . + +CMD [ "python", "-u", "./bot.py" ] diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..6b7566a --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +matrix-nio = "*" +geopy = "*" + +[dev-packages] +pylint = "*" + +[requires] +python_version = "3.7" diff --git a/README.md b/README.md new file mode 100644 index 0000000..0de54d1 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Hemppa - generic Matrix bot + +## First + +* Create a Matrix user +* Get user's access token - In Riot Web see Settings / Help & about + +## Running on host + +Run something like: + +``` bash +pip3 install pipenv +pipenv shell +pipenv install +MATRIX_USER="@user:matrix.org" MATRIX_ACCESS_TOKEN="MDAxOGxvYlotofcharacters53CgYAYFgo" MATRIX_SERVER="https://matrix.org" JOIN_ON_INVITE=True python3 bot.py +``` + +## Running with Docker + +Create .env file and set variables: + +``` bash +MATRIX_USER=@user:matrix.org +MATRIX_ACCESS_TOKEN=MDAxOGxvYlotofcharacters53CgYAYFgo +MATRIX_SERVER=https://matrix.org +JOIN_ON_INVITE=True +``` + +Note: without quotes! + +Just run: + +``` bash +docker-compose up +``` + +## Env variables + +User, access token and server should be self-explanatory. Set JOIN_ON_INVITE to anything if you want the bot to +join invites automatically. + +You can set MATRIX_PASSWORD if you want to get access token. Normally you can use Riot to get it. + +## Testing diff --git a/bot.py b/bot.py new file mode 100755 index 0000000..210e5d6 --- /dev/null +++ b/bot.py @@ -0,0 +1,70 @@ +import asyncio +import os +import json +from nio import (AsyncClient, RoomMessageText, RoomMessageUnknown, JoinError, InviteEvent) + + +class Bot: + client = None + join_on_invite = False + + async def send_html(self, body, client, room): + msg = { + "body": body, + "msgtype": "m.text" + } + await self.client.room_send(self.get_room_id(room), 'm.room.message', msg) + + def get_room_id(self, room): + for roomid in client.rooms: + if self.client.rooms[roomid].named_room_name() == room.named_room_name(): + return roomid + print('Cannot find id for room', room.named_room_name(), ' - is the bot on it?') + return None + + async def message_cb(self, room, event): + pass + + async def unknown_cb(self, room, event): + if event.msgtype != 'm.location': + return + pass + + async def invite_cb(self, room, event): + for attempt in range(3): + result = await self.client.join(room.room_id) + if type(result) == JoinError: + print(f"Error joining room {room.room_id} (attempt %d): %s", + attempt, result.message, + ) + else: + break + + def init(self): + self.client = AsyncClient(os.environ['MATRIX_SERVER'], os.environ['MATRIX_USER']) + self.client.access_token = os.getenv('MATRIX_ACCESS_TOKEN') + self.join_on_invite = os.getenv('JOIN_ON_INVITE') + + async def run(self): + if not self.client.access_token: + await self.client.login(os.environ['MATRIX_PASSWORD']) + print("Logged in with password, access token:", client.access_token) + + await self.client.sync() + + if self.client.logged_in: + self.client.add_event_callback(self.message_cb, RoomMessageText) + self.client.add_event_callback(self.unknown_cb, RoomMessageUnknown) + if self.join_on_invite: + print('Note: Bot will join rooms if invited') + self.client.add_event_callback(self.invite_cb, (InviteEvent,)) + print('Bot running') + await self.client.sync_forever(timeout=30000) + else: + print('Client was not able to log in, check env variables!') + + +bot = Bot() +bot.init() + +asyncio.get_event_loop().run_until_complete(bot.run()) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f65a14d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' + +services: + malobot: + container_name: hemppa + image: 'hemppa:latest' + build: '.' + restart: always + environment: + - MATRIX_ACCESS_TOKEN + - MATRIX_USER + - MATRIX_PASSWORD + - MATRIX_SERVER + - JOIN_ON_INVITE