Element - From Vision to Architecture

For Element to fulfill its design vision of being a decentralized messaging, VoIP platform, and much more, it has to follow some design principles. Therefore, the creators of Element have created a large specification list where these principles have been implemented. The principles Element follows are 1:

  • Web-friendly APIs
  • Keep It Simple & Stupid: provide a simple architecture with minimal third-party dependencies.
  • Fully open:
    • Fully open federation: Anyone should be able to participate
    • Fully open standard: Fully documented and no intellectual property
    • Fully open-source: Provide open-source reference material
  • Empowering the end-user:
    • The user should be able to choose the server and clients they use
    • The user should be able to control how private their communication is
    • The user should know precisely where their data is stored
  • Fully decentralized: no single point of control over conversations or the network as a whole
  • Learning from history to avoid repeating it
    • Learn from other protocols whilst trying to avoid their failings

To keep to these principles Element has decided on the following overall architecture:

{ Matrix client A }                             { Matrix client B }
        ^          |                                    ^          |
        |  events  |  Client-Server API                 |  events  |
        |          V                                    |          V
    +------------------+                            +------------------+
    |                  |---------( HTTPS )--------->|                  |
    |   homeserver     |                            |   homeserver     |
    |                  |<--------( HTTPS )----------|                  |
    +------------------+      Server-Server API     +------------------+
                          History Synchronisation
                              (Federation)

(source: spec.matrix.org)

Here we see that clients, otherwise known as users, send events, which are JSON objects, to their home server. The home server is the server where the client has decided to host data. To communicate with other clients in the same “room” but with a different home server, data is synchronized using HTTPS requests. With this: “Room data is replicated across all of the home servers whose users are participating in a given room. As such, no single home server has control or ownership over a given room.”2

Containers view

Element’s architecture can be split up into multiple containers. These containers and their implementation can be found on GitHub3. Three main Element repositories can be found here - Web, Android, and iOS. Where the web version serves as both the desktop client as well as the standard browser interface. Furthermore, Element has the ability to communicate with other communication software out there with the use of Matrix Bridges. Keep in mind that this is just an overview of the main software system and does not go into too much depth just yet. For that, consult the later sections of this essay.

The overview of the different containers can be found below. To this end, the c4 model4 has been used to assist in visualization.

Figure: Element’s container view

Components

In the figure below, a components view is shown of the Element web application. This section focuses only on the web application and not on other containers, such as the mobile application.

Figure: Components view of Element Web

The Element web application consists of a few components. These components are all hosted in their Git repository and can be installed as npm packages. The highest level component is the element-web component. element-web is only a skin on top of the matrix-react-sdk component. 3 The matrix-react-sdk component contains most of the user interface components. The matrix-widget-api defines an API for using widgets.

To communicate with a Matrix server, through the Matrix protocol, the matrix-js-sdk is used. The matrix-js-sdk uses an event-based API. 5 The main events are defined in the matrix-events-sdk component and some events are defined in the matrix-analytics-events component. When these events are created, they can be dispatched to the Matrix client/server API of the Matrix server where the Element web application is connected to.

Development view

This section will focus on the Element web application. The element-web repository only functions as a skin for the matrix-react-sdk repository. 6 Therefore, the main focus is on the matrix-react-sdk and matrix-js-sdk repositories. 7

The main dependency for running Element web is Node.js. Other packages that are needed can be installed using the node package manager. To be able to make changes to different repositories at the same time, a local version of the repository can be linked with the element-web component using yarn. 3

The source folder of the matrix-react-sdk repository is divided into modules that each take care of specific functions such as:

  • Notifications
  • Audio
  • Dispatcher
  • Hooks
  • Toasts See the figure below for the layout.

Figure: The file structure of matrix-react-sdk

Furthermore, the matrix-js-sdk repository, on which the matrix-react-sdk depends, also contains multiple modules. The matrix-js-sdk code handles communication between the Element web application and the matrix client/server API. Some of the modules that are present in matrix-js-sdk are:

  • Crypto
  • Store
  • Webrtc

Run-time view

In this section, we will show how the different parts of the code interact with each other in specific scenarios. The scenarios that will be discussed are:

  • Sending a message in a room
  • Receiving a message

When a user sends a message in a room, the client first checks if this room is a room with encryption enabled. If encryption is enabled, it will communicate with matrix-js-sdk to encrypt the contents of the message. This is done through the “crypto” module of matrix-js-sdk. After this is done, an event will be created by matrix-react-sdk, through communication with matrix-js-sdk. There is a small difference between using encryption and not using encryption. This difference is in the creation of events. When a room is encrypted, the event is labeled “RoomMessageEncrypted”, but when it is not it is simply labeled “RoomMessage”. Furthermore, this event contains important data such as:

  • Room id
  • Message content
  • Other things such as callbacks

When the event has been created it will be dispatched from matrix-js-sdk to the server which handles the event. The server then makes sure that each message event is sent to the members of the corresponding room-id. Below is a UML-sequence diagram that displays the process which happens when a user sends a message.

Figure: UML sequence diagram displaying the process that happens when a user sends a message.

Furthermore, clients can also receive messages. Each room member’s client has an event listener. When a message event arrives it handles the event, which is defined in the matrix-react-sdk. When a message event is for an encrypted room the matrix-react-sdk communicates with matrix-js-sdk to decrypt the message through the “crypto” module from matrix-js-sdk. Finally, when all of that has been finished, the message is displayed in the room and the event has been handled.

Quality attributes

The three main quality attributes of Element are security, interoperability, and availability, as discussed in the previous article. How each of these quality attributes is realized will be discussed in this section.

Security To ensure confidentiality and integrity of messages, end-to-end encryption can be used. 8 The matrix-js-sdk provides functionality for encrypting messages. 7 This makes it easy for developers to work with end-to-end encryption, as the implementation is abstracted away. A potential improvement to this design could be to completely abstract encryption away by making it the default. However, this could also make the matrix-js-sdk more difficult to work with.

Interoperability The concept of Matrix bridges ensures interoperability on the container level. A bridge can be a fake user that connects to a Matrix server and to another platform. It then listens for messages from the Matrix server and sends them to the other platform. It can also work the other way around by listening for messages on the other platform and sending them to the Matrix server. 9

Availability Availability is ensured on the container level by the decentralized nature of the Matrix protocol. Everyone can run a server, and connect with other servers to be able to communicate. This makes Element available for everyone. In addition, by introducing multiple matrix servers, Element Web can simply connect to another Matrix server if a specific server fails. 5 The web interface doesn’t need to be hosted on a server. People can also use the mobile or desktop app, which once installed is always available.

API design principles

Since Element is built on Matrix, it makes use of their APIs. Matrix has multiple APIs: Client-Server, Server-Server, Application Service, Identity Service and Push Gateway.10

RESTful API Matrix and therefore also Element adhere to the RESTful API design principles, since Matrix exchanges JSON objects over HTTP(S). The full implementation details can be found on their API specification. 11

Simple & Stupid Matrix aims to achieve a simple yet efficient architecture with minimal third-party dependencies. 10 This is evident by the way the APIs are structured, since each of the APIs have a simple job to perform.

Explicit interface principle The Matrix Client-Server API also contains a Swagger Viewer 10, which makes it adhere to the explicit interface principle, where all possible API calls can be found.

Decentralization This has already been mentioned multiple times, but it is considered to be a good design principle. With the decentralized implementation of Matrix, there are no single points of control in the network or any conversations.

References


  1. Matrix. (n.d.). Matrix Specification Matrix Apis. Spec.Matrix.Org. Retrieved March 11, 2022, from https://spec.matrix.org/latest/#introduction-to-the-matrix-apis ↩︎

  2. Matrix. (n.d.-b). Matrix Specification Matrix Architecture. Spec.Matrix. Retrieved March 11, 2022, from https://spec.matrix.org/unstable/#architecture ↩︎

  3. Vector-IM. (n.d.). GitHub - vector-im/element-web: A glossy Matrix collaboration client for the web. GitHub. Retrieved March 11, 2022, from https://github.com/vector-im/element-web ↩︎

  4. Simon Brown. (n.d.-a). The C4 model for visualising software architecture. Retrieved March 10, 2022, from https://c4model.com/ ↩︎

  5. Parsons, B. (2018, October 18). Dweb: Decentralised, Real-Time, Interoperable Communication with Matrix - Mozilla Hacks - the Web developer blog. Mozilla Hacks – the Web Developer Blog. Retrieved March 11, 2022, from https://hacks.mozilla.org/2018/10/dweb-decentralised-real-time-interoperable-communication-with-matrix/ ↩︎

  6. matrix-org. (n.d.). GitHub - matrix-org/matrix-react-sdk: Matrix SDK for React Javascript. (n.d.). GitHub. Retrieved March 11, 2022, from https://github.com/matrix-org/matrix-react-sdk ↩︎

  7. matrix-org. (n.d.). GitHub - matrix-org/matrix-js-sdk: Matrix Client-Server SDK for JavaScript. GitHub. Retrieved March 11, 2022, from https://github.com/matrix-org/matrix-js-sdk ↩︎

  8. Element. (n.d.). End-to-end encryption (E2EE) | Collaboration and messaging. End-to-End Encryption (E2EE) | Collaboration and Messaging. Retrieved March 11, 2022, from https://element.io/enterprise/end-to-end-encryption ↩︎

  9. Matrix.org. (2022, February 28). How do I bridge thee? Let me count the ways. . . Retrieved March 11, 2022, from https://matrix.org/blog/2017/03/11/how-do-i-bridge-thee-let-me-count-the-ways/ ↩︎

  10. Matrix Specification. (n.d.). Matrix. Retrieved March 2, 2022, from https://spec.matrix.org/ ↩︎

  11. Client-Server API. (n.d.). Matrix Specification. Retrieved March 11, 2022, from https://spec.matrix.org/v1.2/client-server-api/ ↩︎