Skip to content

服務文檔


概述

聊天服務是基於chat協議開發的聊天服務,支持基於房間和事件的加密通信。 同時支持聯邦制的跨服務節點通信,以及基於webrtc的點對點音視頻通話。

跨服務節點的通訊示意

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

基礎概念

Servername(虛擬域名)

servername作為聊天服務的虛擬域名(domain),和用戶的錢包地址共同構成用戶ID

Users(用戶)

每個客戶端關聯一個賬號,用來作為聊天系統的唯一身份識別,即userID。這個賬號與homeserver相關聯形成一個空間分隔化的賬號,形如:

@localpart:domain

Devices(設備)

在聊天系統內定義了一個設備的概念,這個設備可以是一個桌面客戶端,一些瀏覽器,一個安卓設備或者一個iPone等等(目前僅開放安卓設備)。 一個聊天系統的設備就關聯於一個現實中的物理設備或者移動應用。

設備主要應用於管理用於端對端加密的密鑰(每個設備可以得到自己的解密秘鑰拷貝),同時在相同賬號的其它設備進行連接時提供幫助。

當一個用戶第一次使用客戶端的時候,客戶端會把自己註冊為新設備。不同的設備通過設備ID(device_id)進行身份識別,設備ID對於每個用戶是唯一的。 用戶可以給設備定義一個人性化的可讀的設備名稱,用於他們來管理設備。

Events(事件)

所有聊天內的數據交換都是基於event事件進行的。通過事件定義客戶端行為,每個事件都有一個type類型屬性,用來區分數據類型。每個事件類型必須是全局唯一的, 遵循Java命名空間的命名規則,例如m.room.message代表房間內的消息事件。

Event Graphs(事件圖)

房間內的所有事件數據交換被存儲在一個稱作事件圖(Event Graphs)的有向無環圖內。圖中的每個事件按照時間順序排列而成。

通常,一個事件只有一個父事件:發送消息時房間中的最新消息。 但是,家庭服務器(homeserver)在發送消息時可能會合法地相互競爭,從而導致單個事件有多個後繼事件。 因此,添加到圖中的下一個事件將有多個父項。每個事件圖都有一個沒有父事件的根事件。

為了排序和簡化圖中事件之間的時間順序比較,家庭服務器在每個事件上維護一個深度元數據字段。 事件的深度是一個正整數,嚴格大於其任何父事件的深度。 根事件的深度應為 1。因此,如果一個事件在另一個事件之前,則它的深度必須嚴格小於 1。

Room structure(房間結構)

房間是一個概念性的地方,用戶可以在其中發送和接收事件。 事件被發送到一個房間,該房間中具有足夠訪問權限的所有參與者都將收到該事件。 房間通過“房間 ID”在內部唯一標識,具有以下形式:

!room_id:domain  # room_id:一個16位的隨機字符串

每個房間只有一個房間ID。 雖然房間 ID 確實包含域,但它僅用於全局命名空間房間 ID。該房間不在指定的域中。

下面的概念圖顯示了一個 m.room.message 事件被發送到房間 !qporfwt:daodst.com:


    { @alice:daodst.com }                             { @bob:example.org }
            |                                                 ^
            |                                                 |
    [HTTP POST]                                  [HTTP GET]
    Room ID: !qporfwt:daodst.com                 Room ID: !qporfwt:daodst.com
    Event type: m.room.message                   Event type: m.room.message
    Content: { JSON object }                     Content: { JSON object }
            |                                                 |
            V                                                 |
    +------------------+                          +------------------+
    |   homeserver     |                          |   homeserver     |
    |   daodst.com     |                          |   example.org    |
    +------------------+                          +------------------+
            |                                                 ^
            |         [HTTP PUT]                              |
            |         Room ID: !qporfwt:daodst.com            |
            |         Event type: m.room.message              |
            |         Content: { JSON object }                |
            `-------> Pointer to the preceding message  ------`
                      PKI signature from daodst.com
                      Transaction-layer metadata
                      PKI Authorization header

                  ....................................
                 |           Shared Data              |
                 | State:                             |
                 |   Room ID: !qporfwt:daodst.com     |
                 |   Servers: daodst.com, example.org |
                 |   Members:                         |
                 |    - @alice:daodst.com             |
                 |    - @bob:example.org              |
                 | Messages:                          |
                 |   - @alice:daodst.com              |
                 |     Content: { JSON object }       |
                 |....................................|

聯邦機制在多個homeserver之間維護每個房間的共享數據結構。數據分為消息事件和狀態事件。

消息事件:這些描述了房間內的瞬態“一次性”活動,例如即時消息、VoIP 呼叫設置、文件傳輸等。它們通常描述通信活動。

狀態事件:這些描述了對與房間相關的給定持久信息(“狀態”)的更新,例如房間的名稱、主題、成員資格、參與的服務器等。狀態被建模為鍵/值對的查找表 每個房間,每個鍵都是 state_key 和事件類型的元組。每個狀態事件都會更新給定鍵的值。

給定點的房間狀態是通過考慮圖中給定事件之前和包括給定事件的所有事件來計算的。在事件描述相同狀態的情況下,應用合併衝突算法。狀態解析算法是可傳遞的,不依賴於服務器狀態,因為它必須始終選擇相同的事件,而不管服務器或接收事件的順序如何。事件由原始服務器簽名(簽名包括父關係, 類型、深度和有效負載哈希)並通過聯合推送到房間中的參與服務器,目前使用全網狀拓撲。服務器還可以通過聯合從參與房間的其他服務器請求回填事件。

Room Aliases(房間別名)

每個房間也可以有多個“房間別名”,如下所示:

  #room_alias:domain

房間別名“指向”房間 ID,是用於公佈和發現房間的人類可讀標籤。別名指向的房間 ID 可以通過訪問指定的域來獲取。請注意,從房間別名到房間 ID 的映射不是固定的,並且可能會隨著時間的推移而改變以指向不同的房間 ID。因此,客戶端應該將房間別名解析為房間 ID 一次,然後在後續請求中使用該 ID。

解析房間別名時,服務器還將響應房間中可用於加入的服務器列表。

    HTTP GET
    #matrix:example.org      !aaabaa:daodst.com
       |                    ^
       |                    |
    _______V____________________|____
    |          example.org           |
    | Mappings:                      |
    | #matrix >> !aaabaa:daodst.com  |
    | #golf   >> !wfeiofh:sport.com  |
    | #bike   >> !4rguxf:daodst.com  |
    |________________________________|

Identity(身份)

Matrix 中的用戶是通過他們的 Matrix 用戶 ID 來識別的。但是,也可以使用現有的第 3 方 ID 名稱空間來識別 Matrix 用戶。矩陣“身份”描述了用戶 ID 和鏈接到其帳戶的第三方名稱空間中的任何其他現有 ID。 Matrix 用戶可以將電子郵件地址、社交網絡帳戶和電話號碼等第三方 ID (3PID) 鏈接到他們的用戶 ID。鏈接 3PID 會創建從 3PID 到用戶 ID 的映射。 Matrix 用戶隨後可以使用此映射來發現其聯繫人的用戶 ID。為了確保從 3PID 到用戶 ID 的映射是真實的,一個全球聯合的可信“身份服務器”(IS)集群被用來驗證 3PID 並保存和復制映射。

為了使客戶端應用程序成為 Matrix 生態系統的一部分,不需要使用 IS。但是,如果沒有一個客戶端將無法使用 3PID 查找用戶 ID。

Private User Data(用戶隱私數據)

用戶還可以在他們的帳戶中存儲任意私鑰/值數據——例如客戶端首選項或缺少任何其他專用 API 的服務器配置設置。 API 與管理配置文件數據對稱。