Beispiel #1
0
    def __init__(self, settings):
        self.sync_token = None

        self.logger = utils.get_logger()
        self.cache = utils.create_cache(settings)
        self.cache_timeout = int(settings["memcached"]["timeout"])

        self.settings = settings
        self.period = settings["DEFAULT"]["period"]
        self.uri = settings["matrix"]["uri"]
        self.username = settings["matrix"]["username"].lower()
        self.password = settings["matrix"]["password"]
        self.room_ids = settings["matrix"]["rooms"]
        self.domain = self.settings["matrix"]["domain"]
        self.only_local_domain = self.settings["matrix"]["only_local_domain"]

        self.subscriptions_room_ids = settings["subscriptions"].keys()
        self.revokations_rooms_ids = settings["revokations"].keys()
        self.allowed_join_rooms_ids = filter(lambda x: x != 'default',
                                             settings["allowed-join"].keys())
        self.default_allowed_join_rooms = settings["allowed-join"]["default"]

        self.client = MatrixClient(self.uri)
        self.token = self.client.login_with_password(username=self.username,
                                                     password=self.password)
        self.api = MatrixHttpApi(self.uri, token=self.token)

        self.rooms = []
        self.room_aliases = {}
        self.plugins = []
        for plugin in settings['plugins'].itervalues():
            mod = __import__(plugin['module'], fromlist=[plugin['class']])
            klass = getattr(mod, plugin['class'])
            self.plugins.append(klass(self, plugin['settings']))
Beispiel #2
0
 def __init__(self, token, server, roomid):
     self.server = server
     self.roomid = roomid
     self.token = token
     self.APIWrapper = MatrixHttpApi("https://{}".format(self.server), token=self.token)
     self.next_batch = self.APIWrapper.sync().get("next_batch")
     print("client initialized")
class MatrixClient:
    """
    Provides minimal interface to MatrixHttpApi and holds its state.

    :param server: Matrix server to use.
    :param token: Matrix token.
    :param room: Room id for sending data.
    """

    def __init__(self, server: str, token: str, room: str):
        """Construct a new MatrixClient and init and sync MatrixHttpApi."""
        self.server = server
        self.token = token
        self.room = room

        self.api = MatrixHttpApi(self.server, token=self.token)
        self.api.initial_sync()

    def send_event(self, event_type: str, content: dict):
        """Send an event of arbitrary type."""
        return self.api.send_message_event(self.room, event_type, content)

    @staticmethod
    def get_token(server: str, user: str, password: str) -> str:
        """Get an access_token via password login."""
        return MatrixHttpApi(server).login("m.login.password", user=user, password=password)
Beispiel #4
0
def handleNotification():
  req = request.get_json()
  print(req)
  
  matrix = MatrixHttpApi(HOMESERVER, token=req['notification']['devices'][0]['pushkey'])
  print(matrix.send_message_event(room_id=ROOMID, event_type='net.terracrypt.matrix.push', content=req))
  
  return jsonify({})
Beispiel #5
0
def announce(text, token, room=None):
    from matrix_client.api import MatrixHttpApi
    matrix = MatrixHttpApi("https://matrix.org", token=token)
    matrix.sync()
    roomid = matrix.get_room_id(room)
    matrix.join_room(roomid)
    matrix.send_message(roomid, text)
Beispiel #6
0
class Matrix:
    def __init__(self):
        logger.info('logging in to Matrix as %s', config.matrix.username)

        self._client = MatrixClient(config.matrix.server)
        self._token = self._client.login(username=config.matrix.username, password=config.matrix.password, sync=False)
        self._api = MatrixHttpApi(config.matrix.server, self._token)

    def send_text(self, room_id, text):
        self._api.send_message(room_id, text)

    def send_notice_html(self, room_id, text):
        content = dict(
            body=text,
            format='org.matrix.custom.html',
            formatted_body=text,
            msgtype=MsgType.NOTICE
        )

        self._api.send_message_event(room_id, event_type='m.room.message', content=content)

    def send_text_html(self, room_id, text):
        content = dict(
            body=text,
            format='org.matrix.custom.html',
            formatted_body=text,
            msgtype=MsgType.TEXT
        )

        self._api.send_message_event(room_id, event_type='m.room.message', content=content)

    def send_notice(self, room_id, text):
        self._api.send_notice(room_id, text)
Beispiel #7
0
def main(config):
    # setup api/endpoint
    matrix = MatrixHttpApi(config.base_url, config.token)

    log.debug("Setting up plugins...")
    plugins = [
        SmartHomePlugin
        # TimePlugin,
        # Base64Plugin,
        # GuessNumberPlugin,
        # #JiraPlugin,
        # UrlPlugin,
        # #GithubPlugin,
        # #JenkinsPlugin,
        # PrometheusPlugin,
    ]

    # setup engine
    engine = Engine(matrix, config)
    for plugin in plugins:
        engine.add_plugin(plugin)

    engine.setup()

    while True:
        try:
            log.info("Listening for incoming events.")
            engine.event_loop()
        except Exception as e:
            log.error("Ruh roh: %s", e)
        time.sleep(5)

    log.info("Terminating.")
Beispiel #8
0
def main(config):
    # setup api/endpoint
    matrix = MatrixHttpApi(config.base_url, config.token)

    log.debug("Setting up plugins...")
    plugins = [
        ToDoPlugin,
        UrlPlugin,
        GuessNumberPlugin,
    ]

    # setup engine
    engine = Engine(matrix, config)
    for plugin in plugins:
        engine.add_plugin(plugin)

    engine.setup()

    while True:
        try:
            log.info("Listening for incoming events.")
            engine.event_loop()
        except Exception as e:
            log.error("Ruh roh: %s", e)
        time.sleep(5)
Beispiel #9
0
def _get_matrix():
    try:
        return g.matrix
    except AttributeError:
        g.matrix = MatrixHttpApi('https://matrix.org',
                                 token=current_app.config['MATRIX_TOKEN'])
        return g.matrix
    def __init__(self, server: str, token: str, room: str):
        """Construct a new MatrixClient and init and sync MatrixHttpApi."""
        self.server = server
        self.token = token
        self.room = room

        self.api = MatrixHttpApi(self.server, token=self.token)
        self.api.initial_sync()
Beispiel #11
0
def announce(text, cred):
    matrix = MatrixHttpApi(cred.get("url", "https://matrix.org"),
                           token=cred['access_token'])
    for room in cred['rooms']:
        roomid = matrix.get_room_id(room)
        matrix.join_room(roomid)
        if not cred.get('mock', False): matrix.send_message(roomid, text)
Beispiel #12
0
    def __init__(
            self,
            base_url,
            room_id,
            username=None,
            password=None,
            token=None,
            use_m_text=False,
            format='[%(levelname)s] [%(asctime)s] [%(name)s] - %(message)s'):
        logging.Handler.__init__(self)

        self.base_url = base_url
        self.username = username
        self.password = password
        self.room_id = room_id
        self.token = token
        self.use_m_text = use_m_text

        self.matrix = MatrixHttpApi(base_url, token=self.token)

        self.formatter = logging.Formatter(format)
Beispiel #13
0
 def __init__(self):
     self.BOTUSERNAME = "******"
     self.BOTPASSWORD = "******"
     self.BOTSERVO = "matrix.org"
     self.RID = "!RnpiUpFIsfzZfHdHQf:matrix.org"
     self.realRID = "!obQcCWaLRAUgiGBvMg:postmarketos.org"
     self.MainClient = MatrixClient("https://" + self.BOTSERVO)
     self.token = self.MainClient.login_with_password(
         username=self.BOTUSERNAME, password=self.BOTPASSWORD)
     self.APIWrapper = MatrixHttpApi("https://" + self.BOTSERVO,
                                     token=self.token)
     self.target_room = Room(self.MainClient, self.RID)
     print("ready")
Beispiel #14
0
    def __init__(self, host=bothost, user=botuser, pwd=botpwd, room=botroom):
        print("Logging to matrix server...")
        self.chatclient = MatrixClient(host)
        try:
            self.chattoken = self.chatclient.login(username=user,
                                                   password=pwd,
                                                   sync=True)
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username or password.")
                sys.exit(4)
            else:
                print("Check your sever details are correct.")
                sys.exit(2)
        except MissingSchema as e:
            print("Bad URL format.")
            print(e)
            sys.exit(3)
        self.chatapi = MatrixHttpApi(host, self.chattoken)
        print("Login OK")

        ### handle messages
        print("Setting up listener")
        try:
            room = self.chatclient.join_room(room)
        except MatrixRequestError as e:
            print(e)
            if e.code == 400:
                print("Room ID/Alias in the wrong format")
                sys.exit(11)
            else:
                print("Couldn't find room.")
                sys.exit(12)

        room.add_listener(self.on_message)
        self.listener_thread_id = self.chatclient.start_listener_thread()
        print('Listener set.. OK!')
Beispiel #15
0
def send_message(matrix_room, message_plain, message):
    '''
    One day
    '''
    # Init matrix API
    matrix = MatrixHttpApi(settings.MATRIX_SERVER, token=settings.MATRIX_TOKEN)

    try:
        response = matrix.send_message_event(
            room_id=matrix_room,
            event_type="m.room.message",
            content={
                "msgtype": "m.text",
                "format": "org.matrix.custom.html",
                "body": message_plain,
                "formatted_body": message,
            }
        )
    except MatrixRequestError as ex:
        LOG.error('send_message_event failure %s', ex)
        return json.dumps({'success': False}), 417, {'ContentType':'application/json'}

    LOG.debug('Matrix Response: %s', response)
    return json.dumps({'success': True}), 200, {'ContentType':'application/json'}
Beispiel #16
0
    def connect(self):
        ''' log in to the server and get connected rooms'''
        password = self.config['bot']['password']
        username = self.username
        server = self.config['bot']['host']
        room_id = self.config['bot']['room']
        try:
            BOT_LOG.debug("Trying to log in as %s pw: %s", self.username,
                          "".join(['*' for p in password]))
            token = self.client.login(username, password)
            BOT_LOG.debug("Got Token %s..%s", token[0:3], token[-3:-1])
        except MatrixRequestError as error:
            BOT_LOG.error("Login Failed: Code: %s, Content: %s", error.code,
                          error.content)
        #this is a second connection with different interface
        BOT_LOG.debug("Creating matrix API endpoint")
        self.api = MatrixHttpApi(server, token)
        if str(room_id).startswith('!'):
            self.current_room = room_id
        else:
            self.current_room = self.get_room_id_by_name(room_id)
        BOT_LOG.debug("Joining room with id %s", self.current_room)
        self.api.join_room(self.current_room)

        BOT_LOG.debug("Getting member info")
        self.members = self.api.get_room_members(self.current_room)
        BOT_LOG.debug(
            "Members in room: %s", ",".join([
                a['sender'] if 'sender' in a.keys() else ""
                for a in self.members['chunk']
            ]))
        rooms = []
        for _, room in self.client.get_rooms().items():
            rooms.append(room)

        self.all_rooms = VirtualRoom(rooms)
Beispiel #17
0
    def __init__(self, settings):
        self.sync_token = None

        self.logger = utils.get_logger()

        self.settings = settings
        self.period = settings["DEFAULT"]["period"]
        self.uri = settings["matrix"]["uri"]
        self.username = settings["matrix"]["username"].lower()
        self.password = settings["matrix"]["password"]
        self.room_ids = settings["matrix"]["rooms"]
        self.domain = self.settings["matrix"]["domain"]

        self.subscriptions_room_ids = settings["subscriptions"]["rooms"]
        self.revokations_rooms_ids = settings["revokations"]["rooms"]

        self.client = MatrixClient(self.uri)
        self.token = self.client.login_with_password(username=self.username,
                                                     password=self.password)
        self.api = MatrixHttpApi(self.uri, token=self.token)
def _get_messages(request, sync_token, direction):
    storage = get_messages(request)
    for message in storage:
        user_name = message
        print("MESSAGE : ", message)

    print("_get_message username: "******" : ", direction)
    messages.add_message(request, messages.INFO, user_name)
    sys.stdout.flush()
    session = Session.objects.get(matrix_user_name=user_name.message)
    api = MatrixHttpApi(session.matrix_server, token=session.matrix_token)
    synced = api.get_room_messages(api.get_room_id(session.matrix_room_name),
                                   session.matrix_sync_token,
                                   direction,
                                   limit=session.message_count)
    session.matrix_sync_token = synced[sync_token]
    session.save()
    room_topic = api.get_room_topic(api.get_room_id(
        session.matrix_room_name))['topic']
    synced['chunk'] = _parse_messages(synced['chunk'])
    return synced
Beispiel #19
0
class MatrixEngine(object):
    chatapi = ''
    chatclient = ''
    chattoken = ''
    listener_thread_id = 0
    new_msg_queue = []
    new_msg_senders = []

    def __init__(self, host=bothost, user=botuser, pwd=botpwd, room=botroom):
        print("Logging to matrix server...")
        self.chatclient = MatrixClient(host)
        try:
            self.chattoken = self.chatclient.login(username=user,
                                                   password=pwd,
                                                   sync=True)
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username or password.")
                sys.exit(4)
            else:
                print("Check your sever details are correct.")
                sys.exit(2)
        except MissingSchema as e:
            print("Bad URL format.")
            print(e)
            sys.exit(3)
        self.chatapi = MatrixHttpApi(host, self.chattoken)
        print("Login OK")

        ### handle messages
        print("Setting up listener")
        try:
            room = self.chatclient.join_room(room)
        except MatrixRequestError as e:
            print(e)
            if e.code == 400:
                print("Room ID/Alias in the wrong format")
                sys.exit(11)
            else:
                print("Couldn't find room.")
                sys.exit(12)

        room.add_listener(self.on_message)
        self.listener_thread_id = self.chatclient.start_listener_thread()
        print('Listener set.. OK!')

    def sendmsg(self, msg, chatid=botroom):
        room = self.chatclient.join_room(chatid)
        response = self.chatapi.send_message(chatid, msg)

    def sendhtml(self, msg, chatid=botroom):
        room = self.chatclient.join_room(chatid)
        room.send_html(msg)

    def create_room(self, alias):
        ex_room = matrix_mongo.matrix_chats.find_one({"alias": alias})
        if ex_room:
            room_id = ex_room['room_id']
            room = self.chatclient.join_room(room_id)
            room.invite_user(ebuser)
        else:
            try:
                aldt = datetime.datetime.strftime(datetime.datetime.now(),
                                                  '%Y%m%d%H%M%S')
                new_room = self.chatclient.create_room(alias=alias + "_" +
                                                       aldt,
                                                       is_public=False,
                                                       invitees=[ebuser])
                room_id = new_room.room_id
                dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                   '%Y-%m-%d %H:%M:%S')
                chatdata = {
                    "created_date": dtime,
                    "alias": alias,
                    "room_alias": alias + "_" + aldt,
                    "room_id": room_id,
                    "room_data": room
                }

                recordID = matrix_mongo.matrix_chats.insert_one(chatdata)
            except MatrixRequestError as e:
                print(str(e))

        return room_id

    def sendfile(self, filename, chatid=botroom):
        room = self.chatclient.join_room(chatid)

        with open(filename, 'rb') as datafile:
            data = datafile.read()
            uri = self.chatclient.upload(content=data,
                                         content_type='image/jpg')
            print(uri)
            filedate = datetime.datetime.strftime(datetime.datetime.now(),
                                                  '%Y-%m-%d %H:%M:%S')
            room.send_image(
                uri, filedate + '_' + filename.replace('/', '_') + '.jpg')

    def on_message(self, room, event):
        try:
            # Called when a message is recieved.
            if event['type'] == "m.room.member":
                if event['membership'] == "join":
                    # print("{0} joined".format(event['content']['displayname']))
                    dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                       '%Y-%m-%d %H:%M:%S')
                    print(dtime + " new user joined to the room ")
            elif event['type'] == "m.room.message":
                if event['content']['msgtype'] == "m.text":
                    # print("{0}: {1}".format(event['sender'], event['content']['body']))
                    dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                       '%Y-%m-%d %H:%M:%S')
                    print(dtime + "|  '" + event['content']['body'] +
                          "' msg received from " + event['sender'])
                    if event['sender'] != "@mybot:matrix.org":
                        self.new_msg_senders.append(event['sender'])
                        self.new_msg_queue.append(event['content']['body'])
            else:
                print('new event in room:' + event['type'])
        except Exception as e:
            print('error @ on_message: ' + str(e))

    def parsemsg(self):
        for i in range(len(self.new_msg_queue)):
            origMsg = self.new_msg_queue[i]
            sender = self.new_msg_senders[i]

            msg = origMsg.lower()

            print("PARSER:  '" + origMsg + "' msg received from " + sender)

            def doshit():
                print('shit done')

            if msg == "test":
                doshit()
            elif msg == "msg":
                sendmsg("your msg responded!")
            elif msg == "html":
                sendhtml("your <b>html</b>  message <h1>responded</h1>!")
            else:
                print("message not understood")

            self.new_msg_queue.remove(origMsg)
            self.new_msg_senders.remove(sender)
Beispiel #20
0
class CrawlerMatrixClient:
    def __init__(self, token, server, roomid):
        self.server = server
        self.roomid = roomid
        self.token = token
        self.APIWrapper = MatrixHttpApi("https://{}".format(self.server), token=self.token)
        self.next_batch = self.APIWrapper.sync().get("next_batch")
        print("client initialized")

    def getChunk(self):
        b = self.APIWrapper.get_room_messages(self.roomid, self.next_batch, "b", limit=100)
        c = b.get("chunk")
        self.next_batch = b.get("end")
        return c

    def try_recover_suspend(self, output_file, contents, timestamps, names, message_count):
        with open(output_file, "r") as handle:
            a = handle.readlines()
            if a[len(a)-1] == "sus":
                print("\n\nrestoring from suspend'\n\n")
                self.next_batch = a[len(a)-2]
                a = a[:-2]
                for element in a:
                    b = element.split(";")
                    timestamps.append(b[0])
                    names.append(b[1])
                    contents.append(b[2])
                print("restored")
                return message_count - len(a) + 1 

    def suspend(self, contents, timestamps, names, output_file):
        print("suspending to output_file")
        with open(output_file, "w+") as handle:
            for i in range(len(contents)-1):
                handle.write(str(timestamps[i]))
                handle.write(";")
                handle.write(str(names[i]))
                handle.write(";")
                content = base64.b64encode(str.encode(str(contents[i]))).decode()
                handle.write(content)
                handle.write("\n")
            handle.write(self.next_batch)
            handle.write("\n")
            handle.write("sus")

    def dump_message_events(self, message_count, output_file):
        contents = []
        timestamps = []
        names = []
        try:
            message_count = self.try_recover_suspend(output_file, contents, timestamps, names, message_count)
        except:
            pass
        try:
            count = message_count // 100
            for progress in range(count):
                chunk = self.getChunk()
                for element in chunk:
                    content = element.get("content").get("body")
                    if content is not None:
                        timestamps.append(element.get("origin_server_ts"))
                        contents.append(content)
                        names.append(element.get("sender"))
                print("haha progress bar go brr {} out of {}".format(progress, count), end='\r')
            with open(output_file, "w+") as handle:
                for i in range(len(contents)-1):
                    handle.write(str(timestamps[i]))
                    handle.write(";")
                    handle.write(str(names[i]))
                    handle.write(";")
                    content = base64.b64encode(str.encode(str(contents[i]))).decode()
                    handle.write(content)
                    handle.write("\n")
                handle.write(self.next_batch)
                handle.write("\n")
                handle.write("sus")
        except KeyboardInterrupt:
            self.suspend(contents, timestamps, names, output_file)
Beispiel #21
0
        settings = yaml.load(stream)
except IOError as e:
    sys.exit("no settings.yaml found!")

# CONSTANTS
DOMAIN = settings['DOMAIN']
SERVICES = settings['SERVICES']
ROOMS = settings['ROOMS']
TOKEN = settings['TOKEN']


def online(service):
    stat = os.system('systemctl is-active --quiet {}'.format(service))
    if not stat:
        return True
    return False


matrix = MatrixHttpApi(DOMAIN, token=TOKEN)
status = False
for service in SERVICES:
    if not online(service):
        status = True
        message = "Service: '{}' is offline".format(service)
        print(message)
        for room in ROOMS:
            matrix.join_room(room)
            response = matrix.send_message(room, message)
if not status:
    print("everything is fine")
Beispiel #22
0
from auth import url, host, room, token

import pprint

from matrix_client.api import MatrixHttpApi
from matrix_client.api import MatrixRequestError

pp = pprint.PrettyPrinter(indent=4)
pp = pp.pprint

matrix = MatrixHttpApi(host, token=token)

try:
    # pp(matrix.get_room_state(room))
    msg = input("Message : ")
    print(msg)
    print(matrix.send_message(room, msg))

except MatrixRequestError as e:
    print(e)
    if e.code == 400:
        print("Room ID/Alias in the wrong format")
    else:
        print("Couldn't find room.")
Beispiel #23
0
class MatrixBot:
    """The main bot, connecting to the server and handling plugins"""
    def __init__(self, config):
        self.username = config['bot']['username']
        server = config['bot']['host']
        self.fullname = "@" + str(
            self.username).lower() + ':' + urlparse(server).hostname
        self.plugins = []
        self.api = None
        self.current_room = ""
        self.members = []
        self.all_rooms = None
        self.config = config
        # Connect to server
        BOT_LOG.debug("creating matrix client for server %s", server)
        self.client = MatrixClient(server)

    def connect(self):
        ''' log in to the server and get connected rooms'''
        password = self.config['bot']['password']
        username = self.username
        server = self.config['bot']['host']
        room_id = self.config['bot']['room']
        try:
            BOT_LOG.debug("Trying to log in as %s pw: %s", self.username,
                          "".join(['*' for p in password]))
            token = self.client.login(username, password)
            BOT_LOG.debug("Got Token %s..%s", token[0:3], token[-3:-1])
        except MatrixRequestError as error:
            BOT_LOG.error("Login Failed: Code: %s, Content: %s", error.code,
                          error.content)
        #this is a second connection with different interface
        BOT_LOG.debug("Creating matrix API endpoint")
        self.api = MatrixHttpApi(server, token)
        if str(room_id).startswith('!'):
            self.current_room = room_id
        else:
            self.current_room = self.get_room_id_by_name(room_id)
        BOT_LOG.debug("Joining room with id %s", self.current_room)
        self.api.join_room(self.current_room)

        BOT_LOG.debug("Getting member info")
        self.members = self.api.get_room_members(self.current_room)
        BOT_LOG.debug(
            "Members in room: %s", ",".join([
                a['sender'] if 'sender' in a.keys() else ""
                for a in self.members['chunk']
            ]))
        rooms = []
        for _, room in self.client.get_rooms().items():
            rooms.append(room)

        self.all_rooms = VirtualRoom(rooms)

    def init_scheduler(self):
        ''' initialize a thread that handles the event loop for
        the scheduler for all plugins'''
        BOT_LOG.debug("Spinning up scheduler thread")
        self.schedule = schedule
        self.killswitch = Event()
        self.killswitch.clear()
        self.thread = Thread(target=self.schedule_loop,
                             args=(self.killswitch, ))
        #self.thread.daemon = True
        self.thread.start()

    def stop_scheduler(self):
        ''' wind down the scheduler thread gracefully before exit'''
        BOT_LOG.debug("Trying to end scheduler thread ..")
        self.killswitch.set()
        self.thread.join()
        BOT_LOG.debug("..successful")

    def schedule_loop(self, stop_event):
        ''' this event loop is run inside the scheduler thread'''
        BOT_LOG.debug("Scheduler thread started successfully")
        while not stop_event.is_set():
            #BOT_LOG.debug("Scheduler loop runs")
            self.schedule.run_pending()
            sleep(10)

    def add_plugin(self, plugin):
        """Puts a plugin in the internal list
        where it will be registered as a listener"""
        self.plugins.append(plugin)

    def get_room_id_by_name(self, name):
        """Translate human-readable room name into internal room id"""
        BOT_LOG.debug("Getting room ID for name '%s'", name)
        if str(name).startswith('#'):
            rid = self.api.get_room_id(name)
        else:
            rid = self.api.get_room_id('#' + name)
        if rid is None:
            BOT_LOG.warning("Room name '%s' not found", name)
            rid = ""
        return rid

    def send(self, text):
        """Sending initial message to room to announce startup"""
        BOT_LOG.debug("Sending sample text to room")
        self.api.send_message(self.current_room, text)

    def start_polling(self):
        """Starts syncing and polling for new messages in a new thread"""
        # Starts polling for messages
        self.client.start_listener_thread()
        return self.client.sync_thread

    def register_listeners(self):
        ''' register the added plugins as listeners into the rooms
        the bot si connected to'''
        rooms = []
        for room_id, room in self.client.get_rooms().items():
            BOT_LOG.debug("Registering plugins in room %s (%s)", room.name,
                          room_id)
            rooms.append(room)
            for plugin in self.plugins:
                room.add_listener(plugin.handle_message)
Beispiel #24
0
def startup(config):
    # setup api/endpoint
    login = config.json['user_id'][1:].split(":")[0]
    if not config.json['token']:
        matrix = MatrixHttpApi(config.json['url'])
        matrix.validate_certificate(config.json['cert_verify'])
        try:
            res = matrix.login(login_type="m.login.password",
                               user=login,
                               password=config.json['password'])
        except MatrixRequestError as err:
            log.error("Login error: %r" % err)
            exit()
        log.debug("Login result: %r" % res)
        config.json['token'] = res["access_token"]
        matrix.token = config.json['token']
    else:
        matrix = MatrixHttpApi(config.json['url'], config.json['token'])
        matrix.validate_certificate(config.json['cert_verify'])

    config.save()

    # Update Display Name if needed
    cur_dn = matrix.get_display_name(config.json['user_id'])
    if not login == cur_dn:
        matrix.set_display_name(config.json['user_id'], login)

    # root path for plugin search and locale load
    config.rootf = os.path.dirname(os.path.abspath(matrix_bot.__file__))
    log.debug("Matrix_bot root folder: %s" % config.rootf)
    log.debug("Matrix_bot configuration: %s" %
              json.dumps(config.json, indent=4, sort_keys=True))

    # setup engine
    engine = Engine(matrix, config)
    # Dytnamic plugin load from plugins folder
    osppath = os.path.join(config.rootf, "plugins")
    lst = os.listdir(osppath)
    for fil in lst:
        name, ext = os.path.splitext(fil)
        if (not os.path.isdir(os.path.join(osppath, fil)) and not fil[0] == "_"
                and ext in (".py")):
            try:
                mod = __import__("matrix_bot.plugins." + name, fromlist=["*"])
                for cls in inspect.getmembers(mod, inspect.isclass):
                    if hasattr(cls[1], "name"):
                        if not config.json['plugins'] or cls[
                                1].name in config.json['plugins']:
                            engine.add_plugin(cls[1])
                            log.info("Load plugin %s (%s) from %s" %
                                     (cls[1].name, cls[0],
                                      os.path.join("plugins", fil)))
                        else:
                            log.info(
                                "Skip plugin %s (%s) from %s - not listed in config"
                                % (cls[1].name, cls[0],
                                   os.path.join("plugins", fil)))
            except ImportError as err:
                log.error("Plugin module %s import error: %r" %
                          ("plugins." + fil, err))

    engine.setup()

    while True:
        try:
            log.info("Listening for incoming events.")
            engine.event_loop()
        except Exception as e:
            log.error("Ruh roh: %s", e)
        time.sleep(5)

    log.info("Terminating.")
Beispiel #25
0
class MatrixBackend(ErrBot):
    def __init__(self, config):
        super().__init__(config)

        if not hasattr(config, 'MATRIX_HOMESERVER'):
            log.fatal("""
            You need to specify a homeserver to connect to in
            config.MATRIX_HOMESERVER.

            For example:
            MATRIX_HOMESERVER = "https://matrix.org"
            """)
            sys.exit(1)

        self._homeserver = config.MATRIX_HOMESERVER
        self._username = config.BOT_IDENTITY['username']
        self._password = config.BOT_IDENTITY['password']
        self._api = None
        self._token = None

    def serve_once(self):
        def dispatch_event(event):
            log.info("Received event: %s" % event)

            if event['type'] == "m.room.member":
                if event['membership'] == "invite" and event[
                        'state_key'] == self._client.user_id:
                    room_id = event['room_id']
                    self._client.join_room(room_id)
                    log.info("Auto-joined room: %s" % room_id)

            if event['type'] == "m.room.message" and event[
                    'sender'] != self._client.user_id:
                sender = event['sender']
                room_id = event['room_id']
                body = event['content']['body']
                log.info("Received message from %s in room %s" %
                         (sender, room_id))

                # msg = Message(body)
                # msg.frm = MatrixPerson(self._client, sender, room_id)
                # msg.to = MatrixPerson(self._client, self._client.user_id, room_id)
                # self.callback_message(msg)

                msg = self.build_message(body)
                room = MatrixRoom(room_id)
                msg.frm = MatrixRoomOccupant(self._api, room, sender)
                msg.to = room
                self.callback_message(msg)

        self.reset_reconnection_count()
        self.connect_callback()

        self._client = MatrixClient(self._homeserver)

        try:
            self._token = self._client.register_with_password(
                self._username,
                self._password,
            )
        except MatrixRequestError as e:
            if e.code == 400:
                try:
                    self._token = self._client.login_with_password(
                        self._username,
                        self._password,
                    )
                except MatrixRequestError:
                    log.fatal("""
                        Incorrect username or password specified in
                        config.BOT_IDENTITY['username'] or config.BOT_IDENTITY['password'].
                    """)
                    sys.exit(1)

        self._api = MatrixHttpApi(self._homeserver, self._token)

        self.bot_identifier = MatrixPerson(self._api)

        self._client.add_listener(dispatch_event)

        try:
            while True:
                self._client.listen_for_events()
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down...")
            return True
        finally:
            self.disconnect_callback()

    def rooms(self):
        rooms = []
        raw_rooms = self._client.get_rooms()

        for rid, robject in raw_rooms:
            # TODO: Get the canonical alias rather than the first one from
            #       `Room.aliases`.
            log.debug('Found room %s (aka %s)' % (rid, rid.aliases[0]))

    def send_message(self, mess):
        super().send_message(mess)

        room_id = mess.to.room.id
        text_content = item_url = mess.body

        if item_url.startswith("http://") or item_url.startswith("https://"):
            if item_url.endswith("gif"):
                self._api.send_content(room_id, item_url, "image", "m.image")
                return

        # text_content = Markdown().convert(mess.body)
        self._api.send_message(room_id, text_content)

    def connect_callback(self):
        super().connect_callback()

    def build_identifier(self, txtrep):
        raise Exception("XXX")

    def build_reply(self, mess, text=None, private=False):
        log.info("build_reply")

        response = self.build_message(text)
        response.frm = self.bot_identifier
        response.to = mess.frm
        return response

    def change_presence(self, status: str = '', message: str = ''):
        raise Exception("XXX")

    @property
    def mode(self):
        return 'matrix'

    def query_room(self, room):
        raise Exception("XXX")
Beispiel #26
0
if homeserver.endswith('/'):
    homeserver = homeserver[:-1]

if username.startswith('@'):
    username = username[1:]

if username.find(':') > 0:
    username = username.split(':')[0]

matrix = None

for retry in range(0, 4):
    try:
        client = MatrixClient(homeserver)
        token = client.login(username, password)
        matrix = MatrixHttpApi(homeserver, token)
        break
    except MatrixHttpLibError:
        sys.stderr.write('Connection failed, retrying...\n')
        time.sleep(0.25)

if matrix == None:
    sys.stderr.write('Could not connect to homeserver. Message not sent.\n')
    sys.exit(-2)

try:
    client.rooms[room_id].send_text(message)
except:
    sys.stderr.write('Failed to send message to room.\n')
    sys.exit(-3)
Beispiel #27
0
class MatrixBot():
    def __init__(self, settings):
        self.sync_token = None

        self.logger = utils.get_logger()
        self.cache = utils.create_cache(settings)
        self.cache_timeout = int(settings["memcached"]["timeout"])

        self.settings = settings
        self.period = settings["DEFAULT"]["period"]
        self.uri = settings["matrix"]["uri"]
        self.username = settings["matrix"]["username"].lower()
        self.password = settings["matrix"]["password"]
        self.room_ids = settings["matrix"]["rooms"]
        self.domain = self.settings["matrix"]["domain"]
        self.only_local_domain = self.settings["matrix"]["only_local_domain"]

        self.subscriptions_room_ids = settings["subscriptions"].keys()
        self.revokations_rooms_ids = settings["revokations"].keys()
        self.allowed_join_rooms_ids = filter(lambda x: x != 'default',
                                             settings["allowed-join"].keys())
        self.default_allowed_join_rooms = settings["allowed-join"]["default"]

        self.client = MatrixClient(self.uri)
        self.token = self.client.login_with_password(username=self.username,
                                                     password=self.password)
        self.api = MatrixHttpApi(self.uri, token=self.token)

        self.rooms = []
        self.room_aliases = {}
        self.plugins = []
        for plugin in settings['plugins'].itervalues():
            mod = __import__(plugin['module'], fromlist=[plugin['class']])
            klass = getattr(mod, plugin['class'])
            self.plugins.append(klass(self, plugin['settings']))

    def _get_selected_users(self, groups_users_list):
        def _add_or_remove_user(users, username, append):
            username = self.normalize_user_id(username)
            if append and username not in users["in"]:
                users["in"].append(username)
            if not append and username not in users["out"]:
                users["out"].append(username)

        ldap_settings = self.settings["ldap"]
        append = True
        users = {"in": [], "out": []}
        for item in groups_users_list:
            if item == ("but"):
                append = False
            elif item.startswith("+"):
                group_name = item[1:]
                groups_members = bot_ldap.get_ldap_groups_members(
                    ldap_settings)
                if group_name in groups_members.keys():
                    map(lambda x: _add_or_remove_user(users, x, append),
                        groups_members[group_name])
            else:
                _add_or_remove_user(users, item, append)

        selected_users = filter(lambda x: x not in users["out"], users["in"])
        return selected_users

    def normalize_user_id(self, user_id):
        if not user_id.startswith("@"):
            user_id = "@" + user_id
            self.logger.debug("Adding missing '@' to the username: %s" %
                              user_id)
        if user_id.count(":") == 0:
            user_id = "%s:%s" % (user_id, self.domain)
        return user_id

    def get_user_id(self, username=None, normalized=True):
        if not username:
            username = self.username
        normalized_username = self.normalize_user_id(username)
        if normalized:
            return normalized_username
        else:
            return normalized_username[1:].split(':')[0]

    def is_local_user_id(self, username):
        normalized_username = self.get_user_id(username, normalized=True)
        if normalized_username.split(':')[1] == self.domain:
            return True
        return False

    def get_real_room_id(self, room_id):
        if room_id.startswith("#"):
            room_id = self.api.get_room_id(room_id)
        return room_id

    def get_room_members(self, room_id):
        key = "get_room_members-%s" % room_id
        res = self.cache.get(key)
        if res:
            self.logger.debug("get_room_members (cached): %s" % (key))
            return res
        res = self.call_api("get_room_members", 2, room_id)
        self.cache.set(key, res, self.cache_timeout)
        self.logger.debug("get_room_members (non cached): %s" % (key))
        return res

    def is_room_member(self, room_id, user_id):
        try:
            r = Room(self.client, room_id)
            return user_id in r.get_joined_members().keys()
        except Exception, e:
            return False
        return False
Beispiel #28
0
Info:   {HOSTOUTPUT}
When:   {LONGDATETIME}
{COMMENT_PLAIN}
{ICINGA_WEBURL}/monitoring/host/show?host={HOSTNAME}
""".format(**DATA)

# Message in markdown
MSG_MD = """**<font color="{COLOR}">[{NOTIFICATIONTYPE}] Host {HOSTDISPLAYNAME} is {HOSTSTATE}</font>**

> *Info:*
>
> {HOSTOUTPUT}
{COMMENT_MD}
> *{LONGDATETIME} - [Show in Icinga2]({ICINGA_WEBURL}/monitoring/host/show?host={HOSTNAME})*
""".format(**DATA)

# Init matrix API
matrix = MatrixHttpApi(environ['MATRIX_SERVER'], token=environ['MATRIX_TOKEN'])

# Send message in both formats to channel
response = matrix.send_message_event(
    room_id=environ['MATRIX_CHANNEL'],
    event_type="m.room.message",
    content={
        "msgtype": "m.text",
        "format": "org.matrix.custom.html",
        "body": MSG_PLAIN,
        "formatted_body": Markdown().convert(MSG_MD),
    }
)
Beispiel #29
0
class MatrixBackend(ErrBot):
    def __init__(self, config):
        super().__init__(config)

        if not hasattr(config, 'MATRIX_HOMESERVER'):
            log.fatal("""
            You need to specify a homeserver to connect to in
            config.MATRIX_HOMESERVER.

            For example:
            MATRIX_HOMESERVER = "https://matrix.org"
            """)
            sys.exit(1)

        self._homeserver = config.MATRIX_HOMESERVER
        self._username = config.BOT_IDENTITY['username']
        self._password = config.BOT_IDENTITY['password']
        self._api = None
        self._token = None


    def serve_once(self):
        def dispatch_event(event):
            log.info("Received event: %s" % event)

            if event['type'] == "m.room.member":
                if event['membership'] == "invite" and event['state_key'] == self._client.user_id:
                    room_id = event['room_id']
                    self._client.join_room(room_id)
                    log.info("Auto-joined room: %s" % room_id)

            if event['type'] == "m.room.message" and event['sender'] != self._client.user_id:
                sender = event['sender']
                room_id = event['room_id']
                body = event['content']['body']
                log.info("Received message from %s in room %s" % (sender, room_id))

                # msg = Message(body)
                # msg.frm = MatrixPerson(self._client, sender, room_id)
                # msg.to = MatrixPerson(self._client, self._client.user_id, room_id)
                # self.callback_message(msg) 

                msg = self.build_message(body)
                room = MatrixRoom(room_id)
                msg.frm = MatrixRoomOccupant(self._api, room, sender)
                msg.to = room
                self.callback_message(msg) 

        self.reset_reconnection_count()
        self.connect_callback()

        self._client = MatrixClient(self._homeserver)

        try:
            self._token = self._client.register_with_password(self._username,
                                                              self._password,)
        except MatrixRequestError as e:
            if e.code == 400 or e.code == 403:
                try:
                    self._token = self._client.login_with_password(self._username,
                                                     self._password,)
                except MatrixRequestError:
                    log.fatal("""
                        Incorrect username or password specified in
                        config.BOT_IDENTITY['username'] or config.BOT_IDENTITY['password'].
                    """)
                    sys.exit(1)

        self._api = MatrixHttpApi(self._homeserver, self._token)

        self.bot_identifier = MatrixPerson(self._api)

        self._client.add_listener(dispatch_event)

        try:
            while True:
                self._client.listen_for_events()
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down...")
            return True
        finally:
            self.disconnect_callback()

    def rooms(self):
        rooms = []
        raw_rooms = self._client.get_rooms()

        for rid, robject in raw_rooms:
            # TODO: Get the canonical alias rather than the first one from
            #       `Room.aliases`.
            log.debug('Found room %s (aka %s)' % (rid, rid.aliases[0]))

    def send_message(self, mess):
        super().send_message(mess)

        room_id = mess.to.room.id
        text_content = item_url = mess.body

        if item_url.startswith("http://") or item_url.startswith("https://"):
            if item_url.endswith("gif"):
                self._api.send_content(room_id, item_url, "image", "m.image")
                return

        # text_content = Markdown().convert(mess.body)
        self._api.send_message(room_id, text_content)

    def connect_callback(self):
        super().connect_callback()

    def build_identifier(self, txtrep):
        raise Exception(
            "XXX"
        )

    def build_reply(self, mess, text=None, private=False):
        log.info("build_reply")

        response = self.build_message(text)
        response.frm = self.bot_identifier
        response.to = mess.frm
        return response

    def change_presence(self, status: str = '', message: str = ''):
        raise Exception(
            "XXX"
        )

    @property
    def mode(self):
        return 'matrix'

    def query_room(self, room):
        raise Exception(
            "XXX"
        )
Beispiel #30
0
    def serve_once(self):
        def dispatch_event(event):
            log.info("Received event: %s" % event)

            if event['type'] == "m.room.member":
                if event['membership'] == "invite" and event['state_key'] == self._client.user_id:
                    room_id = event['room_id']
                    self._client.join_room(room_id)
                    log.info("Auto-joined room: %s" % room_id)

            if event['type'] == "m.room.message" and event['sender'] != self._client.user_id:
                sender = event['sender']
                room_id = event['room_id']
                body = event['content']['body']
                log.info("Received message from %s in room %s" % (sender, room_id))

                # msg = Message(body)
                # msg.frm = MatrixPerson(self._client, sender, room_id)
                # msg.to = MatrixPerson(self._client, self._client.user_id, room_id)
                # self.callback_message(msg) 

                msg = self.build_message(body)
                room = MatrixRoom(room_id)
                msg.frm = MatrixRoomOccupant(self._api, room, sender)
                msg.to = room
                self.callback_message(msg) 

        self.reset_reconnection_count()
        self.connect_callback()

        self._client = MatrixClient(self._homeserver)

        try:
            self._token = self._client.register_with_password(self._username,
                                                              self._password,)
        except MatrixRequestError as e:
            if e.code == 400 or e.code == 403:
                try:
                    self._token = self._client.login_with_password(self._username,
                                                     self._password,)
                except MatrixRequestError:
                    log.fatal("""
                        Incorrect username or password specified in
                        config.BOT_IDENTITY['username'] or config.BOT_IDENTITY['password'].
                    """)
                    sys.exit(1)

        self._api = MatrixHttpApi(self._homeserver, self._token)

        self.bot_identifier = MatrixPerson(self._api)

        self._client.add_listener(dispatch_event)

        try:
            while True:
                self._client.listen_for_events()
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down...")
            return True
        finally:
            self.disconnect_callback()
Beispiel #31
0
    def serve_once(self):
        def dispatch_event(event):
            log.info("Received event: %s" % event)

            if event['type'] == "m.room.member":
                if event['membership'] == "invite" and event[
                        'state_key'] == self._client.user_id:
                    room_id = event['room_id']
                    self._client.join_room(room_id)
                    log.info("Auto-joined room: %s" % room_id)

            if event['type'] == "m.room.message" and event[
                    'sender'] != self._client.user_id:
                sender = event['sender']
                room_id = event['room_id']
                body = event['content']['body']
                log.info("Received message from %s in room %s" %
                         (sender, room_id))

                # msg = Message(body)
                # msg.frm = MatrixPerson(self._client, sender, room_id)
                # msg.to = MatrixPerson(self._client, self._client.user_id, room_id)
                # self.callback_message(msg)

                msg = self.build_message(body)
                room = MatrixRoom(room_id)
                msg.frm = MatrixRoomOccupant(self._api, room, sender)
                msg.to = room
                self.callback_message(msg)

        self.reset_reconnection_count()
        self.connect_callback()

        self._client = MatrixClient(self._homeserver)

        try:
            self._token = self._client.register_with_password(
                self._username,
                self._password,
            )
        except MatrixRequestError as e:
            if e.code == 400:
                try:
                    self._token = self._client.login_with_password(
                        self._username,
                        self._password,
                    )
                except MatrixRequestError:
                    log.fatal("""
                        Incorrect username or password specified in
                        config.BOT_IDENTITY['username'] or config.BOT_IDENTITY['password'].
                    """)
                    sys.exit(1)

        self._api = MatrixHttpApi(self._homeserver, self._token)

        self.bot_identifier = MatrixPerson(self._api)

        self._client.add_listener(dispatch_event)

        try:
            while True:
                self._client.listen_for_events()
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down...")
            return True
        finally:
            self.disconnect_callback()
Beispiel #32
0
    def __init__(self):
        logger.info('logging in to Matrix as %s', config.matrix.username)

        self._client = MatrixClient(config.matrix.server)
        self._token = self._client.login(username=config.matrix.username, password=config.matrix.password, sync=False)
        self._api = MatrixHttpApi(config.matrix.server, self._token)
Beispiel #33
0
def matrix_sender(homeserver: str, token: str, room: str):
    """
    Matrix sender wrapper: execute func, send a Matrix message with the end status
    (sucessfully finished or crashed) at the end. Also send a Matrix message before
    executing func.

    `homeserver`: str
        The homeserver address which was used to register the BOT.
        It is e.g. 'https://matrix-client.matrix.org'. It can be also looked up
        in Riot by looking in the riot settings, "Help & About" at the bottom.
        Specifying the schema (`http` or `https`) is required.
    `token`: str
        The access TOKEN of the user that will send the messages.
        It can be obtained in Riot by looking in the riot settings, "Help & About" ,
        down the bottom is: Access Token:<click to reveal>
    `room`: str
        The alias of the room to which messages will be send by the BOT.
        After creating a room, an alias can be set. In Riot, this can be done
        by opening the room settings under 'Room Addresses'.
    """

    matrix = MatrixHttpApi(homeserver, token=token)
    room_id = matrix.get_room_id(room)

    def decorator_sender(func):

        def send_message(text, room_id=room_id):
            matrix.send_message(room_id, text)

        @functools.wraps(func)
        def wrapper_sender(*args, **kwargs):

            start_time = datetime.datetime.now()
            host_name = socket.gethostname()
            func_name = func.__name__
            text = ""
            if include_details:
                text += f'{func_name} called on {host_name} at {start_time.strftime(DATE_FORMAT)}'
            if message:
                text += f'{func_name}: {message}' if not include_details else f'\nMessage: {message}'
            if notify_end:
                text += '\nWe\'ll let you know when it\'s done.'

            send_message(text=text)

            try:
                value = func(*args, **kwargs)
                if notify_end:
                    end_time = datetime.datetime.now()
                    elapsed_time = end_time - start_time
                    text = ""
                    text += f'✅ {func_name} finished on {host_name} at {end_time.strftime(DATE_FORMAT)}'
                    text += f'\nDuration: {elapsed_time}'

                    try:
                        str_value = str(value)
                        text += f'\nReturned value: {str_value}'
                    except:
                        text += f'\nReturned value: ERROR - Couldn\'t parse the returned value.'

                    send_message(text=text)

                return value

            except Exception as ex:
                end_time = datetime.datetime.now()
                elapsed_time = end_time - start_time
                contents = [f"☠️ {func_name} has crashed on {host_name} at {end_time.strftime(DATE_FORMAT)}",
                            "Here's the error:",
                            '%s\n\n' % ex,
                            "Traceback:",
                            '%s' % traceback.format_exc()]
                text = '\n'.join(contents)
                send_message(text=text)
                raise ex

        return wrapper_sender

    return decorator_sender
Beispiel #34
0
def matrix_sender(homeserver: str, token: str, room: str):
    """
    Matrix sender wrapper: execute func, send a Matrix message with the end status
    (sucessfully finished or crashed) at the end. Also send a Matrix message before
    executing func.

    `homeserver`: str
        The homeserver address which was used to register the BOT.
        It is e.g. 'https://matrix-client.matrix.org'. It can be also looked up
        in Riot by looking in the riot settings, "Help & About" at the bottom.
        Specifying the schema (`http` or `https`) is required.
    `token`: str
        The access TOKEN of the user that will send the messages.
        It can be obtained in Riot by looking in the riot settings, "Help & About" ,
        down the bottom is: Access Token:<click to reveal>
    `room`: str
        The alias of the room to which messages will be send by the BOT.
        After creating a room, an alias can be set. In Riot, this can be done
        by opening the room settings under 'Room Addresses'.
    """

    matrix = MatrixHttpApi(homeserver, token=token)
    room_id = matrix.get_room_id(room)

    def decorator_sender(func):
        @functools.wraps(func)
        def wrapper_sender(*args, **kwargs):

            start_time = datetime.datetime.now()
            host_name = socket.gethostname()
            func_name = func.__name__

            # Handling distributed training edge case.
            # In PyTorch, the launch of `torch.distributed.launch` sets up a RANK environment variable for each process.
            # This can be used to detect the master process.
            # See https://github.com/pytorch/pytorch/blob/master/torch/distributed/launch.py#L211
            # Except for errors, only the master process will send notifications.
            if 'RANK' in os.environ:
                master_process = (int(os.environ['RANK']) == 0)
                host_name += ' - RANK: %s' % os.environ['RANK']
            else:
                master_process = True

            if master_process:
                contents = [
                    'Your training has started 🎬',
                    'Machine name: %s' % host_name,
                    'Main call: %s' % func_name,
                    'Starting date: %s' % start_time.strftime(DATE_FORMAT)
                ]
                text = '\n'.join(contents)

                matrix.send_message(room_id, text)

            try:
                value = func(*args, **kwargs)

                if master_process:
                    end_time = datetime.datetime.now()
                    elapsed_time = end_time - start_time
                    contents = [
                        "Your training is complete 🎉",
                        'Machine name: %s' % host_name,
                        'Main call: %s' % func_name,
                        'Starting date: %s' % start_time.strftime(DATE_FORMAT),
                        'End date: %s' % end_time.strftime(DATE_FORMAT),
                        'Training duration: %s' % str(elapsed_time)
                    ]

                    try:
                        str_value = str(value)
                        contents.append('Main call returned value: %s' %
                                        str_value)
                    except:
                        contents.append(
                            'Main call returned value: %s' %
                            "ERROR - Couldn't str the returned value.")

                    text = '\n'.join(contents)
                    matrix.send_message(room_id, text)

                return value

            except Exception as ex:
                end_time = datetime.datetime.now()
                elapsed_time = end_time - start_time
                contents = [
                    "Your training has crashed ☠️",
                    'Machine name: %s' % host_name,
                    'Main call: %s' % func_name,
                    'Starting date: %s' % start_time.strftime(DATE_FORMAT),
                    'Crash date: %s' % end_time.strftime(DATE_FORMAT),
                    'Crashed training duration: %s\n\n' % str(elapsed_time),
                    "Here's the error:",
                    '%s\n\n' % ex, "Traceback:",
                    '%s' % traceback.format_exc()
                ]
                text = '\n'.join(contents)
                matrix.send_message(room_id, text)
                raise ex

        return wrapper_sender

    return decorator_sender