#5 Fourth Week (Show me your pass, please?)

I've spent most of my time implementing the background task which validates a user's room membership to a particular room.


TL;DR

  • Background validator task
  • Global app state for the backend

Related PRs:

Long Version: 

How does the background task validate a user's room membership?

  1. The background task verifies all the users currently registered with the app and it runs at uniform intervals (a specific time period
  2. It starts by fetching the users and rooms list from `matrix-cerberus.global_data` event type in account data.
  3. Then the bot has two loops iterating over the users and the rooms to gets a user's membership in a particular room.
    • For join and invite states, I've tried to use the data which is cached internally by matrix-nio on every successful sync with the matrix homeserver.
    • When it comes to the other states such as ban, knock  and leave the bot will try to  fetch the m.room.member room state event with the user_id as state_key.
    • But, it feels like there's something missing in here. Don't you think?
      Well, you are right.
      We are not keeping track of users who have either:
      • Rejected an invite
      • Retracted their knock
      • User left the room
      • Was kicked by a member who is not a bot.
    • In all these cases, we are not supposed to send an invite to the user even if they satisfy the room conditions.

      Why?
      • In the first two cases, we want to avoid spamming the users with invites
      • Whereas, in the third and fourth case, we don't want to go against a room admin's/user's wishes and invite the user to the room.
    •  There is actually a simple solution which will handle all the above cases. We can just fetch the full state of the m.room.member state event for all the users who have left the room via the /rooms/{roomId}/members endpoint.
    • With this, we get the sender property. And if the sender is not equal to the bot user_id we can simply ignore the user.

      How does this solve the problem?
      • In the first three cases, the sender key is equal to the state key i.e. user_id.
      • In the fourth case, the sender key can be anyone other than the bot.
        So, if we can ignore users whose sender key in m.room.member state event is not equal to the bot's user_id we can avoid all those 4 scenarios.
        4. Now, that we have the user's current room membership the bot will use the                         methods from github api class and check for the conditions set in the matrix-                        cerberus.rooms.<room_id>.

        5.  If any of the conditions are satisfied the bot will send corresponding invite and                     kick event for the room.
        6.  Steps 4 and 5 are repeated for each user_id and room_id combination.
        7.  After the entire loop finishes executing, the bot puts this task to sleep for a specific              amount of time and then fetches the new updated rooms and users list before                     starting the all over again from 1.

A global app state for backend?

After reviewing PR Feat: external url invites,  Cadair has suggested to use a global app state variable which takes care of maintaining all the global variables like http_client, session_storage, bot_client and so on where it is necessary to maintain a single session for each Class. It is an alternative to using the global variables independently which introduces bugs and makes the code unmaintainable when the amount of code scales up.

So, I ended up refactoring the entire code to support the global_app_state variable such that the session is created during the app startup and stop the session on app shutdown.

I've tried to make sure the core modules are not dependent on other module's global variables thus making them completely independent and are at the top of the tree during imports.

Comments

Popular Posts