-
Matthew Hodgson authoredMatthew Hodgson authored
Matrix Server-to-Server API
A description of the protocol used to communicate between Matrix home servers; also known as Federation.
Overview
The server-server API is a mechanism by which two home servers can exchange Matrix event messages, both as a real-time push of current events, and as a historic fetching mechanism to synchronise past history for clients to view. It uses HTTP connections between each pair of servers involved as the underlying transport. Messages are exchanged between servers in real-time by active pushing from each server's HTTP client into the server of the other. Queries to fetch historic data for the purpose of back-filling scrollback buffers and the like can also be performed.
- { Matrix clients } { Matrix clients }
- ^ | ^ | | events | | events | | V | V
+------------------+ +------------------+ | |---------( HTTP )---------->| | | Home Server | | Home Server | | |<--------( HTTP )-----------| | +------------------+ +------------------+
There are three main kinds of communication that occur between home servers:
- Queries These are single request/response interactions between a given pair of servers, initiated by one side sending an HTTP request to obtain some information, and responded by the other. They are not persisted and contain no long-term significant history. They simply request a snapshot state at the instant the query is made.
- EDUs - Ephemeral Data Units These are notifications of events that are pushed from one home server to another. They are not persisted and contain no long-term significant history, nor does the receiving home server have to reply to them.
- PDUs - Persisted Data Units These are notifications of events that are broadcast from one home server to any others that are interested in the same "context" (namely, a Room ID). They are persisted to long-term storage and form the record of history for that context.
Where Queries are presented directly across the HTTP connection as GET requests to specific URLs, EDUs and PDUs are further wrapped in an envelope called a Transaction, which is transferred from the origin to the destination home server using a PUT request.
Transactions and EDUs/PDUs
The transfer of EDUs and PDUs between home servers is performed by an exchange of Transaction messages, which are encoded as JSON objects with a dict as the top-level element, passed over an HTTP PUT request. A Transaction is meaningful only to the pair of home servers that exchanged it; they are not globally- meaningful.
Each transaction has an opaque ID and timestamp (UNIX epoch time in milliseconds) generated by its origin server, an origin and destination server name, a list of "previous IDs", and a list of PDUs - the actual message payload that the Transaction carries.
- {"transaction_id":"916d630ea616342b42e98a3be0b74113",
- "ts":1404835423000, "origin":"red", "destination":"blue", "prev_ids":["e1da392e61898be4d2009b9fecce5325"], "pdus":[...], "edus":[...]}
The "previous IDs" field will contain a list of previous transaction IDs that the origin server has sent to this destination. Its purpose is to act as a sequence checking mechanism - the destination server can check whether it has successfully received that Transaction, or ask for a retransmission if not.
The "pdus" field of a transaction is a list, containing zero or more PDUs.[*] Each PDU is itself a dict containing a number of keys, the exact details of which will vary depending on the type of PDU. Similarly, the "edus" field is another list containing the EDUs. This key may be entirely absent if there are no EDUs to transfer.
(* Normally the PDU list will be non-empty, but the server should cope with receiving an "empty" transaction, as this is useful for informing peers of other transaction IDs they should be aware of. This effectively acts as a push mechanism to encourage peers to continue to replicate content.)
All PDUs have an ID, a context, a declaration of their type, a list of other PDU IDs that have been seen recently on that context (regardless of which origin sent them), and a nested content field containing the actual event content.
[[TODO(paul): Update this structure so that 'pdu_id' is a two-element [origin,ref] pair like the prev_pdus are]]
- {"pdu_id":"a4ecee13e2accdadf56c1025af232176",
- "context":"#example.green", "origin":"green", "ts":1404838188000, "pdu_type":"m.text", "prev_pdus":[["blue","99d16afbc857975916f1d73e49e52b65"]], "content":... "is_state":false}