Skip to content

客户端-服务器接口


客户端-服务器 API 允许客户端 发送消息,控制房间和同步对话历史记录。是的 旨在支持不存储状态的轻量级客户端和 根据需要从服务器延迟加载数据 - 以及重量级数据 维护服务器状态的完整本地持久副本的客户端。

1.接口标准

Matrix 中客户端-服务器通信的强制基线是 通过 HTTP API 交换 JSON 对象。更高效的运输可能是 将来指定为可选扩展。

建议使用 HTTPS 进行通信。使用纯 HTTP 不是 推荐的外部测试环境。

客户端使用不透明字符串access_token进行身份验证。

所有和端点,除了 POST /_matrix/media/v3/upload 和 PUT /_matrix/media/v3/upload/{serverName}/{mediaId}, 要求客户端提供包含(可能为空)的请求正文POST JSON 对象。客户端应为具有PUT JSON 正文的所有请求提供标头Content-Type application/json,但这不是必需的。

同样,所有端点都要求服务器返回 JSON 对象, 除了对 GET /matrix/media/v200/download/{serverName}/{mediaId} 和 GET / matrix/media/v3/thumbnail/{serverName}/{mediaId} 的 3 个响应。 服务器必须包含所有 JSON 响应的标头。Content-Typeapplication/json

请求或响应中的所有 JSON 数据都必须使用 UTF-8 进行编码。

另请参阅附录中的矩阵 API 约定,了解所有矩阵 API 应遵循的约定, 和下面的 Web 浏览器客户端以获取其他 服务器响应的要求。

1.1 标准错误响应

在矩阵API级别发生的任何错误都必须返回"标准" 错误响应"。这是一个 JSON 对象,如下所示:

{
  "errcode": "<error code>",
  "error": "<error message>"
}

该字符串将是人类可读的错误消息,通常为 解释出了什么问题的句子。error

该字符串将是一个唯一的字符串,可用于处理 错误消息,例如 .错误代码应具有其命名空间 在所有大写字母中首先,然后是单个.例如,如果有自定义 命名空间和代码,错误代码应 肖。由此定义的错误代码 规范应该开始。errcodeM_FORBIDDEN_com.mydomain.hereFORBIDDENCOM.MYDOMAIN.HERE_FORBIDDENM_

一些定义了错误中应该存在的其他键 响应对象,但键和必须始终存在。errcodeerrorerrcode

错误通常最好由其错误代码表示,而不是 返回的 HTTP 状态代码。遇到错误码时, 客户端应首选 HTTP 状态代码作为更可靠的参考 问题是什么。例如,如果客户端收到错误 的代码,但请求给出了 400 错误请求状态 代码,客户端应将错误视为资源不是 发现。但是,如果客户端收到错误代码 400 错误请求,则客户端应假定 请求无效。M_UNKNOWNM_NOT_FOUNDM_UNKNOWN

1.1.1 常见错误

任何 API 端点都可以返回这些错误代码:

M_FORBIDDEN禁止访问,例如未经许可加入房间,登录失败。

M_UNKNOWN_TOKEN无法识别指定的访问或刷新令牌。

其他响应参数 上可能存在 响应 401 HTTP 状态代码。查看软注销 部分了解更多信息。soft_logout

M_MISSING_TOKEN没有为请求指定访问令牌。

M_BAD_JSON请求包含有效的 JSON,但格式以某种方式不正确,例如 缺少必需的键,键的值无效。

M_NOT_JSON请求不包含有效的 JSON。

M_NOT_FOUND找不到此请求的资源。

M_LIMIT_EXCEEDED在短时间内发送了太多请求。稍等片刻 然后重试。

M_UNRECOGNIZED服务器无法理解该请求。预计这将返回 404 HTTP 状态代码(如果终结点未实现)或 405 HTTP 状态 代码(如果终结点已实现,但使用了不正确的 HTTP 方法)。

M_UNKNOWN发生未知错误。

1.1.2 其他错误代码

以下错误代码特定于某些终结点。

M_UNAUTHORIZED请求未正确授权。通常是由于登录失败。

M_USER_DEACTIVATED与请求关联的用户标识已被停用。通常 对于证明身份验证的终结点,例如 。/login

M_USER_IN_USE尝试注册已占用的用户 ID 时遇到此问题。

M_INVALID_USERNAME尝试注册无效的用户 ID 时遇到。

M_ROOM_IN_USE当提供给 API 的房间别名已在 中时发送 用。createRoom

M_INVALID_ROOM_STATE当提供给 API 的初始状态无效时发送。createRoom

M_THREEPID_IN_USE当提供给 API 的三pid 无法使用时发送,因为相同 三PID已经在使用中。

M_THREEPID_NOT_FOUND当提供给 API 的三 pid 由于没有记录而无法使用时发送 找到了匹配的三皮。

M_THREEPID_AUTH_FAILED无法对第三方标识符执行身份验证。

M_THREEPID_DENIED服务器不允许使用此第三方标识符。这可能会发生 例如,如果服务器只允许来自 特定域。

M_SERVER_NOT_TRUSTED客户端的请求使用了第三方服务器,例如身份服务器, 此服务器不信任。

M_UNSUPPORTED_ROOM_VERSION客户端创建房间的请求使用了 服务器不支持。

M_INCOMPATIBLE_ROOM_VERSION客户端尝试加入具有服务器版本的文件室 不支持。检查错误响应的属性 对于房间的版本。room_version

M_BAD_STATE无法执行请求的状态更改,例如尝试 取消禁止未被禁止的用户。

M_GUEST_ACCESS_FORBIDDEN客房或资源不允许客人访问。

M_CAPTCHA_NEEDED需要验证码才能完成请求。

M_CAPTCHA_INVALID提供的验证码与预期不符。

M_MISSING_PARAM请求中缺少必需参数。

M_INVALID_PARAM指定的参数具有错误的值。例如, 服务器需要一个整数,而是收到一个字符串。

M_TOO_LARGE请求或实体太大。

M_EXCLUSIVE请求的资源由应用程序服务保留,或者 发出请求的应用程序服务尚未创建资源。

M_RESOURCE_LIMIT_EXCEEDED无法完成请求,因为主服务器已达到 对其施加的资源限制。例如,共享中保存的家庭服务器 如果托管环境也开始使用,则可能会达到资源限制 大量内存或磁盘空间。错误必须有一个字段 为收到错误的用户提供一个可以联系的地方。 通常,此错误将出现在尝试修改的路由上 状态(例如:发送消息,帐户数据等)而不是路由 仅读取状态(例如:,获取帐户数据等)。admin_contact/sync

M_CANNOT_LEAVE_SERVER_NOTICE_ROOM用户无法拒绝加入服务器通知室的邀请。 有关详细信息,请参阅服务器通知模块。

1.2 交易标识符

客户端-服务器 API 通常用于提交请求 HTTP 路径中客户端生成的事务标识符。HTTP PUT

事务 ID 的目的是允许主服务器区分 来自先前请求的重新传输的新请求,以便它可以发出 请求幂等。

交易 ID 只能用于此目的。

从客户端的角度来看,在请求完成后,应为下一个请求更改值(未指定 how;a 建议单调递增整数)。{txnId}

如果 事务 ID 与上一个请求相同,并且 HTTP 请求是相同的。

如果已识别出重传,则主服务器应返回 与原始请求相同的 HTTP 响应代码和内容。 例如,将返回一个 与原始请求 响应正文。PUT /_ matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}200 OKevent_id

除了 HTTP 路径,事务 ID 的作用域是"客户端" 会话",其中该会话由特定访问令牌标识。 刷新访问令牌时, 保留事务 ID 的范围。这意味着如果客户端 令牌用作其事务 ID,将令牌刷新为 ,并再次使用它,这将被假定为重复请求 并被忽略。如果客户端注销并在 和 令牌之间重新注销,则可以为每个令牌使用一次。ATXN1BTXN1ABTXN1

某些 API 端点可能允许或要求使用请求 没有交易 ID。如果这是可选的,强烈建议使用请求。POSTPUT

2.网页浏览器客户端

期望某些客户端将被写入以运行是现实的 在 Web 浏览器或类似环境中。在这些情况下, 主服务器应响应飞行前请求并提供跨源 所有请求上的资源共享 (CORS) 标头。

服务器必须期望客户端会通过请求接近它们,从而允许客户端发现 CORS 标头。所有端点 在此规范中支持该方法,但是服务器 在接近端点时,不得执行为端点定义的任何逻辑 与请求。OPTIONSOPTIONSOPTIONS

当客户端向服务器发出请求时,服务器应 使用该路由的 CORS 标头进行响应。推荐的可替代资源保护计划 服务器在所有请求上返回的标头包括:

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
    Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization

3.服务器发现

为了允许用户连接到矩阵服务器而无需 显式指定主服务器的 URL 或其他参数,客户端 应使用自动发现机制来确定服务器的 URL 基于用户的矩阵 ID。自动发现只能在登录时完成 时间。

在本节中,以下术语具有特定含义:

PROMPT从用户那里检索特定信息的方式 适合现有的客户端用户体验(如果客户端是 倾向于这样做。如果没有好的用户,则可能会发生故障 在这一点上,这方面的经验是可能的。

IGNORE停止当前的自动发现机制。如果没有更多的自动发现 机制是可用的,那么客户端可以使用其他方法 确定所需的参数,例如提示用户,或 使用默认值。

FAIL_PROMPT通知用户自动发现由于数据无效/空和参数而失败。PROMPT

FAIL_ERROR通知用户自动发现未返回任何可用的 URL。做 不要继续当前登录过程。此时, 已获取有效数据,但没有服务器可用于为客户端提供服务。 不应尝试进一步猜测,用户应进行 认真决定下一步该做什么。

3.1 Well-known URI

该方法使用预定位置的 JSON 文件来 指定参数值。此方法的流程如下:.well-known

  1. 通过拆分 第一个冒号处的矩阵 ID。
  2. 从服务器名称中提取主机名。
  3. 向 发出 GET 请求。https://hostname/.well-known/matrix/client
    1. 如果返回的状态代码为 404,则 .IGNORE
    2. 如果返回的状态代码不是 200,或者响应正文为 空的,然后.FAIL_PROMPT
    3. 将响应正文解析为 JSON 对象
      1. 如果无法解析内容,则 .FAIL_PROMPT
    4. 从属性中提取值。 此值将用作主服务器的基本 URL。base_urlm.homeserver
      1. 如果未提供此值,则 .FAIL_PROMPT
    5. 验证主服务器基本 URL:
      1. 将其解析为 URL。如果它不是 URL,则 .FAIL_ERROR
      2. 客户端应验证 URL 是否指向有效的 主服务器 在接受它之前,通过连接到 /_matrix/客户端/版本端点,确保它 不返回错误,并解析和验证 数据符合预期的响应格式。如果有任何步骤 在验证失败时,.验证是 作为针对配置错误的简单检查完成,在 以确保发现的地址指向 有效的主服务器。FAIL_ERROR
      3. 请务必注意,该值可能包括 尾随 .消费者应准备好处理这两种情况。base_url/
    6. 如果该属性存在,请提取值以用作身份服务器的基本 URL。 此 URL 的验证按上述步骤完成,但用作要连接到的终结点。如果该属性存在,但没有值,则 .m.identity_serverbase_url/_ matrix/identity/v2m.identity_serverbase_urlFAIL_PROMPT

GET /.well-known/matrix/client

获取有关域的发现信息。该文件可能包括 附加键,必须遵循 Java 包命名约定, 例如.这可确保属性名称 为每个应用程序适当地命名,并降低 冲突。com.example.myapp.property

请注意,此终结点不一定由主服务器处理, 但由另一个网络服务器使用,用于发现主服务器 URL。

响应示例:

    {
  "m.homeserver": {
    "base_url": "https://daodst.example.com"
  },
  "m.identity_server": {
    "base_url": "https://identity.example.com"
  },
  "org.example.custom.property": {
    "app_url": "https://custom.app.example.org"
  }
}

GET /_matrix/client/versions

获取服务器支持的规范版本。

值将采用形式或历史案例。有关详细信息,请参阅规范版本控制 信息。vX.YrX.Y.Z

服务器可能会额外公布其支持的实验性功能 通过。这些功能应具有命名空间,并且 如果需要,可以选择在其名称中包含版本信息。 此处列出的功能不适用于选择性切换矩阵的各个部分 规范,应仅用于播发对功能的支持 尚未进入规范。例如,当前功能。 正在进行提案流程可能会出现在这里并最终被采纳 一旦功能进入规范并且服务器认为它,就脱离此列表 这样做是合理的。服务器可能希望在此处保留广告功能 在它们被发布到规范中后,让客户有机会 适当升级。此外,客户端应避免使用不稳定 稳定版本中的功能。unstable_features

响应示例:

    {
  "unstable_features": {
    "org.example.my_feature": true
  },
  "versions": [
    "r0.0.1",
    "v1.1"
  ]
}

4. 客户端身份验证

大多数 API 端点要求用户通过呈现来标识自己 以前以查询形式获得的凭据 access_token参数或通过授权标头 Bearer $access_token。 访问令牌通常通过登录或注册过程获取。访问令牌 可以过期;可以使用刷新令牌生成新的访问令牌。

4.1 使用访问令牌

访问令牌可以通过两种方式提供,这两种方式都是主服务器 必须支持:

1. 通过查询字符串参数 .access_token=TheTokenHere 
2. 通过请求标头 .Authorization: Bearer TheTokenHere

鼓励客户尽可能使用标头 以防止访问令牌在访问/HTTP 日志中泄露。查询 字符串应仅在标头为 客户端无法访问。AuthorizationAuthorization

当凭据需要但缺失或无效时,HTTP 调用将 返回状态为 401 和错误代码,或分别返回。请注意,错误代码 可能意味着以下四种情况之一:M_MISSING_TOKENM_UNKNOWN_TOKENM_UNKNOWN_TOKEN

1. 访问令牌从未有效。
2. 访问令牌已注销。
3. 访问令牌已软注销。
4. [在 v1.3 中添加] 访问令牌需要刷新。

当客户端收到错误代码 时,它应该:M_UNKNOWN_TOKEN

  • 尝试刷新令牌(如果它有刷新) 令 牌;
  • 如果soft_logout设置为 ,它可以提供 重新登录用户,保留任何客户端的持久 信息;true
  • 否则,将用户视为已注销。

4.2 访问令牌和设备之间的关系

客户端设备与访问密切相关 令牌和刷新令牌。矩阵服务器应记录哪个设备 每个访问令牌和刷新令牌都分配给,以便 可以正确处理后续请求。当刷新令牌为 用于生成新的访问令牌和刷新令牌,即新的访问 和刷新令牌现在绑定到与 初始刷新令牌。

默认情况下,登录和注册过程自动生成新的 .客户也可以自由 生成自己的,或者,前提是用户保持不变, 重用设备:无论哪种情况,客户端都应传递 请求正文。如果客户端设置 ,服务器将 使以前分配给该设备的任何访问和刷新令牌无效。device_iddevice_iddevice_iddevice_id

4.3 刷新访问令牌

访问令牌可能会在一定时间后过期。任何 HTTP 调用 使用过期的访问令牌将返回错误代码, 最好带 .当客户端收到此错误并且 具有刷新令牌,它应尝试通过调用 /refresh 来刷新访问令牌。客户还可以刷新他们的 随时访问令牌,即使它尚未过期。如果令牌刷新 成功后,客户端应将新令牌用于将来的请求,并且可以 使用新令牌重试以前失败的请求。当访问令牌 刷新后,可能会返回新的刷新令牌;如果新的刷新令牌是 给定,旧的刷新令牌将失效,而新的刷新令牌将失效 应在需要刷新访问令牌时使用。M_UNKNOWN_TOKENsoft_logout: true

旧的刷新令牌在新的访问令牌或刷新令牌之前一直有效 ,此时将吊销旧的刷新令牌。这可确保如果 客户端无法接收或保留新令牌,它将能够重复 刷新操作。

如果令牌刷新失败并且错误响应包含属性,则客户端可以将其视为软注销,并尝试通过重新登录来获取新的访问令牌。如果错误 响应不包含属性,客户端应 将用户视为已注销。soft_logout: truesoft_logout: true

不支持刷新令牌的客户端的处理由主服务器决定; 客户端通过在 /login 和 /register 终结点的请求正文中包含属性来指示其对刷新令牌的支持。例如,家庭服务器 可能允许使用未过期的访问令牌,或者可能使访问令牌过期 无论如何,并依赖于不支持的客户端上的软注销行为 刷新。refresh_token: true

4.4 软注销

如果服务器需要,客户端可以处于"软注销"状态 在继续之前重新进行身份验证,但不希望使 客户端会话。服务器指示客户端处于软注销状态 通过在错误响应中包含参数来状态;参数默认为 。如果参数被省略或为 ,这意味着服务器具有 已销毁会话,客户端不应重用它。也就是说,任何 客户端持有的持久状态,例如加密密钥和设备 信息,不得重复使用,必须丢弃。如果是,客户端可以重用任何持久状态。soft_logout: trueM_UNKNOWN_TOKENsoft_logoutfalsesoft_logoutfalsesoft_logouttrue

[在 v1.3 中更改]

收到此类响应的客户端可以尝试刷新其访问令牌(如果它有刷新) 令牌可用。如果没有可用的刷新令牌,或者正在刷新 失败,客户端可以通过 指定它已用于登录 API 的设备 ID。soft_logout: true

4.5 用户交互式身份验证 API

4.5.1 概述

某些 API 端点需要与用户交互的身份验证。 主服务器可以提供许多不同的身份验证方式,例如 作为用户/密码身份验证,通过单点登录服务器 (SSO) 登录等。 此规范未定义主服务器应如何授权 他们的用户,而是定义了标准接口 应遵循实现,以便任何客户端都可以登录到任何 主服务器。

该过程采取一个或多个"阶段"的形式。在每个阶段 客户端为给定的身份验证类型提交一组数据并等待 来自服务器的响应,这将是最终成功或 请求执行其他阶段。这种交换一直持续到 最后的成功。

对于每个端点,服务器提供一个或多个客户端的"流" 可用于对自身进行身份验证。每个流程包括一系列阶段, 如上所述。客户端可以自由选择它遵循的流程, 但是,流的各个阶段必须按顺序完成。未能遵循 按顺序排列的流必须产生 HTTP 401 响应,如定义 下面。当流中的所有阶段都完成后,身份验证是 完成,API 调用成功。

4.5.2 REST API 中的用户交互式 API

在本规范中描述的 REST API 中,身份验证的工作方式为 交换 JSON 字典的客户端和服务器。服务器指示 通过 HTTP 401 正文需要哪些身份验证数据 响应,客户端通过请求参数提交该身份验证数据。auth

客户端应首先发出不带参数的请求。 主服务器返回带有 JSON 正文的 HTTP 401 响应,如下所示:auth

HTTP/1.1 401 Unauthorized
Content-Type: application/json
    {
  "flows": [
    {
      "stages": [
        "example.type.foo",
        "example.type.bar"
      ]
    },
    {
      "stages": [
        "example.type.foo",
        "example.type.baz"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxx"
}

除了 之外,此对象还包含一些额外的信息:flows

  • params:此部分包含客户端将要提供的任何信息 需要知道才能使用给定类型的身份验证。对于每个 提供的身份验证类型,该类型可能在此类型中作为密钥存在 字典。例如,OAuth 客户端 ID 的公共部分可以是 在这里给出。
  • session:这是客户端必须传回的会话标识符 到主服务器(如果提供了),在随后的身份验证尝试中 在同一个 API 调用中。

然后,客户端选择一个流并尝试完成第一阶段。 它通过重新提交相同的请求并在提交的对象中添加密钥来实现此目的。此字典包含一个键,其值是身份验证类型的名称,该 客户端正在尝试完成。它还必须包含一个密钥 使用主服务器给出的会话密钥的值(如果 鉴于。它还包含依赖于身份验证类型的其他键 企图。例如,如果客户端正在尝试完成身份验证 键入 ,它可能会提交如下内容:authtypesessionexample.type.foo

POST /_matrix/client/v3/endpoint HTTP/1.1
Content-Type: application/json
{
  "a_request_parameter": "something",
  "another_request_parameter": "something else",
  "auth": {
    "type": "example.type.foo",
    "session": "xxxxxx",
    "example_credential": "verypoorsharedsecret"
  }
}

如果主服务器认为身份验证尝试成功,但 仍然需要更多阶段才能完成,它返回HTTP状态401 以及与未尝试身份验证时相同的对象, 添加密钥,该密钥是身份验证类型的数组 客户端已成功完成:completed

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo",
        "example.type.bar"
      ]
    },
    {
      "stages": [
        "example.type.foo",
        "example.type.baz"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxx"
}

各个阶段可能需要多个请求才能完成,在 在这种情况下,响应将好像请求未经身份验证 添加由身份验证类型定义的任何其他密钥。

如果主服务器确定某个阶段的尝试不成功, 但客户端可能会进行第二次尝试,它返回相同的 HTTP 状态 401 响应如上所述,并添加了描述错误的标准和字段。例如:errcodeerror

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "errcode": "M_FORBIDDEN",
  "error": "Invalid password",
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo",
        "example.type.bar"
      ]
    },
    {
      "stages": [
        "example.type.foo",
        "example.type.baz"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxx"
}

如果请求由于身份验证以外的原因而失败,则服务器 返回标准格式的错误消息。例如:

HTTP/1.1 400 Bad request
Content-Type: application/json
{
  "errcode": "M_EXAMPLE_ERROR",
  "error": "Something was wrong"
}

如果客户端已完成流的所有阶段,则主服务器 执行 API 调用并正常返回结果。已完成的阶段 客户端无法重试,因此服务器必须返回 401 包含已完成阶段的响应,或 API 调用的结果(如果全部) 当客户端重试阶段时,阶段已完成。

某些身份验证类型可以通过 矩阵客户端,例如,可以完成电子邮件确认 当用户单击电子邮件中的链接时。在这种情况下,客户端 使用仅包含会话密钥的身份验证字典重试请求。 对此的响应将与客户端尝试相同 正常完成身份验证状态,即请求将 完成或请求身份验证,是否存在该身份验证类型 在"已完成"数组中指示该阶段是否完成。

4.5.3 例

在高级别上,对 API 调用发出的请求完成身份验证 具有三个阶段的流将类似于下图:

    _______________________
    |       Stage 0         |
    | No auth               |
    |  ___________________  |
    | |_Request_1_________| | <-- Returns "session" key which is used throughout.
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 1         |
    | type: "<auth type1>"  |
    |  ___________________  |
    | |_Request_1_________| |
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 2         |
    | type: "<auth type2>"  |
    |  ___________________  |
    | |_Request_1_________| |
    |  ___________________  |
    | |_Request_2_________| |
    |  ___________________  |
    | |_Request_3_________| |
    |_______________________|
             |
             |
    _________V_____________
    |       Stage 3         |
    | type: "<auth type3>"  |
    |  ___________________  |
    | |_Request_1_________| | <-- Returns API response
    |_______________________|

4.5.4 身份验证类型

此规范定义了以下身份验证类型:

  • m.login.password
  • m.login.recaptcha
  • m.login.sso
  • m.login.email.identity
  • m.login.msisdn
  • m.login.dummy
  • m.login.registration_token

4.5.5 后备

不能期望客户能够知道如何处理每个 单一登录类型。如果客户端不知道如何处理给定的登录 类型,它可以将用户定向到具有回退 URL 的 Web 浏览器 页面,允许用户在带外完成该登录步骤 在他们的网络浏览器中。它应该打开的 URL 是:

/_matrix/client/v3/auth/<auth type>/fallback/web?session=<session ID>

其中 是它正在尝试的阶段的类型名称,是主服务器提供的会话的 ID。auth typesession ID

这必须返回可以执行此身份验证的 HTML 页面 阶段。此页面必须使用以下 JavaScript 在 身份验证已完成:

if (window.onAuthDone) {
    window.onAuthDone();
} else if (window.opener && window.opener.postMessage) {
    window.opener.postMessage("authDone", "*");
}

这允许客户端安排在嵌入式浏览器中定义全局函数,或使用HTML5跨文档 消息传递 API, 到 接收身份验证阶段已完成的通知。onAuthDone

客户端收到身份验证阶段的通知后 已完成,它应该使用身份验证字典重新提交请求 仅使用会话 ID:

{
  "session": "<session ID>"
}

4.5.6 标识符类型

某些身份验证机制使用用户标识符对象来标识 一个用户。用户标识符对象有一个字段来指示 正在使用的标识符类型,并且根据类型,具有其他 提供标识用户所需信息的字段,如所述 下面。type

此规范定义了以下标识符类型:

  • m.id.user
  • m.id.thirdparty
  • m.id.phone

4.6 登录

客户端可以使用 API 获取访问令牌。/login

请注意,此终结点当前不使用用户交互式身份验证 原料药。

对于简单的用户名/密码登录,客户端应提交请求,如下所示:/login

{
  "type": "m.login.password",
  "identifier": {
    "type": "m.id.user",
    "user": "<user_id or user localpart>"
  },
  "password": "<password>"
}

或者,客户端可以使用绑定到用户帐户的 3PID 主服务器使用 /account/3pid API 而不是显式提供,如下所示:user

{
  "type": "m.login.password",
  "identifier": {
    "medium": "<The medium of the third-party identifier>",
    "address": "<The canonicalised third-party address of the user>"
  },
  "password": "<password>"
}

如果主服务器不知道提供的 3PID, 主服务器必须响应 。403 Forbidden

要使用登录令牌登录,客户端应提交请求 如下:/login

{
"type": "m.login.token",
"token": "<login token>"
}

必须对用户 ID 进行编码,因为没有其他标识 请求中的数据。在令牌无效的情况下,主服务器必须 响应 和错误代码 。token403 ForbiddenM_FORBIDDEN

如果主服务器播发为可行的流,并且 客户端支持它,客户端应将用户重定向到端点,以便通过 SSO 登录客户端。身份验证后 完成后,客户端将需要提交匹配的请求。m.login.sso/redirect/loginm.login.token

GET /_matrix/client/v3/login

获取主服务器支持的登录类型以对用户进行身份验证。客户 应该选择其中之一并在登录时提供它。type

{
  "flows": [
    {
      "type": "m.login.password"
    }
  ]
}

POST /_matrix/client/v3/login

对用户进行身份验证,并颁发他们可以的访问令牌 用于在后续请求中授权自己。

如果客户端未提供 ,则服务器必须 自动生成一个。device_id

返回的访问令牌必须与客户端提供的或由服务器生成的相关联。服务器可能 使以前与该设备关联的任何访问令牌无效。请参阅访问令牌和设备之间的关系。device_id

{
  "identifier": {
    "type": "m.id.user",
    "user": "cheeky_monkey"
  },
  "initial_device_display_name": "Jungle Phone",
  "password": "ilovebananas",
  "type": "m.login.password"
}
{
  "access_token": "abc123",
  "device_id": "GHTYAJCE",
  "expires_in_ms": 60000,
  "refresh_token": "def456",
  "user_id": "@cheeky_monkey:matrix.org",
  "well_known": {
    "m.homeserver": {
      "base_url": "https://example.org"
    },
    "m.identity_server": {
      "base_url": "https://id.example.org"
    }
  }
}

POST /_matrix/client/v3/refresh

v1.3 中新增

刷新访问令牌。客户端应使用返回的访问令牌 进行后续 API 调用时,并存储返回的刷新令牌 (如果给定),以便在必要时刷新新的访问令牌。

刷新访问令牌后,服务器可以选择 使旧访问令牌立即失效,也可以选择不使旧访问令牌失效 例如,访问令牌是否很快就会过期。客户应该 不对旧访问令牌仍然有效做出任何假设, 并应改用新提供的访问令牌。

旧的刷新令牌在新的访问令牌或刷新令牌之前一直有效 ,此时将吊销旧的刷新令牌。

请注意,此端点不需要通过 访问令牌。身份验证通过刷新令牌提供。

已为此终结点禁用应用程序服务标识断言。


{
  "refresh_token": "some_token"
}
{
  "access_token": "a_new_token",
  "expires_in_ms": 60000,
  "refresh_token": "another_new_token"
}

POST /_matrix/client/v3/logout

使现有访问令牌失效,使其不能再用于 授权。与访问令牌关联的设备也将被删除。设备的设备密钥将与设备一起删除。

{}

POST /_matrix/client/v3/logout/all

使用户的所有访问令牌失效,以便它们不能再用于 授权。这包括发出此请求的访问令牌。所有设备 对于用户也将被删除。设备的设备密钥为 与设备一起删除。

此终结点不使用用户交互式身份验证 API,因为 用户交互式身份验证旨在防止以下攻击:有人掌握了一个访问令牌,然后接管了该帐户。这 终结点使用户的所有访问令牌失效,包括 请求,因此攻击者无法接管帐户 这边。

{}

4.7 帐户注册和管理

POST /_matrix/client/v3/account/deactivate

停用用户帐户,删除用户的所有能力 再次登录。

此 API 终结点使用用户交互式身份验证 API。

如果客户端具有 活动会话。

主服务器可能会更改可用的流,具体取决于 提供了有效的访问令牌。

与其他端点不同,此端点不采用参数,因为主服务器应将请求签名到 而是标识服务器。id_access_token

req

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "id_server": "example.org"
}
200

{
  "id_server_unbind_result": "success"
}
401

{
  "completed": [
    "example.type.foo"
  ],
  "flows": [
    {
      "stages": [
        "example.type.foo"
      ]
    }
  ],
  "params": {
    "example.type.baz": {
      "example_key": "foobar"
    }
  },
  "session": "xxxxxxyz"
}
429

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "Too many requests",
  "retry_after_ms": 2000
}

POST /_matrix/client/v3/account/password

更改此主服务器上帐户的密码。

此 API 端点使用用户交互式身份验证 API 来 确保更改密码的用户实际上是 帐户。

如果客户端具有 活动会话。

主服务器可能会更改可用的流,具体取决于 提供了有效的访问令牌。主服务器不应撤销 请求中提供的访问令牌。是否为其他访问令牌 吊销的用户取决于请求参数。

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "logout_devices": true,
  "new_password": "ihatebananas"
}
{}

POST /_matrix/client/v3/account/password/email/requestToken

主服务器必须检查给定的电子邮件地址是否为 与此主服务器上的帐户关联。此接口应为 用于在对终结点进行身份验证时请求验证令牌。/account/password

此 API 的参数和响应与 /register/email/requestToken 端点的参数和响应相同,只是如果没有与 可以找到给定的电子邮件地址。服务器可能会发送 向给定地址发送电子邮件,提示用户创建帐户。 可能无法退货。M_THREEPID_NOT_FOUNDM_THREEPID_IN_USE

主服务器应验证电子邮件本身,方法是发送 验证电子邮件本身或使用它可以控制的服务。

{
  "client_secret": "monkeys_are_GREAT",
  "email": "alice@example.org",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "send_attempt": 1
}
{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

POST /_matrix/client/v3/account/password/msisdn/requestToken

主服务器必须检查给定的电话号码是否为 与此主服务器上的帐户关联。此接口应为 用于在对终结点进行身份验证时请求验证令牌。/account/password

此 API 的参数和响应与 /register/msisdn/requestToken 终结点的参数和响应相同,只是如果没有与 可以找到给定的电话号码。服务器可能会改为发送短信 到提示用户创建帐户的给定电话号码。 可能无法退货。M_THREEPID_NOT_FOUNDM_THREEPID_IN_USE

主服务器应验证电话号码本身,方法是发送 验证消息本身或通过使用它可以控制的服务。

{
  "client_secret": "monkeys_are_GREAT",
  "country": "GB",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "phone_number": "07700900001",
  "send_attempt": 1
}
{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

POST /_matrix/client/v3/register

此 API 終結點使用使用者互動式身份驗證 API,但 正在註冊來賓帳戶的情況。

在此主伺服器上註冊一個帳戶。

有兩種類型的使用者帳戶:

  • user帳戶。這些帳戶可以使用本規範中描述的完整 API。
  • guest帳戶。這些帳戶可能具有有限的許可權,並且可能並非受所有伺服器支援

如果註冊成功,此終結點將頒發訪問令牌 用戶端可以使用 在後續請求中授權自身。

如果客戶端未提供 ,則伺服器必須 自動生成一個。device_id

伺服器應根據提供的使用者 ID 註冊一個帳戶(如果有)。請注意,矩陣使用者ID的語法 localparts 受到限制,因此伺服器必須以邏輯方式將提供的映射到 上,或者拒絕任何不符合語法的內容。usernameusernameuser_idusernameM_INVALID_USERNAME

矩陣用戶端不得假定註冊的本地部分與提供的 .user_idusername

返回的訪問令牌必須與用戶端提供的或由伺服器生成的相關聯。伺服器可能 使以前與該設備關聯的任何訪問令牌無效。請參閱訪問令牌和設備之間的關係。device_id

註冊來賓帳戶時,請求正文中的所有參數 必須忽略除外 由伺服器。伺服器必須為帳戶選擇一個 無論輸入如何。initial_device_display_namedevice_id

請求正文示例

{
  "auth": {
    "example_credential": "verypoorsharedsecret",
    "session": "xxxxx",
    "type": "example.type.foo"
  },
  "device_id": "GHTYAJCE",
  "initial_device_display_name": "Jungle Phone",
  "password": "ilovebananas",
  "username": "cheeky_monkey"
}

200 回應

{
  "access_token": "abc123",
  "device_id": "GHTYAJCE",
  "user_id": "@cheeky_monkey:matrix.org"
}

GET /_matrix/client/v3/register/available

檢查使用者名是否可用於伺服器且有效。

伺服器應檢查以確保在請求時 請求的使用者名可供使用。這包括驗證 應用程式服務尚未聲明使用者名,並且該使用者名 符合伺服器的所需要求(例如,伺服器可以指示 它不允許帶下劃線的使用者名)。

矩陣用戶端可能希望在嘗試註冊之前使用此 API, 但是,客戶端還必須注意,通常不會使用此 API 保留使用者名。這可能意味著使用者名變得不可用 在檢查其可用性和嘗試註冊它之間。

200 回應

{
  "available": true
}

400 回應

{
  "errcode": "M_USER_IN_USE",
  "error": "Desired user ID is already taken."
}

POST /_matrix/client/v3/register/email/requestToken

主伺服器必須檢查給定的電子郵件位址是否尚未與此主伺服器上的帳戶關聯。主伺服器 應通過發送驗證電子郵件來驗證電子郵件本身 本身或通過使用它可以控制的服務。

請求正文示例

{
  "client_secret": "monkeys_are_GREAT",
  "email": "alice@example.org",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "send_attempt": 1
}

200 回應

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

POST /_matrix/client/v3/register/msisdn/requestToken

主伺服器必須檢查給定的電話號碼是否尚未與此主伺服器上的帳戶關聯。主伺服器 應通過發送驗證來驗證電話號碼本身 消息本身或通過使用它可以控制的服務。

請求正文示例

{
  "client_secret": "monkeys_are_GREAT",
  "country": "GB",
  "id_server": "id.example.com",
  "next_link": "https://example.org/congratulations.html",
  "phone_number": "07700900001",
  "send_attempt": 1
}

200 回應

{
  "sid": "123abc",
  "submit_url": "https://example.org/path/to/submitToken"
}

4.8 添加帳戶管理聯繫資訊

POST /_matrix/client/v3/account/3pid/unbind

從提供的身份伺服器中刪除使用者的第三方標識碼 無需將其從主伺服器中刪除。

與其他端點不同,此端點不採用參數,因為主伺服器應將請求簽名到 而是標識伺服器。id_access_token

請求正文示例

{
  "address": "example@example.org",
  "id_server": "example.org",
  "medium": "email"
}

200 回應

{
  "id_server_unbind_result": "success"
}

4.9 往來帳戶資訊

GET /_matrix/client/v3/account/whoami

獲取有關給定訪問令牌的所有者的資訊。

請注意,與客戶端-伺服器 API 的其餘部分一樣, 應用程式服務可能會偽裝成其使用者 命名空間,通過提供查詢參數。在此 在這種情況下,伺服器應驗證給定的是否由應用服務註冊,並在回應中返回 body。user_iduser_id

200 回應

{
  "device_id": "ABC1234",
  "user_id": "@joe:example.org"
}

4.9.1 有關身份伺服器的說明

Matrix 中的識別伺服器儲存綁定(關係) 使用者的第三方標識碼,通常是電子郵件或電話號碼,以及 他們的使用者ID。用戶選擇身份伺服器后,該身份 伺服器應由所有用戶端使用。

用戶端可以通過帳戶數據事件查看用戶選擇了哪個身份伺服器,如下所述。客戶 應避免向任何身份伺服器發出請求,直到 的存在被確認為(不存在)。如果 存在,用戶端應檢查事件內容中是否存在屬性。如果存在,則 用戶端應使用該屬性中的標識伺服器作為標識 用戶的伺服器。如果缺少,或者帳戶數據 事件不存在,客戶端應使用任何預設值 通常適用於身份伺服器(如果適用)。客戶不應 當使用者使用預設身份伺服器更新帳戶數據時 其帳戶數據中缺少身份伺服器。m.identity_serverm.identity_serverbase_urlbase_urlbase_url

客戶應偵聽帳戶的更改 數據事件,並更新他們正在聯繫的身份伺服器 結果。m.identity_server

如果用戶端提供了一種設置要使用的身份伺服器的方法,則必須 相應地更新的值。A 的 MUST 被視為使用者不想使用 身份伺服器,因此禁用所有相關功能。m.identity_serverbase_urlnull

客戶應避免將帳戶數據作為遷移進行填充 針對缺少帳戶數據的使用者的步驟,除非用戶設置 用戶端內的身份伺服器為值。例如,使用者 沒有帳戶數據事件不應最終 在帳戶數據中使用客戶端的預設身份伺服器,除非 使用者首先訪問其帳戶設置以設置身份伺服器。m.identity_server

例子

{
  "content": {
    "base_url": "https://example.org"
  },
  "type": "m.identity_server"
}

5. 能力協商

主伺服器可能不支援某些操作,客戶端必須能夠 查詢主伺服器可以提供和不能提供的內容。例如,一個 家庭伺服器可能不支援使用者按原樣更改其密碼 配置為對外部系統執行身份驗證。

通過此系統宣傳的功能旨在 通告在 API 中可選的功能,或者依賴於 使用者或伺服器狀態的某種方式。這個系統不應該 用於宣傳不穩定或實驗性功能 - 這更好 由端點完成。/versions

合理能力的一些範例包括:

  • 伺服器是否支援用戶狀態。
  • 伺服器是否支援可選功能,例如使用者或 房間目錄。
  • 對用戶端施加的速率限制或檔類型限制 伺服器。

不應成為功能的一些範例包括:

  • 伺服器是否支持規範中的功能。unstable
  • 媒體大小限制 - 這些限制由 /config API 處理。
  • 用於通信的可選編碼或替代傳輸 伺服器

前綴為的功能保留用於在 矩陣規範,而其他值可能由伺服器使用 Java 包命名約定。矩陣支援的功能 規範將在本節後面定義。m.

GET /_matrix/client/v3/capabilities

獲取有關伺服器支援的功能集的資訊 和其他相關功能。

200 回應

{
  "capabilities": {
    "com.example.custom.ratelimit": {
      "max_requests_per_hour": 600
    },
    "m.change_password": {
      "enabled": false
    },
    "m.room_versions": {
      "available": {
        "1": "stable",
        "2": "stable",
        "3": "unstable",
        "test-version": "unstable"
      },
      "default": "1"
    }
  }
}

5.1 m.change_password能力

此功能具有單個標誌,指示是否或 不是使用者可以使用 API 來更改其 密碼。如果不存在,用戶端應假定密碼更改 可以通過 API 實現。如果存在,客戶應尊重 功能的標誌,並在用戶無法時向使用者指示 以更改其密碼。enabled/account/passwordenabled

功能 API 對此功能的回應示例如下:

{
  "capabilities": {
    "m.change_password": {
      "enabled": false
    }
  }
}

5.2 m.room_versions能力

此功能描述預設和可用的房間版本 a 伺服器支援,以及穩定性級別。客戶應使用 此功能,以確定是否需要鼓勵使用者 升級他們的房間。

功能 API 對此功能的回應示例如下:

{
  "capabilities": {
    "m.room_versions": {
      "default": "1",
      "available": {
        "1": "stable",
        "2": "stable",
        "3": "unstable",
        "custom-version": "unstable"
      }
    }
  }
}

此功能反映了房間的相同限制 用於描述哪些版本的版本 穩定和不穩定。用戶端應假定版本為 。任何未明確標記為版本的版本都將被視為 。例如,一個 列為的版本應被視為 。defaultstablestableavailableunstablefuture-stableunstable

版本是伺服器用於創建新版本的版本 房間。用戶端應鼓勵具有足夠許可權的使用者在 房間將他們的房間升級到房間時的版本 使用版本。defaultdefaultunstable

如果未列出此功能,用戶端應用作 默認且唯一穩定的房間版本。"1"available

5.3 m.set_displayname能力

此功能具有單個標誌 ,用於指示使用者是否 能夠通過配置檔終結點更改自己的顯示名稱。案例 禁用可能包括從外部標識/目錄映射的使用者 服務,例如LDAP。enabled

請注意,這與功能很好地匹配。m.set_avatar_url

如果未列出,用戶端應假定用戶能夠更改其 顯示名稱。

功能 API 對此功能的回應示例如下:

{
  "capabilities": {
    "m.set_displayname": {
      "enabled": false
    }
  }
}

5.4 m.set_avatar_url能力

此功能具有單個標誌 ,用於指示使用者是否 能夠通過配置檔端點更改自己的頭像。案例 禁用可能包括從外部標識/目錄映射的使用者 服務,例如LDAP。enabled

請注意,這與功能很好地匹配。m.set_displayname

如果未列出,用戶端應假定用戶能夠更改其 化身。

功能 API 對此功能的回應示例如下:

{
  "capabilities": {
    "m.set_avatar_url": {
      "enabled": false
    }
  }
}

5.5 m.3pid_changes能力

此功能具有單個標誌 ,用於指示使用者是否 能夠添加,刪除或更改其帳戶上的 3PID 關聯。注意 這僅影響使用者使用管理員聯繫資訊 API 的能力,而不會影響身份服務公開的終結點。禁用案例 可能包括從外部標識/目錄服務映射的使用者, 例如LDAP。enabled

如果未列出,用戶端應假定用戶能夠修改其 3PID 協會。

功能 API 對此功能的回應示例如下:

{
  "capabilities": {
    "m.3pid_changes": {
      "enabled": false
    }
  }
}

6 濾波

過濾器可以在伺服器上創建,並可以作為參數傳遞給 返回事件的 API。這些篩選器更改從返回的數據 那些 API。並非所有 API 都接受篩選器。

6.1 懶人裝載室成員

會員活動通常需要大量資源供客戶跟蹤。 為了減少使用的資源數量,用戶端可以啟用 房間成員的'延遲載入'。。通過這樣做,伺服器將嘗試 僅發送與客戶相關的會員活動。

重要的是要了解延遲載入並不是為了 完美的優化,並且伺服器可能不切實際 精確計算哪些成員資格事件與客戶相關。 因此,伺服器發送冗餘成員資格是有效的 事件向客戶端簡化實現,儘管這種冗餘 應盡可能減少以節省頻寬。

在篩檢程式方面,延遲載入是通過在 (或 僅大小寫)。啟用後,延遲載入感知端點(請參閱 以下)將僅包括 OF 活動的會員活動 包含在回應中。例如,如果客戶端發出啟用了延遲載入的請求,則伺服器將僅返回 時間線中事件的成員身份事件,而不是全部 聊天室的成員。lazy_load_membersRoomEventFilterStateFilter/syncsender/syncsender

在處理一系列事件時(例如,通過迴圈或 分頁 ),對於事件塊來說很常見 序列以共用一組類似的寄件者。而不是回應 將這些發送方的重複成員身份事件發送到 用戶端,伺服器可能會假設客戶端會記住成員資格 已發送的事件,並選擇跳過發送 會員資格未更改的成員資格活動。這些 稱為'冗餘成員資格事件'。。客戶可以要求 冗餘成員身份事件始終包含在回應中,方法是在篩選器中設置為 true。/sync/messagesinclude_redundant_members

使用延遲載入的預期模式目前為:

  • 用戶端在啟用延遲載入的情況下執行初始 /sync,並且 僅接收與的發送方相關的成員身份事件 它接收的事件。
  • 支持顯示名稱制表元補全或其他功能的用戶端 需要快速訪問房間內所有成員的操作 應為當前選定的聊天室調用 /members,並將參數設置為 /sync 回應的 from 令牌。成員清單 因為房間然後由國家在隨後維護 增量/同步回應。?at
  • 不支援製表符補全的用戶端可能會拉入 任意使用者的配置檔(例如已讀回執,鍵入 通知)通過查詢房間狀態或 ./profile

支援延遲載入房間成員的當前終結點包括:

  • /sync
  • /rooms//messages
  • /rooms//context/{eventId}

6.2 介面連接點

POST /_matrix/client/v3/user/{userId}/filter

將新的篩選器定義上載到主伺服器。 返回篩選器ID,該ID可在將來的請求中使用 限制將哪些事件返回到用戶端。

請求正文示例

{
  "event_fields": [
    "type",
    "content",
    "sender"
  ],
  "event_format": "client",
  "presence": {
    "not_senders": [
      "@alice:example.com"
    ],
    "types": [
      "m.presence"
    ]
  },
  "room": {
    "ephemeral": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.receipt",
        "m.typing"
      ]
    },
    "state": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "types": [
        "m.room.*"
      ]
    },
    "timeline": {
      "limit": 10,
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.room.message"
      ]
    }
  }
}

200 回應

{
  "filter_id": "66696p746572"
}

GET /_matrix/client/v3/user/{userId}/filter/{filterId}

200 回應

{
  "event_fields": [
    "type",
    "content",
    "sender"
  ],
  "event_format": "client",
  "presence": {
    "not_senders": [
      "@alice:example.com"
    ],
    "types": [
      "m.presence"
    ]
  },
  "room": {
    "ephemeral": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.receipt",
        "m.typing"
      ]
    },
    "state": {
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "types": [
        "m.room.*"
      ]
    },
    "timeline": {
      "limit": 10,
      "not_rooms": [
        "!726s6s6q:example.com"
      ],
      "not_senders": [
        "@spam:example.com"
      ],
      "types": [
        "m.room.message"
      ]
    }
  }
}

7 事件

用戶端-伺服器 API 公開的對話歷史記錄模型可以 被視為事件清單。伺服器'行化'了 將事件的最終一致性事件圖轉換為"事件流" 任何給定的時間點:

[E0]->[E1]->[E2]->[E3]->[E4]->[E5]

7.1 房間活動的類型

會議室活動分為兩類:

  • 狀態事件:這些是更新房間(例如房間)元數據狀態的事件 主題,房間成員資格等)。狀態由事件元組和 .具有相同鍵元組的房間中的狀態將是 覆蓋。typestate_key
  • 消息事件:這些事件描述了房間中的暫時性'一次性'活動:通常是通信,例如發送即時消息或設置 網路電話呼叫。

此規範概述了幾個事件,所有事件都具有事件類型 前綴。(有關 m. 事件,請參閱房間事件 規範。但是,應用程式可能希望添加自己的類型 事件,這可以使用 以下各節。如果添加了新事件,則事件鍵應 遵循 Java 包命名約定,例如 .這可確保事件類型合適 為每個應用程式命名,並降低衝突風險。m.typecom.example.myapp.event

7.2 會議室事件格式

聊天室事件的'聯合'格式,由主伺服器在內部使用 和通過伺服器-伺服器API的家庭伺服器之間,取決於"房間" 版本"在房間使用。例如,請參閱定義 房間版本 1 和房間版本 3.

但是,矩陣用戶端遇到此事件是不尋常的 格式。相反,主伺服器負責將事件轉換為 格式如下所示,以便用戶端可以輕鬆解析它們。

ClientEvent

事件從主伺服器返回到用戶端時用於事件的格式 通過用戶端-伺服器 API,或透過應用程式服務 API 發送到應用程式服務。

例子

{
  "content": {
    "membership": "join"
  },
  "event_id": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
  "origin_server_ts": 1632489532305,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@user:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1567437,
    "redacted_because": {
      "content": {
        "reason": "spam"
      },
      "event_id": "$Nhl3rsgHMjk-DjMJANawr9HHAhLg4GcoTYrSiYYGqEE",
      "origin_server_ts": 1632491098485,
      "redacts": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
      "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
      "sender": "@moderator:example.org",
      "type": "m.room.redaction",
      "unsigned": {
        "age": 1257
      }
    }
  }
}

7.3 剝離狀態

剝離狀態是房間狀態的簡化視圖,旨在説明 潛在的細木工識別房間。它由一組有限的狀態事件組成 它們本身經過簡化以減少所需的數據量。

剝離的狀態事件只能存在, 和屬性。sendertypestate_keycontent

剝離狀態通常出現在邀請,敲門和其他位置,其中 用戶可以在可用條件(例如受限房間)下加入聊天室。

用戶端應僅在沒有 進入房間的正常狀態。一旦房間的狀態為 可用,應丟棄所有剝離狀態。在以下情況下 用戶端具有房間的存檔狀態(例如被踢后) 並且用戶端正在接收房間的剝離狀態,例如來自 邀請或敲門,則剝離狀態應優先,直到 可以從聯接中獲取新狀態。

剝離狀態應包含以下部分或全部狀態事件,這些事件 應盡可能表示為剝離的狀態事件:

  • m.room.create
  • m.room.name
  • m.room.avatar
  • m.room.topic
  • m.room.join_rules
  • m.room.canonical_alias
  • m.room.encryption

7.4 大小限制

格式化時,完整事件不得大於65536位元組 使用聯合事件格式,包括任何 簽名,並編碼為規範 傑森。

每個金鑰大小還有其他限制:

  • sender不得超過255位元組(包括域)。
  • room_id不得超過 255 個字節。
  • state_key不得超過 255 個字節。
  • type不得超過 255 個字節。
  • event_id不得超過 255 個字節。

某些事件類型具有指定的其他大小限制 在事件的描述中。附加鍵沒有限制其他 而不是事件的總 64 KiB 限制所暗示的。

7.5 會議室活動

此規範概述了幾種標準事件類型,所有這些事件類型都 前綴為m.

m.room.canonical_alias

此事件用於通知聊天室應使用哪個別名 被認為是規範的,以及其他哪些別名指向房間。 這可以用於顯示目的或作為對別名用戶的建議 用於宣傳和訪問房間。

例子

{
  "content": {
    "alias": "#somewhere:localhost",
    "alt_aliases": [
      "#somewhere:example.org",
      "#myroom:example.com"
    ]
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.canonical_alias",
  "unsigned": {
    "age": 1234
  }
}

m.room.create

這是會議室中的第一個事件,無法更改。它充當所有其他事件的根。

{
  "content": {
    "creator": "@example:example.org",
    "m.federate": true,
    "predecessor": {
      "event_id": "$something:example.org",
      "room_id": "!oldroom:example.org"
    },
    "room_version": "1"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.create",
  "unsigned": {
    "age": 1234
  }
}

m.room.join_rules

房間可以具有以下名稱之一:

  • public- 任何人都可以加入房間,無需事先執行任何操作。
  • invite- 用戶必須首先收到會議室中已有人員的邀請 為了加入。
  • knock- 用戶可以請求邀請加入房間。他們可以被允許(邀請) 或拒絕(踢/禁止)訪問。否則,需要邀請使用者加入。只 可在支持敲門的房間使用。
  • restricted- 任何能夠滿足至少一個允許條件的人都是 無需事先操作即可加入房間。否則,需要邀請。 僅適用於支援加入規則的房間。
  • knock_restricted- 用戶可以使用提供的相同功能請求邀請 通過加入規則,或者可以在滿足允許條件的情況下嘗試加入 根據聯接規則。僅適用於支援加入規則的房間。knockrestricted
  • private- 保留而不實施。沒有重要意義。
{
  "content": {
    "join_rule": "public"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.join_rules",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "allow": [
      {
        "room_id": "!other:example.org",
        "type": "m.room_membership"
      },
      {
        "room_id": "!elsewhere:example.org",
        "type": "m.room_membership"
      }
    ],
    "join_rule": "restricted"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.join_rules",
  "unsigned": {
    "age": 1234
  }
}

m.room.member

調整聊天室中用戶的成員身份狀態。最好在執行成員資格操作時使用成員資格 API( 等),而不是直接調整狀態,因為存在一組受限制的有效轉換。例如,使用者 A 無法強制使用者 B 加入聊天室,並且嘗試直接強制更改此狀態將失敗。/rooms//invite

指定了以下成員資格狀態:

  • invite- 使用者已被邀請加入聊天室,但尚未加入該聊天室。在加入之前,他們不得參加會議室。
  • join- 使用者已加入聊天室(可能在接受邀請后),並可能參與其中。
  • leave- 用戶曾經加入房間,但後來離開了(可能是出於選擇,也可能是被踢)。
  • ban- 使用者已被禁止進入聊天室,並且不再被允許加入聊天室,直到他們被取消禁止進入聊天室(通過將其成員身份狀態設置為非 值)。ban
  • knock- 使用者已敲房間,請求允許參與。在加入之前,他們不得參加會議室。

如果此邀請是事件並且是事件的後續事件,則設置該屬性,否則不存在。third_party_inviteinvitem.room.third_party_invite

此事件還可能包含事件數據中的鍵。 如果存在,則包含一組剝離狀態事件,以説明接收器識別房間。invite_room_stateunsigned

套用成員資格的使用者由 .在某些情況下, 和可能不匹配 - 這可能被解釋為影響 用戶的成員身份狀態。state_keysenderstate_keysenderstate_key

給定使用者的 TO 可能會隨時間而變化。下表列出了各種更改 隨時間推移以及客戶端和伺服器必須如何解釋這些更改。可以檢索以前的會員資格 從事件上的物件。如果不存在,則必須假定使用者以前的成員身份 如。membershipprev_contentleave

{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "join",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "invite",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "invite_room_state": [
      {
        "content": {
          "name": "Example Room"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.name"
      },
      {
        "content": {
          "join_rule": "invite"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.join_rules"
      }
    ]
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "join_authorised_via_users_server": "@bob:other.example.org",
    "membership": "join"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "knock",
    "reason": "Looking for support"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234,
    "knock_room_state": [
      {
        "content": {
          "name": "Example Room"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.name"
      },
      {
        "content": {
          "join_rule": "knock"
        },
        "sender": "@bob:example.org",
        "state_key": "",
        "type": "m.room.join_rules"
      }
    ]
  }
}
{
  "content": {
    "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
    "displayname": "Alice Margatroid",
    "membership": "invite",
    "third_party_invite": {
      "display_name": "alice",
      "signed": {
        "mxid": "@alice:example.org",
        "signatures": {
          "magic.forest": {
            "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
          }
        },
        "token": "abc123"
      }
    }
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "@alice:example.org",
  "type": "m.room.member",
  "unsigned": {
    "age": 1234
  }
}

m.room.power_levels

此事件指定用戶必須具有的最低級別才能執行 某些動作。它還指定檔室中每個用戶的級別。

如果 a 在清單中,則具有 相關的功率級別。否則,它們具有默認級別。如果未提供,則假定為 0. 如果聊天室不包含任何事件,則聊天室的建立者具有 功率級別為 100,所有其他使用者的功率級別為 0。user_idusersuser_idusers_defaultusers_defaultm.room.power_levels

發送特定事件所需的級別由和控制。如果在 中指定了事件類型,則用戶必須至少具有指定的級別,以便 發送該事件。如果未提供事件類型,則預設為 for 消息事件和 state 事件。eventsstate_defaultevents_defaulteventsevents_defaultstate_default

如果事件中沒有state_default,或者 m.room.power_levels沒有事件,是 m.room.power_levels 50。 如果事件中沒有state_default, 或者沒有事件events_default,則為 0。

邀請使用者加入聊天室所需的功率級別,將使用者踢出 聊天室,禁止使用者進入聊天室或編輯其他用戶發送的事件是 分別由, , 和定義。關卡 ,如果未在事件中指定,或者檔室不包含任何事件,則預設為 50。 在任一情況下均預設為 0。invite kick ban redact kick ban redact m.room.power_levels m.room.power_levels invite

諾維克斯

功率電平值的允許範圍為 , 按照規範 JSON 規範的要求。[-(253)+1, (253)-1]

{
  "content": {
    "ban": 50,
    "events": {
      "m.room.name": 100,
      "m.room.power_levels": 100
    },
    "events_default": 0,
    "invite": 50,
    "kick": 50,
    "notifications": {
      "room": 20
    },
    "redact": 50,
    "state_default": 50,
    "users": {
      "@example:localhost": 100
    },
    "users_default": 0
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "state_key": "",
  "type": "m.room.power_levels",
  "unsigned": {
    "age": 1234
  }
}

7.5.1 歷史事件

但是,命名空間中的某些事件可能會出現在聊天室中 它們在此版本的規範中沒有重要意義。 它們是:m.

  • m.room.aliases

該規範的先前版本提供了有關這些的更多資訊 事件。

7.6 同步

若要讀取事件,預期的操作流是用戶端首先 調用不帶參數的 /sync API。這將返回 每個聊天室的最新消息事件,以及 返回時間線開頭的房間。回應還包括一個字段,該字段應在下次調用 時用作參數的值。最後,回應包括: 對於每個房間,一個字段,該字段可以作為參數傳遞給 /rooms//messages API 以提前檢索 消息。sincenext_batchsince/syncprev_batchstart

例如,一個請求可能會返回一個由四個事件組成的範圍,並在給定的房間內,省略兩個先前的事件和 。這可以可視化如下:/syncE2E3E4E5E0E1

    [E0]->[E1]->[E2]->[E3]->[E4]->[E5]
               ^                      ^
               |                      |
         prev_batch: '1-2-3'        next_batch: 'a-b-c'

通常,客戶端可見的所有新事件都將出現在 對 API 的回應。但是,如果大量事件 在調用 之間到達,返回'有限'時間線, 僅包含最新的消息事件。狀態"delta"也是 返回,總結省略部分的任何狀態更改 時間軸。因此,客戶最終可能會在其知識上出現"差距" 的消息時間線。用戶端可以使用 /rooms//messages API 填充這些空白。/sync/sync

繼續我們的示例,假設我們發出第三個請求,要求 自上次同步以來的事件,通過將令牌作為 參數。伺服器知道四個新事件,, 和 ,但認為這太多了,無法一次報告。相反 伺服器發送包含的回應,並且 省略。這形成了一個缺口,我們可以在可視化中看到:/syncnext_batchx-y-zsinceE7E8E9E10limitedE8E9E10E7

                                            | gap |
                                            | <-> |
    [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
                                            ^     ^                  ^
                                            |     |                  |
                                 since: 'x-y-z'   |                  |
                                       prev_batch: 'd-e-f'       next_batch: 'u-v-w'

有限的回應包括一個狀態增量,它描述了狀態 的房間在間隙上變化。此增量說明如何構建狀態 在從用戶端知道的狀態返回時間線(即在)之前 (即在 )。為了縮小差距,客戶端應該使用查詢參數和 向 /rooms//messages 發出請求。E7E6from=x-y-zto=d-e-f

GET /_matrix/client/v3/sync

將客戶端的狀態與伺服器上的最新狀態同步。 用戶端在首次登錄時使用此 API 以獲取初始快照 的狀態,然後繼續調用此 API 獲取 增量增量到狀態,並接收新消息。

注意:此端點支援延遲載入。有關詳細資訊,請參閱篩選。延遲載入成員僅在此端點上受支援。啟用延遲載入後,伺服器必須包括 當使用者加入聊天室時同步自己的成員資格事件,或者當使用者 請求房間的完整狀態,以幫助發現用戶的頭像和 顯示名稱。StateFilter

此外,與其他會員一樣,使用者自己的會員活動也符合條件 被伺服器視為冗餘。當同步為 時 , 伺服器必須返回間隙中事件的成員身份事件 (在返回的時間線之間和開始之間),無論 至於它們是否是多餘的。這可確保連接/離開 並且在間隙期間發生的輪廓變化不會丟失。limitedsince

請注意,的預設行為是包括所有成員資格 事件以及其他狀態,當未啟用延遲載入時。state

200回應

{
  "account_data": {
    "events": [
      {
        "content": {
          "custom_config_key": "custom_config_value"
        },
        "type": "org.example.custom.config"
      }
    ]
  },
  "next_batch": "s72595_4483_1934",
  "presence": {
    "events": [
      {
        "content": {
          "avatar_url": "mxc://localhost/wefuiwegh8742w",
          "currently_active": false,
          "last_active_ago": 2478593,
          "presence": "online",
          "status_msg": "Making cupcakes"
        },
        "sender": "@example:localhost",
        "type": "m.presence"
      }
    ]
  },
  "rooms": {
    "invite": {
      "!696r7674:example.com": {
        "invite_state": {
          "events": [
            {
              "content": {
                "name": "My Room Name"
              },
              "sender": "@alice:example.com",
              "state_key": "",
              "type": "m.room.name"
            },
            {
              "content": {
                "membership": "invite"
              },
              "sender": "@alice:example.com",
              "state_key": "@bob:example.com",
              "type": "m.room.member"
            }
          ]
        }
      }
    },
    "join": {
      "!726s6s6q:example.com": {
        "account_data": {
          "events": [
            {
              "content": {
                "tags": {
                  "u.work": {
                    "order": 0.9
                  }
                }
              },
              "type": "m.tag"
            },
            {
              "content": {
                "custom_config_key": "custom_config_value"
              },
              "type": "org.example.custom.room.config"
            }
          ]
        },
        "ephemeral": {
          "events": [
            {
              "content": {
                "user_ids": [
                  "@alice:matrix.org",
                  "@bob:example.com"
                ]
              },
              "type": "m.typing"
            },
            {
              "content": {
                "$1435641916114394fHBLK:matrix.org": {
                  "m.read": {
                    "@rikj:jki.re": {
                      "ts": 1436451550453
                    }
                  },
                  "m.read.private": {
                    "@self:example.org": {
                      "ts": 1661384801651
                    }
                  }
                }
              },
              "type": "m.receipt"
            }
          ]
        },
        "state": {
          "events": [
            {
              "content": {
                "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
                "displayname": "Alice Margatroid",
                "membership": "join",
                "reason": "Looking for support"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "state_key": "@alice:example.org",
              "type": "m.room.member",
              "unsigned": {
                "age": 1234
              }
            }
          ]
        },
        "summary": {
          "m.heroes": [
            "@alice:example.com",
            "@bob:example.com"
          ],
          "m.invited_member_count": 0,
          "m.joined_member_count": 2
        },
        "timeline": {
          "events": [
            {
              "content": {
                "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
                "displayname": "Alice Margatroid",
                "membership": "join",
                "reason": "Looking for support"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "state_key": "@alice:example.org",
              "type": "m.room.member",
              "unsigned": {
                "age": 1234
              }
            },
            {
              "content": {
                "body": "This is an example text message",
                "format": "org.matrix.custom.html",
                "formatted_body": "<b>This is an example text message</b>",
                "msgtype": "m.text"
              },
              "event_id": "$143273582443PhrSn:example.org",
              "origin_server_ts": 1432735824653,
              "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
              "sender": "@example:example.org",
              "type": "m.room.message",
              "unsigned": {
                "age": 1234
              }
            }
          ],
          "limited": true,
          "prev_batch": "t34-23535_0_0"
        },
        "unread_notifications": {
          "highlight_count": 1,
          "notification_count": 5
        },
        "unread_thread_notifications": {
          "$threadroot": {
            "highlight_count": 3,
            "notification_count": 6
          }
        }
      }
    },
    "knock": {
      "!223asd456:example.com": {
        "knock_state": {
          "events": [
            {
              "content": {
                "name": "My Room Name"
              },
              "sender": "@alice:example.com",
              "state_key": "",
              "type": "m.room.name"
            },
            {
              "content": {
                "membership": "knock"
              },
              "sender": "@bob:example.com",
              "state_key": "@bob:example.com",
              "type": "m.room.member"
            }
          ]
        }
      }
    },
    "leave": {}
  }
}

7.7 獲取聊天室的事件

為聊天室的事件提供了多個 API:

GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}

獲取基於的單個事件。您必須具有以下權限:檢索此事件,例如,通過成為此事件房間中的成員。roomId/eventId

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!636q39766251:matrix.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

GET /_matrix/client/v3/rooms/{roomId}/joined_members

此 API 將 MXID 的映射返回到聊天室成員的成員信息物件。當前用戶必須在聊天室中才能工作,除非它是應用程式服務,在這種情況下,任何 AS 的使用者都必須在聊天室中。此 API 主要用於應用程式服務,回應速度應快於在伺服器上更高效地實現。/members

{
  "joined": {
    "@bar:example.com": {
      "avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK",
      "display_name": "Bar"
    }
  }
}

GET /_matrix/client/v3/rooms/{roomId}/members

獲取此會議室的成員清單。

{
  "chunk": [
    {
      "content": {
        "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
        "displayname": "Alice Margatroid",
        "membership": "join",
        "reason": "Looking for support"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "@alice:example.org",
      "type": "m.room.member",
      "unsigned": {
        "age": 1234
      }
    }
  ]
}

GET /_matrix/client/v3/rooms/{roomId}/state

獲取聊天室當前狀態的狀態事件。

[
  {
    "content": {
      "join_rule": "public"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.join_rules",
    "unsigned": {
      "age": 1234
    }
  },
  {
    "content": {
      "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
      "displayname": "Alice Margatroid",
      "membership": "join",
      "reason": "Looking for support"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "@alice:example.org",
    "type": "m.room.member",
    "unsigned": {
      "age": 1234
    }
  },
  {
    "content": {
      "creator": "@example:example.org",
      "m.federate": true,
      "predecessor": {
        "event_id": "$something:example.org",
        "room_id": "!oldroom:example.org"
      },
      "room_version": "1"
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.create",
    "unsigned": {
      "age": 1234
    }
  },
  {
    "content": {
      "ban": 50,
      "events": {
        "m.room.name": 100,
        "m.room.power_levels": 100
      },
      "events_default": 0,
      "invite": 50,
      "kick": 50,
      "notifications": {
        "room": 20
      },
      "redact": 50,
      "state_default": 50,
      "users": {
        "@example:localhost": 100
      },
      "users_default": 0
    },
    "event_id": "$143273582443PhrSn:example.org",
    "origin_server_ts": 1432735824653,
    "room_id": "!636q39766251:example.com",
    "sender": "@example:example.org",
    "state_key": "",
    "type": "m.room.power_levels",
    "unsigned": {
      "age": 1234
    }
  }
]

GET /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}

查找檔室中狀態事件的內容。如果使用者是 加入到房間,然後狀態從當前獲取 房間的狀態。如果用戶已離開房間,則狀態為 取自他們離開時的房間狀態。

200 回應

{
  "name": "Example room name"
}

GET /_matrix/client/v3/rooms/{roomId}/messages

此 API 返回聊天室的消息和狀態事件清單。它使用 分頁查詢參數,用於對房間中的歷史記錄進行分頁。

注:此端點支援延遲載入檔案室成員事件。有關詳細資訊,請參閱懶惰載入室成員。

{
  "chunk": [
    {
      "content": {
        "body": "This is an example text message",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>This is an example text message</b>",
        "msgtype": "m.text"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234
      }
    },
    {
      "content": {
        "name": "The room name"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "state_key": "",
      "type": "m.room.name",
      "unsigned": {
        "age": 1234
      }
    },
    {
      "content": {
        "body": "Gangnam Style",
        "info": {
          "duration": 2140786,
          "h": 320,
          "mimetype": "video/mp4",
          "size": 1563685,
          "thumbnail_info": {
            "h": 300,
            "mimetype": "image/jpeg",
            "size": 46144,
            "w": 300
          },
          "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
          "w": 480
        },
        "msgtype": "m.video",
        "url": "mxc://example.org/a526eYUSFFxlgbQYZmo442"
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:example.com",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234
      }
    }
  ],
  "end": "t47409-4357353_219380_26003_2265",
  "start": "t47429-4392820_219380_26003_2265"
}

GET /_matrix/client/v1/rooms/{roomId}/timestamp_to_event

v1.6 中新增

獲取最接近給定時間戳的事件的ID,在 參數指定的方向。dir

如果伺服器沒有所有房間歷史記錄,並且沒有 適當接近請求時間戳的事件,它可以使用 相應的聯合終結點,用於向其他伺服器請求合適的事件。

調用此終結點后,用戶端可以調用 /rooms/{roomId}/context/{eventId} 來獲取分頁令牌,以檢索返回事件周圍的事件。

此終結點返回的事件可能是用戶端返回的事件 無法呈現,因此可能需要分頁才能找到事件 它可以顯示,最終可能會超出用戶端的 合適的範圍。客戶可以採用不同的策略來展示 對用戶來說合理的東西。例如,用戶端可以嘗試 朝一個方向分頁一會兒,同時看著 它正在分頁的事件的時間戳,以及它是否 超過與目標時間戳的一定差異,可以嘗試 以相反的方向分頁。客戶也可以簡單地 在一個方向上分頁,並通知使用者最近的事件 在該方向上發現超出了預期範圍。

{
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653
}

7.8 將事件發送到聊天室

如果某些事件與另一個事件相關,則伺服器可能需要對其進行後處理。該活動的 關係類型 () 確定可能適用的任何限制, 例如,使用者只能發送一個給定類型的事件 到另一個。rel_type

PUT /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}

可以使用此終結點發送狀態事件。這些事件將是 覆蓋 if 和所有 火柴。

對此端點的請求不能像其他路徑一樣使用事務 ID,因為它們無法與 .此外,在狀態路徑上不受支援。PUTstate_keyPOST

請求的正文應該是事件的內容物件;這 此物件中的欄位將根據事件類型而有所不同。有關活動規範,請參閱會議室活動。m.

如果要發送的事件類型是伺服器 應確保事件中列出的任何新別名都有效 根據他們的語法/句法,並且他們指向房間ID其中 將發送狀態事件。伺服器不驗證別名 正在刪除或已存在於狀態事件中。m.room.canonical_alias

請求正文示例

{
  "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF",
  "displayname": "Alice Margatroid",
  "membership": "join"
}

200回應

{
  "event_id": "$YUwRidLecu:example.com"
}

PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}

此終結點用於將消息事件發送到聊天室。消息事件 允許訪問歷史事件和分頁,使其適合 用於房間內的'一次性'活動。

請求的正文應該是事件的內容物件;這 此物件中的欄位將根據事件類型而有所不同。有關 m. 事件規範,請參閱會議室事件。

請求正文示例

{
  "body": "hello",
  "msgtype": "m.text"
}

200 回應

{
  "event_id": "$YUwRidLecu:example.com"
}

7.9 密文

由於事件是可擴展的,因此惡意使用者和/或 伺服器,用於添加諸如攻擊性或非法的密鑰。因為 有些事件不能簡單地刪除,例如會員活動,我們取而代之的是 "編輯"事件。這涉及從事件中刪除所有鍵 協定不需要。此後,此精簡事件 每當客戶端或遠端伺服器請求它時返回。編輯一個 事件無法撤銷,允許伺服器擁有者刪除有問題的 資料庫中的內容。伺服器應在向用戶端提供經過編輯的事件時在 as 下包含事件的副本。m.room.redactionunsignedredacted_because

在房間中定義要應用於事件的確切演算法 版本規範,以及主伺服器應遵循的標準 在決定是否接受來自遠端的編校事件時使用 主伺服器。

當用戶端收到事件時,它應該更改 受影響的事件與伺服器相同。m.room.redaction

7.9.1 事件

m.room.redaction

此事件由伺服器創建,用於描述已編輯的事件,由誰編輯以及(可選)原因。已編輯的事件在事件級別鍵中指定。編輯事件意味著協定不需要的所有密鑰都會被剝離,從而允許隱藏消息或允許管理員刪除冒犯性或非法內容。redacts

{
  "content": {
    "reason": "Spamming"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "redacts": "$fukweghifu23:localhost",
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.redaction",
  "unsigned": {
    "age": 1234
  }
}

7.9.2 客戶端行為

PUT /_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{txnId}

從對 聊天室的伺服器端表示形式的完整性。

這是無法撤銷的。

任何功率級別大於或等於事件功率級別的使用者都可以在聊天室中發送密文事件。如果用戶的電源 電平大於也大於或等於功率電平 ,用戶可以編輯其他用戶發送的事件。m.room.redactionredact

伺服器管理員可以編輯使用者在其伺服器上發送的事件。

請求正文示例

{
  "reason": "Indecent material"
}

200 回應

{
  "event_id": "$YUwQidLecu:example.com"
}

7.10 在事件之間形成關係

在某些情況下,最好在邏輯上將一個事件的內容與 另一個事件的內容 — 例如,在回復消息時,編輯 事件,或者只是希望為事件的目的添加上下文。

事件在父/子結構中相互關聯,其中任何事件都可以 通過簡單地讓一個孩子事件點成為父母。父事件不 定義他們的孩子,而不是依靠孩子來描述他們的父母。

子事件與其父事件之間的關係在子事件中描述 事件為(定義如下)。子事件可以指向 任何其他事件,包括另一個子事件,以建立如此長時間的關係 由於兩個活動都在同一個房間內,但是可能會施加額外的限制 按關係的類型 ()。contentm.relates_torel_type

若要允許伺服器聚合和查找父事件的子事件,事件的鍵必須包含在事件的明文部分中。它不可能 以獨佔方式記錄在加密的有效負載中,因為伺服器無法解密事件 用於處理。m.relates_to

與架構不匹配或違反關係規則的關係, 只是被忽略了。一個例子可能是父項和子項處於不同的位置 房間,或以下架構所需的缺少屬性的關係。客戶 處理此類無效關係應獨立於每個事件顯示事件 其他,可選取的顯示錯誤訊息。

m.relates_to

{
  "m.relates_to": {
    "event_id": "$an_event",
    "rel_type": "org.example.relationship"
  }
}

7.10.1 關係類型

這個規範描述以下關係類型:

  • Event replacements.
  • Event annotations.
  • Threads.
  • References

7.10.2 子事件的聚合

某些子事件可以由伺服器'聚合',具體取決於它們的 .這可以允許將一組子事件匯總到用戶端,而無需 需要子事件本身的用戶端。rel_type

這方面的一個例子可能是 a 需要一個額外的欄位,當 適當指定,將意味著用戶端收到該數字的總數 子事件使用的次數。rel_typekeykey

實際的聚合格式取決於 .rel_type

當通過下面列出的 API 將事件提供給用戶端時,如果事件具有子級,則在'如果事件具有子項'下將包含一個屬性 可以聚合併指向它的事件。該物業是 由和值為鍵的物件是特定於類型的聚合 格式.此屬性稱為'捆綁'。 聚合" 。m.relationsunsignedm.relationsrel_typerel_typem.relations

例如(不包括不重要的欄位):

{
  "event_id": "$my_event",
  "unsigned": {
    "m.relations": {
      "org.example.possible_annotations": [
        {
          "key": "👍",
          "origin_server_ts": 1562763768320,
          "count": 3
        },
        {
          "key": "👎",
          "origin_server_ts": 1562763768320,
          "count": 1
        }
      ],
      "org.example.possible_thread": {
        "current_server_participated": true,
        "count": 7,
        "latest_event": {
          "event_id": "$another_event",
          "content": {
            "body": "Hello world"
          }
        }
      }
    }
  }
}

7.10.3 關係介面

若要從伺服器檢索父項的子事件,用戶端可以調用 以下端點。

如果客戶端丟失了聚合上的上下文,則此終結點特別有用 父事件,需要重新生成/驗證它。

GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}

檢索給定父事件的所有子事件。

請注意,分頁時,令牌應"在"令牌之後 拓撲排序術語,因為只能'向後'分頁 通過事件,從 開始。fromtofrom

例如,從結果的第 2 頁傳遞令牌,以及一個令牌 從第 1 頁開始,將返回空集。調用方可以使用來自 但是,第 1 頁和第 2 頁中的標記將在同一範圍內進行分頁。fromtofromto

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}
GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/{relType}

檢索給定父事件與父事件相關的所有子事件 使用給定的 .relType

請注意,分頁時,令牌應"在"令牌之後 拓撲排序術語,因為只能'向後'分頁 通過事件,從 開始。fromtofrom

例如,從結果的第 2 頁傳遞令牌,以及一個令牌 從第 1 頁開始,將返回空集。調用方可以使用來自 但是,第 1 頁和第 2 頁中的標記將在同一範圍內進行分頁。fromtofromto

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}
GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}

檢索給定父事件與父事件相關的所有子事件 使用給定的並擁有給定的.relTypeeventType

請注意,分頁時,令牌應"在"令牌之後 拓撲排序術語,因為只能'向後'分頁 通過事件,從 開始。fromtofrom

例如,從結果的第 2 頁傳遞令牌,以及一個令牌 從第 1 頁開始,將返回空集。調用方可以使用來自 但是,第 1 頁和第 2 頁中的標記將在同一範圍內進行分頁。fromtofromto

{
  "chunk": [
    {
      "content": {
        "m.relates_to": {
          "event_id": "$asfDuShaf7Gafaw",
          "rel_type": "org.example.my_relation"
        }
      },
      "event_id": "$143273582443PhrSn:example.org",
      "origin_server_ts": 1432735824653,
      "room_id": "!636q39766251:matrix.org",
      "sender": "@example:example.org",
      "type": "m.room.message",
      "unsigned": {
        "age": 1234
      }
    }
  ],
  "next_batch": "page2_token",
  "prev_batch": "page1_token"
}

8 房間

8.1 類型

(可選)房間可以具有表示其預期功能的類型。一個房間 沒有類型並不一定意味著它具有特定的預設函數, 儘管通常這些房間將用於對話目的。

當客戶可能需要區分 兩個不同的房間,例如對話保持和數據保持。如果房間 有一個類型,它在 m.room.create 事件的鍵中指定。要指定房間的類型,請將其作為 on 的一部分提供 創建檔案室請求。typecreation_content

在此規範中,指定了以下房型:

  • m.space

通過使用命名空間標識碼,允許未指定的房間類型。

8.2 創造

當房間 已創建,用作此聊天室的事件圖的根。這 事件還有一個金鑰,其中包含聊天室的使用者 ID 造物主。它還將生成其他幾個事件以管理 此房間的許可權。這包括:m.room.createcreator

  • m.room.power_levels:設置使用者的功率級別和所需功率 房間內各種操作的級別,例如發送事件。
  • m.room.join_rules:房間是否"僅限邀請"。

有關這些活動的更多資訊,請參閱會議室活動。自 創建房間時,客戶端必須使用以下 API。

POST /_matrix/client/v3/createRoom

創建具有各種配置選項的新房間。

伺服器必須在創建時應用正常狀態解析規則 新房間,包括檢查每個事件的功率級別。它必須 依以下順序應用請求隱含的事件:

  1. 事件本身。必須是 房間。m.room.create

  2. 建立者加入聊天室的事件。這是 需要,以便可以發送其餘事件。m.room.member

  3. 默認事件,為房間建立者提供 (而不是其他成員)發送狀態事件的許可權。重寫 按參數。m.room.power_levelspower_level_content_override

  4. 如果給定,則為事件。m.room.canonical_aliasroom_alias_name

  5. 由設置的事件。目前,這些是 , 和狀態事件。presetm.room.join_rulesm.room.history_visibilitym.room.guest_access

  6. 中列出的事件,按其順序排列 上市。initial_state

  7. 和 ( 和狀態事件)所隱含的事件。nametopicm.room.namem.room.topic

  8. 邀請和 ( with and ) 所隱含的事件。inviteinvite_3pidm.room.membermembership: invitem.room.third_party_invite

伺服器將在房間內創建一個事件,其中包含 請求使用者作為建立者,以及中提供的其他密鑰。m.room.createcreation_content

請求正文示例

{
  "creation_content": {
    "m.federate": false
  },
  "name": "The Grand Duke Pub",
  "preset": "public_chat",
  "room_alias_name": "thepub",
  "topic": "All about happy hour"
}

200 回應

{
  "room_id": "!sefiuhWgwghwWgh:example.com"
}

8.3 房間別名 伺服器可以託管具有人類友好名稱的房間的別名。別名 採取形式.#friendlyname:server.name

由於房間別名的範圍限定為特定的主伺服器功能變數名稱,因此它是 主伺服器可能會拒絕在 上維護別名的嘗試 其他功能變數名稱。此規範不提供 主伺服器,用於向其他伺服器發送更新請求。然而 主伺服器必須處理解析其他別名的請求 伺服器;如有必要,他們應使用聯合身份驗證 API 執行此操作。GET

但是,檔室不會儲存檔室中存在的所有別名的清單 具有相關許可權的聊天室成員可以發佈首選 通過狀態事件的別名。中的別名 狀態事件應指向在其中發佈它們的房間ID, 但是,隨著時間的推移,房間別名可能會漂移到其他房間 ID。 用戶端不應將別名視為準確。他們應該被檢查 在使用它們或與其他用戶共用之前。如果房間看起來 具有的房間別名,這應該被檢查到 確保房間的ID與從 請求。m.room.canonical_alias#alias: example.comroom_id

GET /_matrix/client/v3/directory/room/{roomAlias}

請求伺服器將會議室別名解析為會議室ID。

伺服器將使用聯合 API 解析別名,如果 別名的域部分與伺服器自己的不對應 域。

200 回應

{
  "room_id": "!abnjk1jdasj98:capuchins.com",
  "servers": [
    "capuchins.com",
    "matrix.org",
    "another.com"
  ]
}

PUT /_matrix/client/v3/directory/room/{roomAlias}

請求正文示例

{
  "room_id": "!abnjk1jdasj98:capuchins.com"
}

200 回應

{}

DELETE /_matrix/client/v3/directory/room/{roomAlias}

刪除房間別名到房間ID的映射。

伺服器可以選擇在此處實施額外的訪問控制檢查,例如 聊天室別名只能由其建立者或伺服器管理員刪除。

注意:伺服器可以選擇在刪除別名時更新聊天室中的狀態事件。選擇更新 建議使用規範別名事件,除了其其他相關許可權外 檢查,刪除別名並返回成功回應,即使用戶沒有 有權更新事件。alt_aliasesm.room.canonical_aliasm.room.canonical_alias

200 回應

{}

GET /_matrix/client/v3/rooms/{roomId}/aliases

獲取由本地伺服器維護的別名清單 給了空間。

此終結點可由會議室(外部)中的用戶調用 使用者會收到錯誤回應)。如果房間映射到 ,則任意 用戶可以調用此終結點。M_FORBIDDENm.room.history_visibilityworld_readable

伺服器可以選擇在此處實施額外的訪問控制檢查, 例如,允許伺服器管理員查看別名,而不管 會員。

注意:建議用戶端不要突出顯示此別名清單 因為它們不是策劃的,不像狀態事件中列出的那些。m.room.canonical_alias

200 回應

{
  "aliases": [
    "#somewhere:example.com",
    "#another:example.com",
    "#hat_trick:example.com"
  ]
}

8.4 許可權

房間的許可權是通過功率級別的概念完成的 - 待辦事項 用戶在房間內的任何操作都必須具有合適的功率級別。權力 關卡作為狀態事件存儲在給定房間中。功率水準 操作所需的和使用者的功率級別在 中定義,其中預設使用者和特定使用者的功率 可以設置級別。默認情況下,所有使用者的功率級別為 0,其他 比電源級別預設為 100 的聊天室建立者。用戶可以授予 其他使用者將功率級別提高到自己的功率級別。為 例如,功率級別為50的使用者 A 可以提高功率級別 使用者 B 的最高等級為 50。跟蹤使用者的功率水準 每個房間,即使使用者不在房間中。包含的金鑰 在確定某些所需的水準 踢,禁止和發送國家事件等操作。有關詳細資訊,請參閱m.room.power_levels。m.room.power_levelsm.room.power_levels

用戶端可能希望為特定功率級別分配名稱。一建議 映射如下:- 0 使用者 - 50 版主 - 100 管理員

8.5 檔室成員資格

使用者需要是聊天室的成員才能發送和接收事件 在那個房間里。使用者可能處於多種狀態,在 與房間的關係:

  • 不相關(使用者無法在聊天室中傳送或接收事件)
  • 敲門(使用者已請求參與房間,但 尚不被允許 )
  • 已邀請(使用者已被邀請參與聊天室,但 尚未參與)
  • 已加入(使用者可以在聊天室中傳送與接收事件)
  • 禁止(不允許使用者加入聊天室)

有一些值得注意的例外情況允許未加入的成員 在聊天室中傳送事件的房間:

  • 希望拒絕邀請的使用者將使用 發送帶有的事件。他們一定是先被邀請的。m.room.membercontent.membershipleave

  • 如果房間允許,用戶可以發送帶有 of 的事件來敲房間。這是使用者發出的邀請請求。m.room.membercontent.membershipknock

  • 要收回之前的敲門聲,用戶將發送類似於 拒絕邀請。leave

有些聊天室要求使用者在加入之前先受邀加入; 其他人允許任何人加入。給定的聊天室是否為"僅限受邀者" 房間由房間配置鍵確定。它可以 具有以下值之一:m.room.join_rules

public這個房間可供任何人免費加入,無需邀請。

invite只有在您被邀請的情況下才能加入此房間。

knock此房間只有在您被邀請的情況下才能加入,並允許任何人 請求邀請加入會議室。請注意,此聯接規則僅可用 在支援敲門的房間版本中。

[v1.2 中新增]

restricted如果您被邀請或您是另一個房間的成員,則可以加入此房間 加入規則中列出的房間。如果伺服器無法驗證任何成員身份 列出的房間,那麼您只能通過邀請加入。請注意,此規則 只應在支援它的房間版本中工作。

[v1.3 中新增]

knock_restricted這個房間可以像以前一樣連接。如果你 使用敲門與房間交互,規則生效,而 嘗試在沒有邀請的情況下加入聊天室將應用加入規則。 請注意,此規則僅適用於支援它的房間版本。restrictedknockknockrestricted

GET /_matrix/client/v3/joined_rooms

此 API 傳回使用者目前聊天室的清單。

{
  "joined_rooms": [
    "!foo:example.com"
  ]
}

8.5.1 連接房間

POST /_matrix/client/v3/rooms/{roomId}/invite

請注意,此 API 有兩種形式,分別記錄。 此版本的 API 要求邀請者知道矩陣 被邀請者的標識碼。另一個記錄在第三方邀請部分中。

此 API 邀請用戶參與特定聊天室。 在他們實際加入 房間。

只有當前位於特定聊天室中的使用者才能邀請其他使用者 加入那個房間。

如果使用者被邀請到聊天室,主伺服器會將事件追加到聊天室。m.room.member

請求正文示例

{
  "reason": "Welcome to the team!",
  "user_id": "@cheeky_monkey:matrix.org"
}

200 回應

{}
POST /_matrix/client/v3/join/{roomIdOrAlias}

請注意,此 API 採用房間 ID 或別名,這與 ./rooms/{roomId}/join

此 API 啟動參與特定聊天室的使用者(如果該使用者) 被允許參加該房間。在此調用之後,用戶端是 允許查看房間中的所有當前狀態事件,以及所有後續事件 與聊天室關聯的事件,直到使用者離開聊天室。

使用者加入檔室后,該聊天室將作為條目顯示在 /initialSync 和 /sync API 的回應。

請求正文示例

{
  "reason": "Looking for support",
  "third_party_signed": {
    "mxid": "@bob:example.org",
    "sender": "@alice:example.org",
    "signatures": {
      "example.org": {
        "ed25519:0": "some9signature"
      }
    },
    "token": "random8nonce"
  }
}

200 回應

{
  "room_id": "!d41d8cd:matrix.org"
}
POST /_matrix/client/v3/rooms/{roomId}/join

請注意,此 API 需要會議室 ID,而不是別名。 如果您有檔室別名,則存在。/join/{roomIdOrAlias}

此 API 啟動參與特定聊天室的使用者(如果該使用者) 被允許參加該房間。在此調用之後,用戶端是 允許查看房間中的所有當前狀態事件,以及所有後續事件 與聊天室關聯的事件,直到使用者離開聊天室。

使用者加入檔室后,該聊天室將作為條目顯示在 /initialSync 和 /sync API 的回應。

請求正文示例

{
  "reason": "Looking for support",
  "third_party_signed": {
    "mxid": "@bob:example.org",
    "sender": "@alice:example.org",
    "signatures": {
      "example.org": {
        "ed25519:0": "some9signature"
      }
    },
    "token": "random8nonce"
  }
}

200 回應

{
  "room_id": "!d41d8cd:matrix.org"
}

8.5.2 離開房間

用戶可以離開聊天室以停止接收該聊天室的事件。一個使用者 必須在他們被邀請或加入房間之前 有資格離開房間。離開使用者所在的房間 邀請拒絕邀請,並且可以收回敲門聲。用戶離開后 一個房間,它將不再出現在對 /sync API 的回應中,除非它是 通過具有欄位集的過濾器顯式請求 自。include_leavetrue

無論他們是否真的加入了房間,如果房間是一個 "僅限邀請"聊天室 使用者需要重新邀請才能 重新加入房間。

使用者還可以忘記他們離開的房間。客房有 被遺忘永遠不會出現對 /sync API 的回應, 直到使用者重新加入,重新邀請或敲門。

使用者可能希望強制其他使用者離開房間。這是可以做到的 通過'踢'其他使用者。為此,執行踢球的用戶必須 具有所需的功率水準。一旦使用者被踢出,則 行為與自願離開是一樣的。在 特別是,如果房間不是,用戶可以自由重新加入 "僅限邀請"。

POST /_matrix/client/v3/rooms/{roomId}/forget

此 API 阻止使用者記住特定房間。

一般來說,歷史是駭客帝國的一等公民。在此 API 之後 被調用,但是,使用者將無法再檢索歷史記錄 對於這個房間。如果主伺服器上的所有用戶都忘記了一個房間,則該房間是 符合從該主伺服器刪除的條件。

如果使用者當前已加入聊天室,則他們必須離開聊天室 在調用此 API 之前。

200 回應

{}
POST /_matrix/client/v3/rooms/{roomId}/leave

此 API 阻止用戶參與特定聊天室。

如果用戶已經在房間中,他們將無法再看到 房間里有新事件。如果聊天室需要邀請才能加入,則 需要重新邀請才能重新加入。

如果使用者被邀請加入聊天室,但尚未加入,則此呼叫 用於拒絕邀請。

使用者仍被允許從房間中檢索歷史記錄 他們以前被允許看到。

請求正文示例

{
  "reason": "Saying farewell - thanks for the support!"
}

200 回應

{}
POST /_matrix/client/v3/rooms/{roomId}/kick

將使用者踢出房間。

調用方必須具有所需的功率級別才能執行此操作。

踢出使用者會將目標成員的成員資格狀態調整為 自選。與其他成員資格更改一樣,用戶可以直接調整 通過向發出請求來顯示目標成員的狀態。leavereason/rooms/ /state/m.room.member/

請求正文示例

{
  "reason": "Telling unfunny jokes",
  "user_id": "@cheeky_monkey:matrix.org"
}

200 回應

{}

8.6 列出房間

GET /_matrix/client/v3/directory/list/room/{roomId}

獲取給定檔室在伺服器的公共會議室目錄中的可見性。

200 回應

{
  "visibility": "public"
}

PUT /_matrix/client/v3/directory/list/room/{roomId}

設置給定聊天室在伺服器公共聊天室中的可見性 目錄。

伺服器可以選擇實施額外的訪問控制檢查 例如,在這裡,房間的可見性只能通過以下方式更改 聊天室建立者或伺服器管理員。

請求正文示例

{
  "visibility": "public"
}

200 回應

{}

GET /_matrix/client/v3/publicRooms

列出伺服器上的公共會議室。

此 API 返回分頁回應。房間按編號排序 加入的成員,最大的房間排在第一位。

200 回應

{
  "chunk": [
    {
      "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
      "guest_can_join": false,
      "join_rule": "public",
      "name": "CHEESE",
      "num_joined_members": 37,
      "room_id": "!ol19s:bleecker.street",
      "room_type": "m.space",
      "topic": "Tasty tasty cheese",
      "world_readable": true
    }
  ],
  "next_batch": "p190q",
  "prev_batch": "p1902",
  "total_room_count_estimate": 115
}

9 用戶數據

9.1 用戶目錄

POST /_matrix/client/v3/user_directory/search

對使用者執行搜索。主伺服器可能 確定搜索哪些用戶子集,但主伺服器 必須至少考慮請求使用者共享的使用者 與居住在公共房間(家庭伺服器已知)的人的房間。 搜索必須考慮本地使用者到主伺服器,並且應該 在搜索過程中查詢遠端使用者。

搜索對使用者 ID 和顯示不區分大小寫 名稱最好使用基於請求中提供的標頭(如果存在)確定的排序規則。Accept-Language

請求正文示例

{
  "limit": 10,
  "search_term": "foo"
}

200 回應

{
  "limited": false,
  "results": [
    {
      "avatar_url": "mxc://bar.com/foo",
      "display_name": "Foo",
      "user_id": "@foo:bar.com"
    }
  ]
}

9.2 配置 檔

GET /_matrix/client/v3/profile/{userId}

獲取此使用者的組合配置檔資訊。可以使用此介面 獲取使用者自己的個人資料資訊或其他使用者;也 本地或遠端家庭伺服器上。此 API 可能會返回不是 只限於或 。displaynameavatar_url

200 回應

{
  "avatar_url": "mxc://matrix.org/SDGdghriugerRg",
  "displayname": "Alice Margatroid"
}

GET /_matrix/client/v3/profile/{userId}/avatar_url

獲取用戶的頭像網址。此 API 可用於獲取使用者的 擁有頭像網址或查詢其他使用者的網址;本地或 在遠端家庭伺服器上。

200 回應

{
  "avatar_url": "mxc://matrix.org/SDGdghriugerRg"
}

PUT /_matrix/client/v3/profile/{userId}/avatar_url

此 API 設定給定使用者的頭像 URL。您必須具有以下權限:設定此使用者的頭像 URL,例如,您需要擁有他們的 .access_token

請求正文示例

{
  "avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34"
}

200 回應

{}

GET /_matrix/client/v3/profile/{userId}/displayname

獲取使用者的顯示名稱。此 API 可用於獲取使用者的 自己的顯示名稱或查詢其他用戶的名稱;本地或 在遠端家庭伺服器上。

{
  "displayname": "Alice Margatroid"
}

PUT /_matrix/client/v3/profile/{userId}/displayname

此 API 設定給定使用者的顯示名稱。您必須具有以下權限:設定此使用者的顯示名稱,例如,您需要具有他們的 .access_token

請求正文示例

{
  "displayname": "Alice Margatroid"
}

200 回應

{}

9.2.1 個人資料資訊變更事件

因為配置文件顯示名稱和頭像資訊很可能是 在客戶端顯示的許多位置使用,對這些欄位的更改會導致 發生自動傳播事件,通知可能感興趣的人 新價值觀的各方。此更改使用兩個單獨的 機制:

  • 一個事件(具有成員資格)被發送到每個 使用者所屬的聊天室,以更新 和 。m.room.memberjoindisplaynameavatar_url
  • 發送狀態更新,再次包含 和鍵的新值,此外 到包含當前狀態的必需鍵 的使用者。m.presencedisplaynameavatar_urlpresence 當使用者使用時,這兩者都應由主伺服器自動完成 成功更改其顯示名稱或頭像 URL 欄位。

此外,當主伺服器為自己發出房間成員身份事件時 用戶,他們應該在 這些事件使客戶已經掌握了這些詳細資訊,並且 不必執行額外的往返來查詢它。

10 安全

10.1 速率限制

家庭伺服器應實施速率限制以降低風險 重載。如果請求因速率限制而被拒絕,則應 傳回以下形式的標準錯誤回應:

{
  "errcode": "M_LIMIT_EXCEEDED",
  "error": "string",
  "retry_after_ms": integer (optional)
}

應包含金鑰以告訴客戶端多長時間 他們必須在幾毫秒內等待,然後才能重試。retry_after_ms

11 模組

模組是用戶端-伺服器 API 的一部分,並非通用 所有終結點。模組在此規範中嚴格定義 並且不應被誤認為是實驗性擴展或可選擴展 特徵。相容的伺服器實現必須支援所有模組和 支援規範(除非實現僅針對用戶端 某些配置檔,在這種情況下,只有那些配置檔所需的模組 必須實現功能配置檔)。合規的客戶端實現 必須支援所有必需的模組和支持規範 它所針對的功能配置檔。

11.1 功能配置檔

矩陣支援許多不同類型的用戶端:來自嵌入式物聯網 設備到桌面用戶端。並非所有用戶端都可以提供相同的功能 設置為其他用戶端,例如由於缺少物理硬體,例如 有一個螢幕。用戶端可以屬於多個配置檔之一,每個配置檔 配置檔包含客戶端必須支援的一組功能。這 部分詳細介紹了一組'功能配置檔'。客戶應 完整地實現配置檔,以便將其分類為 該配置檔。

11.2 即時通訊

此模組增加了對向房間發送人類可讀消息的支援。 它還增加了對將人類可讀資訊與 房間本身,例如房間名稱和主題。

11.2.1 事件

m.room.message

在聊天室中發送消息時使用此事件。消息不限於文本。鍵概述了消息的類型,例如文本,音訊,圖像,視頻等。密鑰是文本,必須與各種一起使用,作為客戶端無法呈現消息時的回退機制。這允許客戶端顯示某些內容,即使它只是純文字。msgtypebodymsgtype

{
  "content": {
    "body": "This is an example text message",
    "format": "org.matrix.custom.html",
    "formatted_body": "<b>This is an example text message</b>",
    "msgtype": "m.text"
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.room.message",
  "unsigned": {
    "age": 1234
  }
}

11.2.2 客戶端行為

用戶端應驗證傳入事件的結構,以確保 預期的鍵存在,並且它們屬於正確的類型。客戶可以 放棄格式錯誤的事件或向用戶顯示佔位元消息。 必須從用戶端中刪除已編輯的'm.room.message'事件。這 可以用佔位元文本替換(例如"[已編輯]")或 可以從郵件檢視中完全刪除已編輯的郵件。

包含附件的事件(例如"m.image","m.file")應該是 使用 [內容存儲庫模組](#content存储库)上傳 如果可用。然後,可以在"url"中使用生成的"mxc://"URI 。.key。

用戶端可以包含用戶端生成的附件縮圖 在"info.thumbnail_url"鍵下。縮圖也應該是 "mxc://"烏里。顯示帶有附件的事件的用戶端可以使用 用戶端生成的縮圖或要求其主伺服器生成 原始附件中的縮圖,使用 [內容存儲庫 模組](#content存储库)。

發送消息時的建議

如果發送失敗,用戶端應使用 一定時間 T 的指數退避演算法。是的 建議 T 不超過 5 分鐘。在此之後, 用戶端應停止重試並將消息標記為'未發送'。使用者 應該能夠手動重新發送未發送的消息。

用戶可以一次鍵入多條消息並快速發送所有消息 繼承。用戶端應保留發送它們的順序 使用者。這意味著客戶端應等待對 發送下一個請求之前的上一個請求。這可能導致 線頭阻塞。為了減少線頭的影響 阻塞,用戶端應使用每個房間的佇列,而不是全域佇列 佇列,因為訂購僅在單個房間內相關,而不是 房間之間。

本地回聲

當使用者使用時,消息應立即顯示在消息檢視中 按下'發送'按鈕。即使消息是 仍在發送。這稱為'本地回聲'。客戶應該 實現消息的'本地回顯'。用戶端可以在 不同的格式,以指示伺服器尚未處理 消息。伺服器回應時應刪除此格式。

用戶端需要能夠將他們發送的消息與 他們從事件流收到的消息相同。回聲 來自事件流的同一消息稱為'遠端回聲'。。雙 回聲需要標識為同一消息,以防止 顯示重複消息。理想情況下,這種配對會發生 對使用者透明:UI 在轉換時不會閃爍 從本地到遠端。可以通過用戶端使閃爍減少 使用他們用於發送特定事件的事務ID。這 使用的交易 ID 將包含在事件的'未簽名'數據中,作為 當它通過事件流到達時transaction_id。

無法使用交易 ID 的用戶端可能會 當遠端回聲到達事件流時體驗閃爍 發送消息的請求完成之前。在這種情況下, 事件在客戶端獲取事件 ID 之前到達,使其 無法將其識別為遠端回聲。這會導致用戶端 在一段時間內顯示兩次消息(取決於伺服器) 回應能力)在原始請求發送消息之前 完成。完成後,客戶端可以採取補救措施來 通過查找重複的事件ID來刪除重複的事件。

計算使用者的顯示名稱

用戶端可能希望顯示房間的人類可讀顯示名稱 成員身份,或當他們發送消息時。 但是,不同的成員可能具有衝突的顯示名稱。顯示 在向用戶顯示名稱之前,必須消除名稱的歧義,以便 防止欺騙其他使用者。

為了確保跨用戶端一致地執行此操作,用戶端應使用 以下演算法用於計算 給定使用者:

  1. 檢查相關使用者 ID 的"m.room.member"狀態事件。
  2. 如果"m.room.member"狀態事件沒有"顯示名稱"字段,或者如果 該欄位具有'null' 值,請使用原始使用者 ID 作為顯示 名字。否則:
  3. 如果"m.room.member"事件具有唯一的"顯示名稱" 在具有'成員資格:加入'或 "成員資格:邀請",使用給定的"顯示名稱"作為 用戶可見的顯示名稱。否則:
  4. "m.room.member"事件具有非唯一的"顯示名稱"。這 應使用使用者ID消除歧義,例如"顯示名稱 (@id:homeserver.org)"。

開發人員在實現上述內容時應注意以下事項 演算法:

  • 一個成員的用戶可見顯示名稱可能受到以下因素的影響 另一個成員的狀態更改。例如,如果 "@user1:matrix.org"出現在一個房間里,帶有"顯示名稱:愛麗絲", 然後當"@user2:示例.com"加入房間時,也與 "顯示名稱:愛麗絲",兩個用戶必須消除歧義 顯示名稱。同樣,當其中一個使用者隨後更改其 顯示名稱,不再有衝突,兩個用戶可以 給定他們選擇的顯示名稱。客戶應對此保持警惕 可能性並確保所有受影響的使用者都正確 重新命名。
  • 聊天室的顯示名稱也可能受到 成員名單。這是由於房間名稱有時是基於 在使用者顯示名稱上(請參閱 [計算 的顯示名稱 房間](#calculating房间的显示名称))。
  • 如果搜索整個成員身份清單以顯示衝突 名稱,這導致用於構建清單的 O(N^2) 實現 的房間成員。對於大型房間來說,這將非常低效 成員人數。建議客戶端實現 維護從'顯示名稱'到房間清單的哈希表映射 使用該名稱的成員。然後可以使用這樣的表來有效地 計算是否需要消除歧義。
使用消息顯示成員身份資訊

客戶可能希望顯示房間的顯示名稱和頭像URL 發送消息的成員。這可以通過檢查 該使用者 ID 的"m.room.member"狀態事件(請參閱 [計算 用戶的顯示名稱](#calculating用户的显示名称))。

當使用者對郵件歷史記錄進行分頁時,用戶端可能希望顯示 聊天室成員的顯示名稱和頭像URL。這是 可能是因為較舊的'm.room.member'事件在以下情況下返回 分頁。這可以通過保留兩組 房間狀態:舊和當前。隨著新事件的到來和/或使用者 時光倒流,這兩組狀態彼此分道揚鑣。 新事件更新當前狀態,分頁事件更新舊狀態 州。按順序處理分頁事件時,舊狀態 表示發送事件時聊天室的狀態*。這 然後可用於設置歷史顯示名稱和頭像URL。

計算聊天室的顯示名稱

客戶可能希望為房間顯示人類可讀的名稱。有一個 選擇有用名稱的可能性數量。確保房間 在用戶端中一致命名,用戶端應使用以下名稱 選擇名稱的演演算法:

  1. 如果聊天室具有非空的 [m.room.name](#mroomname) 狀態事件 "名稱"欄位,請使用該欄位指定的名稱。
  2. 如果聊天室具有 [m.room.canonical_alias](#mroomcanonical_alias) 狀態事件,並且 有效的"別名"欄位,使用該字段給出的別名作為名稱。 請注意,客戶端在計算時應避免使用"alt_aliases" 房間名稱。 3.如果以上條件都不滿足,則應組成一個名稱 基於房間的成員。客戶應考慮 [m.room.member](#mroommember) 登錄使用者以外的使用者的事件,如 定義如下。
    1. 如果房間的'm.hero'數量大於或等於 "m.joined_member_count + m.invited_member_count - 1",然後使用 英雄計算顯示名稱的成員資格事件 對於使用者([消除歧義,如果 必需](#calculating用户的显示名称))和 將它們連接起來。例如,客戶可以選擇顯示 "Alice, Bob, and Charlie (@charlie:example.org)"作為房間 名字。用戶端可以選擇限制其用戶數 用於生成房間名稱。
    2. 如果英雄少於 "m.joined_member_count + m.invited_member_count - 1",以及 "m.joined_member_count + m.invited_member_count"大於 1,用戶端應使用英雄來計算顯示名稱 對於使用者([消除歧義,如果 必需](#calculating用户的显示名称))和 將它們與剩餘使用者的計數連接起來。為 例如,"愛麗絲,鮑勃和其他 1234 人"。
    3. 如果"m.joined_member_count + m.invited_member_count"小於 或等於 1(表示成員是單獨的),用戶端 應使用上述規則來指示房間是空的。 例如,'空房間(是愛麗絲)','空房間(是愛麗絲) 和其他 1234 人)",如果沒有英雄,則為"空房間"。

客戶應將房間名稱國際化為用戶的語言 當使用"m.heroes"計算名稱時。用戶端應使用 在可能的情況下,至少 5 個英雄來計算房間名稱,但可以使用 或多或少是為了更好地適應他們的用戶體驗。

劇透消息

通過使用劇透,可以直觀地向用戶隱藏消息的某些部分。 這不會影響伺服器對事件內容的表示 - 它 只是向使用者提供視覺提示,消息可能會揭示重要內容 有關某事的信息,破壞任何相關的驚喜。

要發送劇透,客戶必須使用"formatted_body",因此 "org.matrix.custom.html"格式,如上所述。這使得劇透在 任何可以適當支援此格式的"msgtype"。

劇透本身包含'span'標籤,原因(可選) 處於'數據-MX-劇透'屬性中。無故劇透必須至少 指定屬性,但該值可能為空/未定義。

劇透的一個例子是:

{
  "msgtype": "m.text",
  "format": "org.matrix.custom.html",
  "body": "電影中的愛麗絲[劇透](mxc://example.org/abc123)。
  "formatted_body": "愛麗絲<跨數據-mx-劇透>從此過上了幸福的生活</跨度>在電影中。
}

如果要提供原因,它將如下所示:

{
  "msgtype": "m.text",
  "format": "org.matrix.custom.html",
  "body": "愛麗絲[愛麗絲的健康劇透](mxc://example.org/abc123)在電影中。
  "formatted_body": "愛麗絲<跨度數據-mx-spoiler='愛麗絲的健康'>從此過上了幸福的生活</跨度>。
}

發送劇透時,用戶端應在"正文"中提供回退,如上所示 (包括原因)。回退不應包含包含劇透的文本,因為 "body"可能會顯示在純文本用戶端或通知中。為防止劇透出現在 在這種情況下,強烈建議客戶先上傳包含劇透的文本 到媒體存儲庫,然後在 markdown 樣式的連結中引用"mxc://"URI,如上所示。

客戶應該通過某種披露以不同的方式呈現劇透。例如, 用戶端可以模糊實際文本並要求用戶按兩下它以顯示它。

伺服器行為

主伺服器應拒絕沒有 "msgtype"鍵,或者沒有文本"body"鍵,帶有 HTTP 狀態代碼為 400。

安全注意事項

使用此模組發送的消息未加密,儘管是端到端的 加密正在開發中(請參閱 [E2E 模組](#end 端到端加密))。

用戶端應清理所有顯示的密鑰以查找不安全的HTML 防止跨網站腳稿 (XSS) 攻擊。這包括房間名稱和 主題。

11.3 豐富的回復

豐富的回復是一個 特殊類型的[關係](#forming-事件之間的關係-事件之間) 有效地引用引用的事件,以便用戶端呈現/處理如何 它希望。它們通常與 ['m.room.message'](#mroommessage) 事件一起使用。

在規範的 v1.3 之前,豐富的回復僅限於"m.room.message"事件 它可以表示 HTML 格式的正文。從 v1.3 開始,現在已擴展 到 all 事件類型,通過放棄 HTML 格式的正文的要求 被包括在內。

此外,豐富的回復可以引用自 v1.3 起的任何其他事件類型。 以前,豐富的回復只能引用另一個"m.room.message"事件。

如果可能,事件應包括 [回退表示形式](#fallbacks-for-rich-replies) 允許不呈現富回復的用戶端仍然看到以下內容 似乎是引用的答覆。

儘管豐富的回復與另一個事件形成關係,但它們不會 使用"rel_type"創建此關係。而是名為"m.in_reply_to"的子項 用於描述回復的關係,保留 "m.relates_to"來描述事件的主要關係。這意味著 如果一個事件只是回復另一個事件,沒有進一步的關係, "m.relates_to"的"rel_type"和"event_id"屬性變為可選

一個範例回復是:

{
  "內容": {
    "m.relates_to": {
      "m.in_reply_to": {
        "event_id": "$another_事件"
      }
    },
    "body": "這聽起來是個好主意!
  },
  事件所需的其他欄位
}

請注意,"m.in_reply_to"物件的"event_id"具有相同的要求 好像它直接在"m.relates_to"下。

豐富回復的回退

某些用戶端可能不支持豐富的回復,因此需要 回退以改用。不支援富回復的用戶端應 將事件呈現為豐富的回復並不特別。

支援富回復的用戶端應提供回退格式 回復,並且必須在呈現回復之前剝離回退。這 每個"msgtype"的特定回退文本都不同,但是 "正文"的一般格式為:

> <@alice:example.org>這是原始正文
> 這是回復的地方

"formatted_body"(如果存在)並使用關聯的"格式" "org.matrix.custom.html"應使用以下範本:


<MX-回復>
    <塊引用>
        <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">回復</a>
        <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
        <BR/>
        <!--這是相關事件的 HTML 所在的位置。-->
    </塊引用>
</MX-回復>
這就是答覆的地方。

如果相關事件沒有"formatted_body",則事件的 在對任何 HTML 特殊字元進行編碼後,應考慮"body"。 請注意,兩個錨點中的"href"都使用 [matrix.to URI](/appendices#matrixto-navigation).

剝離回退

支援富回復的客戶端必須從 事件,然後呈現事件。這是因為 不能信任回退是 事件。刪除回退後,建議用戶端表示 "m.in_reply_to"引用的事件類似於回退的事件 表示,儘管客戶確實為其使用者提供了創作自由 介面。客戶應該更喜歡「formatted_body」而不是「body」, 就像其他"m.room.message"事件一樣。

要剝離"正文"上的回退,用戶端應遍歷每個 字串的行,刪除以回退開頭的任何行 前綴("> ",包括空格,不帶引號)並在以下情況下停止 遇到不帶前綴的行。此前綴稱為 回退前綴序列"。

若要剝離"formatted_body"上的回退,用戶端應刪除 整個"MX-回復"標記。

"m.text"、"m.notice"和無法識別的消息類型的回退

使用前綴序列,相關事件"正文"的第一行 應以使用者的 ID 為前綴,後跟每行 以回退前綴序列為前綴。例如:

> <@alice:example.org>這是第一行
> 這是第二行
> 這是回復

"formatted_body"使用本節前面定義的範本。

"m.emote"的回退

與"m.text"的回退類似,每行都以 回退前綴序列。但是,應在之前插入星號 使用者的ID,如下所示:

> * <@alice:example.org> 感覺今天將是美好的一天
    這是回復

"formatted_body"對於範本有一個細微的區別,其中 星號也插入到使用者的 ID 之前:


<MX-回復>
    <塊引用>
        <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">回復</a>

        * <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
        <BR/>

        <!--這是相關事件的 HTML 所在的位置。-->
    </塊引用>
</MX-回復>
這就是答覆的地方。

"m.image"、"m.video"、"m.audio"和"m.file"的回退

相關事件的"正文"將是一個檔名,可能不是很 描述。相關事件不應具有"格式" 或"內容"中的"formatted_body"——如果活動確實有"格式" 和/或"formatted_body",則應忽略這些欄位。因為 檔名本身可能不是描述性的,相關事件的"正文"應該 被視為「已發送檔」。' 使輸出看起來相似 到以下內容:

> <@alice:example.org>發送了一個檔。
這是回復

<MX-回復>
    <塊引用>
        <a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">回復</a>
        <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
        <BR/>
        發送了一個檔。
    </塊引用>
</MX-回復>
這就是答覆的地方。

對於"m.image",文本應為"發送圖像"。.對於「m.video」, 文本應為「發送視頻」。.對於"m.audio",文本應為 「發送音訊檔」。。

11.4 IP 語音

本模組概述了房間中的兩個使用者如何設置IP語音 (VoIP)互相呼叫。語音和視頻通話建立在 WebRTC 1.0標準。呼叫信令是通過發送 [消息] 來實現的 事件](#events)到房間。在此版本的規範中,只有兩方 支援通信(例如,兩個對等體之間或對等體之間 和多點會議裝置)。這意味著用戶端只能 將呼叫事件發送到只有兩個參與者的聊天室。

11.4.1 事件

m.call.answer

此事件由被叫方在希望應答呼叫時發送

{
  "content": {
    "answer": {
      "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
      "type": "answer"
    },
    "call_id": "12345",
    "version": 0
  },
  "event_id": "$143273582443PhrSn:example.org",
  "origin_server_ts": 1432735824653,
  "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
  "sender": "@example:example.org",
  "type": "m.call.answer",
  "unsigned": {
    "age": 1234
  }
}

客戶端行為

使用交換的消息事件設置呼叫,如下所示:

來電者被叫方
[撥打電話]
m.call.invite ----------->
m.call.candidate -------->
[..候選人..]-------->
[接聽電話]
<--------------- m.call.answer
[通話正在進行中]
<--------------- m.call.hangup

或拒絕的呼叫:

來電者被叫方
m.call.invite ------------>
m.call.candidate --------->
[..候選人..]--------->
[拒絕來電]
<-------------- m.call.hangup

調用是根據WebRTC規範協商的。

眩光

"眩光"是兩個使用者在以下位置相互呼叫時出現的問題 大致在同一時間。這會導致呼叫無法設置為 已經有來電/去電。眩光解析度演算法 可用於確定要掛斷的呼叫和應答的呼叫。 如果兩個用戶端實現相同的演算法,則它們都將選擇 同一呼叫和呼叫將成功連接。

當呼叫被"下達"到房間而不是使用者時,眩光解析度 下面概述的演算法僅考慮用於對 同一個房間。演算法如下:

-如果收到房間的"m.call.invite",而客戶 準備向同一房間發送"m.call.invite": -用戶端應取消其傳出呼叫,改為 代表用戶自動接受傳入呼叫。 -如果收到房間的"m.call.invite"在用戶端有 已發送 "m.call.invite"到同一房間,正在等待 回應: -客戶應執行 兩個呼叫的呼叫ID,並使用兩個呼叫中的較小, 流產越大。如果來電較小,則 用戶端應代表使用者接受此調用。

呼叫設置應該對用戶顯示無縫,就好像他們只是簡單地 打了個電話,對方接聽了。這意味著任何媒體 應轉移已設置為用於呼叫的流,並且 用於替換它的調用。

11.4.3 伺服器行為

主伺服器可以提供用戶端可以使用的 TURN 伺服器 聯繫遠端方。將使用以下 HTTP API 端點 用戶端以獲取有關 TURN 伺服器的資訊。

11.4.4 安全注意事項

只能向具有另一個用戶的房間發出呼叫。如果 它們被放置在群聊室中,可能是其他使用者 將攔截並接聽電話。

11.5 鍵入通知

使用者可能希望在其他用戶在房間內鍵入內容時收到通知。 這可以通過鍵入通知來實現。這些是短暫的 事件,因此它們不構成 [事件圖](/#event图)。鍵入通知的範圍限定 到一個房間。

事件

m.typing

通知用戶端目前正在鍵入的用戶清單。

{
  "content": {
    "user_ids": [
      "@alice:matrix.org",
      "@bob:example.com"
    ]
  },
  "type": "m.typing"
}

客戶端行為

當用戶端收到「m.typing」事件時,它必須使用使用者 ID 清單 替換當前正在鍵入的每個用戶的知識。這 原因是伺服器不記得不是的使用者 目前輸入,因為該清單很快就會變大。客戶應標記 因為不鍵入不在該清單中的任何使用者ID。

建議用戶端存儲一個「布爾值」 指示是否 使用者是否正在鍵入。雖然此值為"true",但計時器應觸發 定期每 N 秒發送一次鍵入的 HTTP 請求。的價值 N建議不超過20-30秒。此請求應 由用戶端重新發送以繼續通知伺服器使用者是 還在打字。由於後續請求將替換舊請求,因此 預期超時用完前 5 秒的安全裕度為 推薦。當使用者停止鍵入時,狀態更改 "布爾"到"假"應該觸發另一個HTTP請求來通知 使用者已停止鍵入的伺服器。

PUT /_matrix/client/v3/rooms/{roomId}/typing/{userId}

這告訴伺服器使用者正在鍵入下一個 N 毫秒,其中 N 是鍵中指定的值。 或者,如果是 ,它告訴伺服器 使用者已停止鍵入。timeouttypingfalse

請求正文示例

{
  "timeout": 30000,
  "typing": true
}

安全注意事項

客戶可能不希望通知房間里的每個人他們正在打字 而是僅會議室中的特定使用者。

11.6 收據

{{< changed-in v="1.4" >}}添加了私人已讀回執。

此模組增加了對收據的支援。這些收據是 事件確認。此模組定義「m.read」收據 用於指示使用者已讀取給定事件,以及"m.read.private" 在沒有任何其他使用者知道的情況下達到相同的目的。主要 "m.read.private"旨在清除[通知](#receiving-通知) 沒有向他人宣傳讀到狀態。

為每個事件發送收據可能會導致發送大量 到主伺服器的流量。為了防止這成為一個問題, 收據是使用"最多"標記實現的。此標記指示 確認適用於"之前並包括"的所有事件 指定的事件。例如,將事件標記為「已讀」 將指示 用戶已讀取所有事件直到引用的事件。請參閱的 [接收通知](#receiving-通知)部分瞭解更多資訊 有關已讀回執如何影響通知計數的資訊。

{{< add-in v="1.4" >}}已讀回執主要有三種形式: 無線程:表示讀取到接收,而不考慮線程。這就是 預線程化已讀回執有效。 線程,主時間線:表示不在 特定線程。由線程ID MAin識別。 *線程,在線程中:表示特定線程中的讀到接收 線。由線程根的事件ID標識。

線程式讀回執將在下面進一步詳細討論(#threaded-已讀回執)。

事件

{{< changed-in v="1.4" >}}每個"user_id"、"receipt_type"和分類 (無線程或"thread_id")元組必須僅與單個元組關聯 "event_id"。

m.receipt

通知客戶新收據。

{
  "content": {
    "$1435641916114394fHBLK:matrix.org": {
      "m.read": {
        "@rikj:jki.re": {
          "ts": 1436451550453
        }
      },
      "m.read.private": {
        "@self:example.org": {
          "ts": 1661384801651
        }
      }
    }
  },
  "type": "m.receipt"
}

客戶端行為

{{< changed-in v="1.4" >}}已更改以支援線程式已讀回執。

在"/sync"中,收據列在"臨時"事件陣列下 對於給定的房間。事件流中的新收據是 更新現有映射的增量。用戶端應替換舊的 基於"user_id"、"receipt_type"和 "thread_id"(如果存在)。 例如:

Client receives m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $aaa:example.com
  thread_id = undefined

Client receives another m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $bbb:example.com
  thread_id = main

The client does not replace any acknowledgements, yet.

Client receives yet another m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $ccc:example.com
  thread_id = undefined

The client replaces the older acknowledgement for $aaa:example.com
with this new one for $ccc:example.com, but does not replace the
acknowledgement for $bbb:example.com because it belongs to a thread.

Client receives yet another m.receipt:
  user = @alice:example.com
  receipt_type = m.read
  event_id = $ddd:example.com
  thread_id = main

Now the client replaces the older $bbb:example.com acknowledgement with
this new $ddd:example.com acknowledgement. The client does NOT replace the
older acknowledgement for $ccc:example.com as it is unthreaded.

當確定 有問題的事件已向用戶顯示。只需接收 事件不能提供足夠的確定性,表明用戶已經看到了 事件。用戶應該需要採取一些操作,例如查看 事件發送到的房間或按順序關閉通知 使事件計為「已讀」。用戶端不應發送已讀回執 對於自己的用戶發送的事件。

與發送回執的規則類似,應顯示線程回執 在線程的上下文中。如果線程呈現在披露後面, 用戶端尚未顯示事件(或任何適用的已讀回執) 給使用者。但是,一旦他們擴展了線程,線程已讀回執 將發送並顯示來自其他使用者的每個線程的收據。

用戶端可以通過與 遵循 HTTP API。

POST /_matrix/client/v3/rooms/{roomId}/receipt/{receiptType}/{eventId}

此 API 將給定收據類型的標記更新為事件 ID 指定。

請求正文示例

{
  "thread_id": "main"
}
私人已讀回執

{{% add-in v="1.4" %}}

一些使用者希望將房間標記為已讀,清除其[通知計數](#receiving通知), 但不要洩露他們已經閱讀了特定消息的事實。自 為此,用戶端可以發送「m.read.private」收據而不是「m.read」。 要做到這一點:清除通知,不要將收據廣播到 其他使用者。

伺服器不得將「m.read.private」收據發送給除 一個最初發送它。

在"m.read"和"m.read.private"之間,收據更"領先"或 在確定最高讀數標記時使用"最近"。請參閱的 [通知](#receiving-通知)部分,以獲取更多資訊 這對通知計數有何影響。

如果客戶端發送"m.read"收據,該收據位於"m.read.private"的"後面" 收到,其他使用者將看到更改發生,但發送使用者將 不會將其通知計數倒回該時間點。而 不常見,"m.read"(公共)接收滯後被認為是有效的 例如,"m.read.private"收據後面的幾條消息。

線程式讀回執

{{% add-in v="1.4" %}}

如果用戶端不使用 [threading](#threading),那麼它們只會 發送「無線程」已讀回執,無論線程如何,都會影響整個房間。

線程式已讀回執只是帶有"thread_id"的回執,目標 線程根的事件 ID 或主時間線的"main"。

線程引入了在同一會話中進行多個對話的概念 房間,因此值得自己的已讀回執和通知計數。事件是 如果滿足以下任何條件,則被視為「在線程中」: 它的"rel_type"為"m.thread"。 它具有"rel_type"為"m.thread"的子事件(在這種情況下,它將是 線程根)。 *在事件關係之後,它有一個父事件,該父事件符合 以上之一。但是,實現不應該無限遞歸:a 建議最多使用 3 個躍點以涵蓋間接關係。

不在線程中但仍在房間中的事件被視為 "主時間線",或ID為"main"的特殊線程。

下面是一個聊天室的示例 DAG,虛線表示事件 關係和顯示拓撲排序的實線。

此 DAG 可以表示為 3 個線程時間線,其中"A"和"B"是線程 根:

有了這個,我們可以證明: "I"上的線程已讀回執會將"A"、"B"和"I"標記為已讀。 "E"上的線程已讀回執會將"C"和"E"標記為已讀。 *"D"上的非線程已讀回執會將"A"、"B"、"C"和"D"標記為已讀。

請注意,使用線程已讀回執將"A"標記為已讀並不意味著 "C"、"E"、"G"或"H"被標記為已讀:線程 A 的時間線需要 它自己的線程讀取回執位於「H」處以實現此目的。

上述 3 個範例的已讀回執為:

{
  "$I": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651,
        "thread_id": "main" // because `I` is not in a thread, but is a threaded receipt
      }
    }
  },
  "$E": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651,
        "thread_id": "$A" // because `E` is in Thread `A`
      }
    }
  },
  "$D": {
    "m.read": {
      "@user:example.org": {
        "ts": 1661384801651
        // no `thread_id` because the receipt is *unthreaded*
      }
    }
  }
}

發送已讀回執的條件與線程和非線程讀取類似 收益。例如,用戶端可能會為線程發送專用已讀回執 用戶展開該線程時的事件。

伺服器行為

為了提高效率,收據應分批到每個房間的一個事件中 在將它們交付給客戶之前。

某些收據作為類型為「m.receipt」的EDU通過聯合發送。這 EDU 格式為:

{
    <room_id>: {
        <receipt_type>: {
            <user_id>: { <content (ts & thread_id, currently)> }
        },
        ...
    },
    ...
}

這些始終作為增量發送到以前發送的回執。現在 只應使用單個"":"m.read"。'm.read.private' 不得出現在此聯合"m.receipt"教育中。

安全注意事項

由於收據是在事件圖的上下文之外發送的,因此存在 未對「m.receipt」事件的內容執行完整性檢查。