Ejemplo n.º 1
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)
Ejemplo n.º 2
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)
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
Ejemplo n.º 4
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
Ejemplo n.º 5
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
Ejemplo n.º 6
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
Ejemplo n.º 7
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)
def chat(request, update=""):
    user_name = None
    storage = get_messages(request)
    for message in storage:
        user_name = message
        print("MESSAGE : ", message)

    if user_name != None:
        print("username: "******"LOGIN VARS")
        print("session.matrix_user_name ", session.matrix_user_name)
        print("session.matrix_room_name ", session.matrix_room_name)
        print("session.matrix_server ", session.matrix_server)
        print("session.message_count ", session.message_count)
        print("session.show_images ", session.show_images)
        sys.stdout.flush()
        api = MatrixHttpApi(session.matrix_server, token=session.matrix_token)
        print("GET_MEMBERSHIP")
        api.join_room(api.get_room_id(session.matrix_room_name))
    else:
        return HttpResponseRedirect('/')

    if request.method == 'POST':  #If the user hit send button
        try:
            print("Posting chat")
            sys.stdout.flush()
            chat_form = ChatForm(request.POST)
            if chat_form.is_valid():
                response = api.send_message(
                    api.get_room_id(session.matrix_room_name),
                    chat_form.cleaned_data['text_entered'])
                chat_form = ChatForm()
                room_topic = api.get_room_topic(
                    api.get_room_id(session.matrix_room_name))['topic']
                messages.add_message(request, messages.INFO,
                                     session.matrix_user_name)
                synced = _get_messages(request,
                                       sync_token="end",
                                       direction='f')
                session.messages = json.dumps(synced['chunk'] +
                                              jsonDec.decode(session.messages))
                session.save()
                return render(
                    request, 'client_app/chat.html', {
                        'chat_form': chat_form,
                        'name': session.matrix_user_name,
                        'messages': jsonDec.decode(session.messages),
                        'room': session.matrix_room_name,
                        'topic': room_topic,
                        'show_images': session.show_images
                    })

        except MatrixRequestError as e:
            print(str(e))
            sys.stdout.flush()
            form = NameForm(request.POST)
            return render(request, 'client_app/login.html', {
                'form': form,
                'login_error': True,
                'error_text': str(e)
            })
        else:
            return render(
                request, 'client_app/chat.html', {
                    'chat_form': chat_form,
                    'name': session.matrix_user_name,
                    'messages': jsonDec.decode(session.messages),
                    'room': session.matrix_room_name,
                    'topic': room_topic,
                    'show_images': session.show_images
                })
    if update == "":  #If not asking for an update, get first sync to server
        try:
            chat_form = ChatForm()
            synced = api.sync()
            room_topic = api.get_room_topic(
                api.get_room_id(session.matrix_room_name))['topic']
            session.matrix_sync_token = synced["next_batch"]
            messages.add_message(request, messages.INFO,
                                 session.matrix_user_name)
            synced = _get_messages(request, sync_token="start", direction='b')
            session.messages = json.dumps(synced['chunk'])
            session.save()

        except MatrixRequestError as e:
            print(str(e))
            sys.stdout.flush()
            form = NameForm(request.POST)
            return render(request, 'client_app/login.html', {
                'form': form,
                'login_error': True
            })
        else:
            return render(
                request, 'client_app/chat.html', {
                    'chat_form': chat_form,
                    'name': session.matrix_user_name,
                    'messages': jsonDec.decode(session.messages),
                    'room': session.matrix_room_name,
                    'topic': room_topic,
                    'show_images': session.show_images
                })
    else:  # update is requested so return next messages using sync token from initial sync
        chat_form = ChatForm()
        room_topic = api.get_room_topic(
            api.get_room_id(session.matrix_room_name))['topic']
        messages.add_message(request, messages.INFO, session.matrix_user_name)
        synced = _get_messages(request, sync_token="end", direction='f')
        session.messages = json.dumps(synced['chunk'] +
                                      jsonDec.decode(session.messages))
        session.save()
        return render(
            request, 'client_app/chat.html', {
                'chat_form': chat_form,
                'name': session.matrix_user_name,
                'messages': jsonDec.decode(session.messages),
                'room': session.matrix_room_name,
                'topic': room_topic,
                'show_images': session.show_images
            })