From f58b3b9819cee9d858caf389745c8a24f040248a Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Mon, 11 Jan 2021 10:33:57 +0100 Subject: [PATCH] add python prototype --- .gitignore | 1 + README.md | 14 ++++++++ main.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4acd06b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fb2367 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Logmatters + +To run, add to `config.py`: + +```python +driver = { + 'url': 'mattermost.example', + 'login_id': '', + 'password': '', + 'port': 443 +} + +logdir = 'logs' +``` diff --git a/main.py b/main.py new file mode 100644 index 0000000..5b9d722 --- /dev/null +++ b/main.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +import sys +import json +import datetime +import os +import os.path +import functools +import contextlib +import asyncio +import concurrent +import logging +import selectors + +from mattermostdriver import Driver, Websocket # pip install mattermostdriver + +import config + + +logging.basicConfig(level='INFO') + + +class MatterLog: + + __slots__ = ['driver', 'logdir'] + + def __init__(self, driver, loop, logdir): + self.driver = driver + self.logdir = logdir + + @contextlib.contextmanager + def channel_file(self, team, channel): + current = os.path.join(self.logdir, team, channel, 'current') + os.makedirs(os.path.dirname(current), exist_ok=True) + with open(current, 'a') as f: + yield f + + async def __call__(self, event): + event = json.loads(event) + if 'event' not in event: + logging.warning('received none-event: ' + str(event)) + elif event['event'] in MatterLog.IGNORED_EVENTS: + pass + elif not hasattr(self, 'handle_' + event['event']): + logging.warning('no handler for event: ' + str(event)) + else: + await getattr(self, 'handle_' + event['event'])(event['data']) + + IGNORED_EVENTS = { 'emoji_added', 'hello', 'license_changed', + 'preference_changed', 'preferences_changed', 'preferences_deleted', + 'typing' } + + async def handle_posted(self, data): + post = json.loads(data['post']) + with self.channel_file(self.cached_team_name(data['team_id']), data['channel_name']) as f: + if post.get('root_id'): + print(post['create_at'], post['id'], 'REPLY', post['original_id'], data['sender_name'][1:], post['message'], sep='\t', file=f) + else: + print(post['create_at'], post['id'], 'MSG', data['sender_name'][1:], post['message'], sep='\t', file=f) + + @functools.lru_cache + def cached_team_name(self, team): + return self.driver.teams.get_team(team)['name'] + + +async def messageloop(driver, loop, logdir): + selector = selectors.DefaultSelector() + for team in driver.teams.get_teams(): + for channel in driver.channels.get_channels_for_user(driver.client.userid, team['id']): + sayfile = os.path.join(logdir, team['name'], channel['name'], 'say') + + if os.path.exists(sayfile): os.unlink(sayfile) + os.makedirs(os.path.dirname(sayfile), exist_ok=True) + os.mkfifo(sayfile) + f = os.open(sayfile, os.O_RDONLY | os.O_NONBLOCK) + selector.register(f, selectors.EVENT_READ, (sayfile, channel['id'])) + + while True: + events = await loop.run_in_executor(None, lambda: selector.select()) + for key, mask in events: + selector.unregister(key.fileobj) + message = os.read(key.fileobj, 1024) + os.close(key.fileobj) + if message: + driver.posts.create_post(options={ + 'channel_id': key.data[1], + 'message': message.decode() + }) + f = os.open(key.data[0], os.O_RDONLY | os.O_NONBLOCK) + selector.register(f, selectors.EVENT_READ, key.data) + + +if __name__ == '__main__': + + driver = Driver(config.driver) + driver.login() + + def listen(driver): + websocket = Websocket(driver.options, driver.client.token) + loop = asyncio.get_event_loop() + loop.set_debug(True) + loop.create_task(messageloop(driver, loop, config.logdir)) + loop.run_until_complete(websocket.connect(MatterLog(driver, loop, config.logdir)))