Newer
Older
Paul "LeoNerd" Evans
committed
"membership": "ban"
}
Kegan Dougal
committed
Paul "LeoNerd" Evans
committed
Events in a room
----------------
Room events can be split into two categories:
Paul "LeoNerd" Evans
committed
:State Events:
These are events which replace events that came before it, depending on a set
of unique keys. These keys are the event ``type`` and a ``state_key``.
Events with the same set of keys will be overwritten. Typically, state events
are used to store state, hence their name.
Paul "LeoNerd" Evans
committed
:Non-state events:
These are events which cannot be overwritten after sending. The list of
events continues to grow as more events are sent. As this list grows, it
becomes necessary to provide a mechanism for navigating this list. Pagination
APIs are used to view the list of historical non-state events. Typically,
non-state events are used to send messages.
Paul "LeoNerd" Evans
committed
This specification outlines several events, all with the event type prefix
``m.``. However, applications may wish to add their own type of event, and this
can be achieved using the REST API detailed in the following sections. If new
events are added, the event ``type`` key SHOULD follow the Java package naming
convention, e.g. ``com.example.myapp.event``. This ensures event types are
suitably namespaced for each application and reduces the risk of clashes.
State events
Kegan Dougal
committed
------------
Paul "LeoNerd" Evans
committed
State events can be sent by ``PUT`` ing to
|/rooms/<room_id>/state/<event_type>/<state_key>|_. These events will be
overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match.
If the state event has no ``state_key``, it can be omitted from the path. These
requests **cannot use transaction IDs** like other ``PUT`` paths because they
cannot be differentiated from the ``state_key``. Furthermore, ``POST`` is
unsupported on state paths. Valid requests look like::
Kegan Dougal
committed
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.example.event
{ "key" : "without a state key" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
{ "key" : "with 'foo' as the state key" }
Paul "LeoNerd" Evans
committed
In contrast, these requests are invalid::
Paul "LeoNerd" Evans
committed
POST /rooms/!roomid:domain/state/m.example.event/
{ "key" : "cannot use POST here" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
{ "key" : "txnIds are not supported" }
Paul "LeoNerd" Evans
committed
Care should be taken to avoid setting the wrong ``state key``::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/11
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
Paul "LeoNerd" Evans
committed
The ``state_key`` is often used to store state about individual users, by using
the user ID as the ``state_key`` value. For example::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com
{ "animal" : "cat", "reason": "fluffy" }
Paul "LeoNerd" Evans
committed
In some cases, there may be no need for a ``state_key``, so it can be omitted::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.room.bgd.color
{ "color": "red", "hex": "#ff0000" }
Paul "LeoNerd" Evans
committed
See `Room Events`_ for the ``m.`` event specification.
Paul "LeoNerd" Evans
committed
Non-state events
----------------
Non-state events can be sent by sending a request to
|/rooms/<room_id>/send/<event_type>|_. These requests *can* use transaction
IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical
events and pagination, making it best suited for sending messages. For
example::
Paul "LeoNerd" Evans
committed
POST /rooms/!roomid:domain/send/m.custom.example.message
{ "text": "Hello world!" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/send/m.custom.example.message/11
{ "text": "Goodbye world!" }
Paul "LeoNerd" Evans
committed
See `Room Events`_ for the ``m.`` event specification.
Paul "LeoNerd" Evans
committed
Syncing rooms
-------------
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
When a client logs in, they may have a list of rooms which they have already
joined. These rooms may also have a list of events associated with them. The
purpose of 'syncing' is to present the current room and event information in a
convenient, compact manner. The events returned are not limited to room events;
presence events will also be returned. A single syncing API is provided:
Paul "LeoNerd" Evans
committed
- |initialSync|_ : A global sync which will present room and event information
for all rooms the user has joined.
.. TODO-spec room-scoped initial sync
Paul "LeoNerd" Evans
committed
- |/rooms/<room_id>/initialSync|_ : A sync scoped to a single room. Presents
room and event information for this room only.
- Room-scoped initial sync is Very Tricky because typically people would
want to sync the room then listen for any new content from that point
onwards. The event stream cannot do this for a single room currently.
As a result, commenting room-scoped initial sync at this time.
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
The |initialSync|_ API contains the following keys:
``presence``
Description:
Contains a list of presence information for users the client is interested
in.
Format:
A JSON array of ``m.presence`` events.
``end``
Description:
Contains an event stream token which can be used with the `Event Stream`_.
Format:
A string containing the event stream token.
``rooms``
Description:
Contains a list of room information for all rooms the client has joined,
and limited room information on rooms the client has been invited to.
Format:
A JSON array containing Room Information JSON objects.
Room Information:
Description:
Contains all state events for the room, along with a limited amount of
the most recent non-state events, configured via the ``limit`` query
parameter. Also contains additional keys with room metadata, such as the
``room_id`` and the client's ``membership`` to the room.
Format:
A JSON object with the following keys:
``room_id``
A string containing the ID of the room being described.
``membership``
A string representing the client's membership status in this room.
``messages``
An event stream JSON object containing a ``chunk`` of recent non-state
events, along with an ``end`` token. *NB: The name of this key will be
changed in a later version.*
``state``
A JSON array containing all the current state events for this room.
Paul "LeoNerd" Evans
committed
Getting events for a room
-------------------------
There are several APIs provided to ``GET`` events for a room:
Paul "LeoNerd" Evans
committed
``/rooms/<room id>/state/<event type>/<state key>``
Description:
Get the state event identified.
Response format:
A JSON object representing the state event **content**.
Example:
``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }``
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/state|_
Description:
Get all state events for a room.
Response format:
``[ { state event }, { state event }, ... ]``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/members|_
Description:
Get all ``m.room.member`` state events.
Response format:
``{ "start": "<token>", "end": "<token>", "chunk": [ { m.room.member event }, ... ] }``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/messages|_
Description:
Get all ``m.room.message`` and ``m.room.member`` events. This API supports
pagination using ``from`` and ``to`` query parameters, coupled with the
``start`` and ``end`` tokens from an |initialSync|_ API.
Response format:
``{ "start": "<token>", "end": "<token>" }``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/initialSync|_
Description:
Get all relevant events for a room. This includes state events, paginated
non-state events and presence events.
Paul "LeoNerd" Evans
committed
Response format:
Paul "LeoNerd" Evans
committed
`` { TODO-doc } ``
Paul "LeoNerd" Evans
committed
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Since events are extensible it is possible for malicious users and/or servers
to add keys that are, for example offensive or illegal. Since some events
cannot be simply deleted, e.g. membership events, we instead 'redact' events.
This involves removing all keys from an event that are not required by the
protocol. This stripped down event is thereafter returned anytime a client or
remote server requests it.
Events that have been redacted include a ``redacted_because`` key whose value
is the event that caused it to be redacted, which may include a reason.
Redacting an event cannot be undone, allowing server owners to delete the
offending content from the databases.
Currently, only room admins can redact events by sending a ``m.room.redaction``
event, but server admins also need to be able to redact events by a similar
mechanism.
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
Upon receipt of a redaction event, the server should strip off any keys not in
the following list:
- ``event_id``
- ``type``
- ``room_id``
- ``user_id``
- ``state_key``
- ``prev_state``
- ``content``
The content object should also be stripped of all keys, unless it is one of
one of the following event types:
- ``m.room.member`` allows key ``membership``
- ``m.room.create`` allows key ``creator``
- ``m.room.join_rules`` allows key ``join_rule``
- ``m.room.power_levels`` allows keys that are user ids or ``default``
- ``m.room.add_state_level`` allows key ``level``
- ``m.room.send_event_level`` allows key ``level``
- ``m.room.ops_levels`` allows keys ``kick_level``, ``ban_level``
and ``redact_level``
- ``m.room.aliases`` allows key ``aliases``
The redaction event should be added under the key ``redacted_because``.
When a client receives a redaction event it should change the redacted event
in the same way a server does.
Paul "LeoNerd" Evans
committed
Room Events
===========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
This specification outlines several standard event types, all of which are
prefixed with ``m.``
Paul "LeoNerd" Evans
committed
``m.room.name``
Summary:
Set the human-readable name for the room.
Type:
State event
JSON format:
``{ "name" : "string" }``
Example:
``{ "name" : "My Room" }``
Description:
A room has an opaque room ID which is not human-friendly to read. A room
alias is human-friendly, but not all rooms have room aliases. The room name
is a human-friendly string designed to be displayed to the end-user. The
room name is not *unique*, as multiple rooms can have the same room name
set. The room name can also be set when creating a room using |createRoom|_
with the ``name`` key.
Paul "LeoNerd" Evans
committed
``m.room.topic``
Summary:
Set a topic for the room.
Type:
State event
JSON format:
``{ "topic" : "string" }``
Example:
``{ "topic" : "Welcome to the real world." }``
Description:
A topic is a short message detailing what is currently being discussed in
the room. It can also be used as a way to display extra information about
the room, which may not be suitable for the room name. The room topic can
also be set when creating a room using |createRoom|_ with the ``topic``
key.
Paul "LeoNerd" Evans
committed
``m.room.member``
Summary:
The current membership state of a user in the room.
Type:
State event
JSON format:
``{ "membership" : "enum[ invite|join|leave|ban ]" }``
Example:
``{ "membership" : "join" }``
Description:
Adjusts the membership state for a user in a room. It is preferable to use
the membership APIs (``/rooms/<room id>/invite`` etc) when performing
membership actions rather than adjusting the state directly as there are a
restricted set of valid transformations. For example, user A cannot force
user B to join a room, and trying to force this state change directly will
fail. See the `Rooms`_ section for how to use the membership APIs.
Paul "LeoNerd" Evans
committed
``m.room.create``
Summary:
The first event in the room.
Type:
State event
JSON format:
``{ "creator": "string"}``
Example:
``{ "creator": "@user:example.com" }``
Description:
This is the first event in a room and cannot be changed. It acts as the
root of all other events.
Paul "LeoNerd" Evans
committed
``m.room.join_rules``
Summary:
Descripes how/if people are allowed to join.
Type:
State event
JSON format:
``{ "join_rule": "enum [ public|knock|invite|private ]" }``
Example:
``{ "join_rule": "public" }``
Description:
Paul "LeoNerd" Evans
committed
TODO-doc : Use docs/models/rooms.rst
Paul "LeoNerd" Evans
committed
``m.room.power_levels``
Summary:
Defines the power levels of users in the room.
Type:
State event
JSON format:
``{ "<user_id>": <int>, ..., "default": <int>}``
Example:
``{ "@user:example.com": 5, "@user2:example.com": 10, "default": 0 }``
Description:
If a user is in the list, then they have the associated power level.
Otherwise they have the default level. If not ``default`` key is supplied,
it is assumed to be 0.
Paul "LeoNerd" Evans
committed
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
``m.room.add_state_level``
Summary:
Defines the minimum power level a user needs to add state.
Type:
State event
JSON format:
``{ "level": <int> }``
Example:
``{ "level": 5 }``
Description:
To add a new piece of state to the room a user must have the given power
level. This does not apply to updating current state, which is goverened
by the ``required_power_level`` event key.
``m.room.send_event_level``
Summary:
Defines the minimum power level a user needs to send an event.
Type:
State event
JSON format:
``{ "level": <int> }``
Example:
``{ "level": 0 }``
Description:
To send a new event into the room a user must have at least this power
level. This allows ops to make the room read only by increasing this level,
or muting individual users by lowering their power level below this
threshold.
Paul "LeoNerd" Evans
committed
``m.room.ops_levels``
Summary:
Defines the minimum power levels that a user must have before they can
kick and/or ban other users.
Type:
State event
JSON format:
``{ "ban_level": <int>, "kick_level": <int>, "redact_level": <int> }``
Paul "LeoNerd" Evans
committed
Example:
``{ "ban_level": 5, "kick_level": 5 }``
Description:
This defines who can ban and/or kick people in the room. Most of the time
``ban_level`` will be greater than or equal to ``kick_level`` since
banning is more severe than kicking.
Paul "LeoNerd" Evans
committed
``m.room.aliases``
Summary:
These state events are used to inform the room about what room aliases it
has.
Type:
State event
JSON format:
``{ "aliases": ["string", ...] }``
Example:
``{ "aliases": ["#foo:example.com"] }``
Description:
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
This event is sent by a homeserver directly to inform of changes to the
list of aliases it knows about for that room. As a special-case, the
``state_key`` of the event is the homeserver which owns the room alias.
For example, an event might look like::
{
"type": "m.room.aliases",
"event_id": "012345678ab",
"room_id": "!xAbCdEfG:example.com",
"state_key": "example.com",
"content": {
"aliases": ["#foo:example.com"]
}
}
The event contains the full list of aliases now stored by the home server
that emitted it; additions or deletions are not explicitly mentioned as
being such. The entire set of known aliases for the room is then the union
of the individual lists declared by all such keys, one from each home
server holding at least one alias.
Clients `should` check the validity of any room alias given in this list
before presenting it to the user as trusted fact. The lists given by this
event should be considered simply as advice on which aliases might exist,
for which the client can perform the lookup to confirm whether it receives
the correct room ID.
Paul "LeoNerd" Evans
committed
``m.room.message``
Summary:
A message.
Type:
Non-state event
JSON format:
``{ "msgtype": "string" }``
Example:
``{ "msgtype": "m.text", "body": "Testing" }``
Description:
This event is used when sending messages in a room. Messages are not
limited to be text. The ``msgtype`` key outlines the type of message, e.g.
text, audio, image, video, etc. Whilst not required, the ``body`` key
SHOULD be used with every kind of ``msgtype`` as a fallback mechanism when
a client cannot render the message. For more information on the types of
messages which can be sent, see `m.room.message msgtypes`_.
Paul "LeoNerd" Evans
committed
``m.room.message.feedback``
Summary:
A receipt for a message.
Type:
Non-state event
JSON format:
``{ "type": "enum [ delivered|read ]", "target_event_id": "string" }``
Example:
``{ "type": "delivered", "target_event_id": "e3b2icys" }``
Description:
Feedback events are events sent to acknowledge a message in some way. There
are two supported acknowledgements: ``delivered`` (sent when the event has
been received) and ``read`` (sent when the event has been observed by the
end-user). The ``target_event_id`` should reference the ``m.room.message``
event being acknowledged.
``m.room.redaction``
Summary:
Indicates a previous event has been redacted.
Type:
Non-state event
JSON format:
``{ "reason": "string" }``
Description:
Events can be redacted by either room or server admins. Redacting an event
means that all keys not required by the protocol are stripped off, allowing
admins to remove offensive or illegal content that may have been attached
to any event. This cannot be undone, allowing server owners to physically
delete the offending data. There is also a concept of a moderator hiding a
non-state event, which can be undone, but cannot be applied to state
events.
The event that has been redacted is specified in the ``redacts`` event
level key.
Paul "LeoNerd" Evans
committed
m.room.message msgtypes
-----------------------
.. TODO-spec
How a client should handle unknown message types.
Paul "LeoNerd" Evans
committed
Each ``m.room.message`` MUST have a ``msgtype`` key which identifies the type
of message being sent. Each type has their own required and optional keys, as
outlined below:
Paul "LeoNerd" Evans
committed
``m.text``
Required keys:
- ``body`` : "string" - The body of the message.
Optional keys:
None.
Example:
``{ "msgtype": "m.text", "body": "I am a fish" }``
Paul "LeoNerd" Evans
committed
``m.emote``
Required keys:
- ``body`` : "string" - The emote action to perform.
Optional keys:
None.
Example:
``{ "msgtype": "m.emote", "body": "tries to come up with a witty explanation" }``
Paul "LeoNerd" Evans
committed
``m.image``
Required keys:
- ``url`` : "string" - The URL to the image.
Optional keys:
- ``info`` : "string" - info : JSON object (ImageInfo) - The image info for
image referred to in ``url``.
- ``thumbnail_url`` : "string" - The URL to the thumbnail.
- ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
image referred to in ``thumbnail_url``.
- ``body`` : "string" - The alt text of the image, or some kind of content
description for accessibility e.g. "image attachment".
Paul "LeoNerd" Evans
committed
ImageInfo:
Information about an image::
{
"size" : integer (size of image in bytes),
"w" : integer (width of image in pixels),
"h" : integer (height of image in pixels),
"mimetype" : "string (e.g. image/jpeg)",
}
Paul "LeoNerd" Evans
committed
``m.audio``
Required keys:
- ``url`` : "string" - The URL to the audio.
Optional keys:
- ``info`` : JSON object (AudioInfo) - The audio info for the audio
referred to in ``url``.
- ``body`` : "string" - A description of the audio e.g. "Bee Gees - Stayin'
Alive", or some kind of content description for accessibility e.g.
"audio attachment".
AudioInfo:
Information about a piece of audio::
Paul "LeoNerd" Evans
committed
{
"mimetype" : "string (e.g. audio/aac)",
"size" : integer (size of audio in bytes),
"duration" : integer (duration of audio in milliseconds),
}
Paul "LeoNerd" Evans
committed
``m.video``
Required keys:
- ``url`` : "string" - The URL to the video.
Optional keys:
- ``info`` : JSON object (VideoInfo) - The video info for the video
referred to in ``url``.
- ``body`` : "string" - A description of the video e.g. "Gangnam style", or
some kind of content description for accessibility e.g. "video
attachment".
Paul "LeoNerd" Evans
committed
VideoInfo:
Information about a video::
Paul "LeoNerd" Evans
committed
{
"mimetype" : "string (e.g. video/mp4)",
"size" : integer (size of video in bytes),
"duration" : integer (duration of video in milliseconds),
"w" : integer (width of video in pixels),
"h" : integer (height of video in pixels),
"thumbnail_url" : "string (URL to image)",
"thumbanil_info" : JSON object (ImageInfo)
}
Paul "LeoNerd" Evans
committed
``m.location``
Required keys:
- ``geo_uri`` : "string" - The geo URI representing the location.
Optional keys:
- ``thumbnail_url`` : "string" - The URL to a thumnail of the location
being represented.
- ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
image referred to in ``thumbnail_url``.
- ``body`` : "string" - A description of the location e.g. "Big Ben,
London, UK", or some kind of content description for accessibility e.g.
"location attachment".
Paul "LeoNerd" Evans
committed
The following keys can be attached to any ``m.room.message``:
Paul "LeoNerd" Evans
committed
Optional keys:
- ``sender_ts`` : integer - A timestamp (ms resolution) representing the
wall-clock time when the message was sent from the client.
Paul "LeoNerd" Evans
committed
Presence
========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
Each user has the concept of presence information. This encodes the
"availability" of that user, suitable for display on other user's clients. This
is transmitted as an ``m.presence`` event and is one of the few events which
are sent *outside the context of a room*. The basic piece of presence
information is represented by the ``presence`` key, which is an enum of one of
the following:
Paul "LeoNerd" Evans
committed
- ``online`` : The default state when the user is connected to an event
stream.
- ``unavailable`` : The user is not reachable at this time.
- ``offline`` : The user is not connected to an event stream.
- ``free_for_chat`` : The user is generally willing to receive messages
moreso than default.
Paul "LeoNerd" Evans
committed
- ``hidden`` : Behaves as offline, but allows the user to see the client
state anyway and generally interact with client features. (Not yet
implemented in synapse).
Paul "LeoNerd" Evans
committed
This basic ``presence`` field applies to the user as a whole, regardless of how
many client devices they have connected. The home server should synchronise
this status choice among multiple devices to ensure the user gets a consistent
experience.
Paul "LeoNerd" Evans
committed
In addition, the server maintains a timestamp of the last time it saw an active
action from the user; either sending a message to a room, or changing presence
state from a lower to a higher level of availability (thus: changing state from
``unavailable`` to ``online`` will count as an action for being active, whereas
in the other direction will not). This timestamp is presented via a key called
``last_active_ago``, which gives the relative number of miliseconds since the
message is generated/emitted, that the user was last seen active.
Paul "LeoNerd" Evans
committed
Home servers can also use the user's choice of presence state as a signal for
how to handle new private one-to-one chat message requests. For example, it
might decide:
- ``free_for_chat`` : accept anything
- ``online`` : accept from anyone in my addres book list
- ``busy`` : accept from anyone in this "important people" group in my
address book list
Paul "LeoNerd" Evans
committed
Presence List
-------------
Each user's home server stores a "presence list" for that user. This stores a
list of other user IDs the user has chosen to add to it. To be added to this
list, the user being added must receive permission from the list owner. Once
granted, both user's HS(es) store this information. Since such subscriptions
are likely to be bidirectional, HSes may wish to automatically accept requests
when a reverse subscription already exists.
Paul "LeoNerd" Evans
committed
As a convenience, presence lists should support the ability to collect users
into groups, which could allow things like inviting the entire group to a new
("ad-hoc") chat room, or easy interaction with the profile information ACL
implementation of the HS.
Paul "LeoNerd" Evans
committed
Presence and Permissions
------------------------
For a viewing user to be allowed to see the presence information of a target
user, either:
Paul "LeoNerd" Evans
committed
- The target user has allowed the viewing user to add them to their presence
list, or
- The two users share at least one room in common
Paul "LeoNerd" Evans
committed
In the latter case, this allows for clients to display some minimal sense of
presence information in a user list for a room.
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
Client API
----------
The client API for presence is on the following set of REST calls.
Fetching basic status::
GET $PREFIX/presence/:user_id/status
Returned content: JSON object containing the following keys:
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
Setting basic status::
PUT $PREFIX/presence/:user_id/status
Content: JSON object containing the following keys:
presence and status_msg: as above
When setting the status, the activity time is updated to reflect that activity;
the client does not need to specify the ``last_active_ago`` field.
Fetching the presence list::
GET $PREFIX/presence/list
Returned content: JSON array containing objects; each object containing the
following keys:
user_id: observed user ID
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
Maintaining the presence list::
POST $PREFIX/presence/list
Content: JSON object containing either or both of the following keys:
invite: JSON array of strings giving user IDs to send invites to
drop: JSON array of strings giving user IDs to remove from the list
.. TODO-spec
- Define how users receive presence invites, and how they accept/decline them
Server API
----------
The server API for presence is based entirely on exchange of the following
EDUs. There are no PDUs or Federation Queries involved.
Performing a presence update and poll subscription request::
EDU type: m.presence
Content keys:
push: (optional): list of push operations.
Each should be an object with the following keys:
user_id: string containing a User ID
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
poll: (optional): list of strings giving User IDs
unpoll: (optional): list of strings giving User IDs
The presence of this combined message is two-fold: it informs the recipient
server of the current status of one or more users on the sending server (by the
``push`` key), and it maintains the list of users on the recipient server that
the sending server is interested in receiving updates for, by adding (by the
``poll`` key) or removing them (by the ``unpoll`` key). The ``poll`` and
``unpoll`` lists apply *changes* to the implied list of users; any existing IDs
that the server sent as ``poll`` operations in a previous message are not
removed until explicitly requested by a later ``unpoll``.
On receipt of a message containing a non-empty ``poll`` list, the receiving
server should immediately send the sending server a presence update EDU of its
own, containing in a ``push`` list the current state of every user that was in
the orginal EDU's ``poll`` list.
Sending a presence invite::
EDU type: m.presence_invite
Content keys:
observed_user: string giving the User ID of the user whose presence is
requested (i.e. the recipient of the invite)
observer_user: string giving the User ID of the user who is requesting to
observe the presence (i.e. the sender of the invite)
Accepting a presence invite::
EDU type: m.presence_accept
Content keys - as for m.presence_invite
Rejecting a presence invite::
EDU type: m.presence_deny
Content keys - as for m.presence_invite
.. TODO-doc
- Explain the timing-based roundtrip reduction mechanism for presence
messages
- Explain the zero-byte presence inference logic
See also: docs/client-server/model/presence
Paul "LeoNerd" Evans
committed
Paul "LeoNerd" Evans
committed
Voice over IP
=============
Matrix can also be used to set up VoIP calls. This is part of the core
specification, although is still in a very early stage. Voice (and video) over
Matrix is based on the WebRTC standards.
Paul "LeoNerd" Evans
committed
Call events are sent to a room, like any other event. This means that clients
must only send call events to rooms with exactly two participants as currently
the WebRTC standard is based around two-party communication.
Paul "LeoNerd" Evans
committed
Events
------
``m.call.invite``
This event is sent by the caller when they wish to establish a call.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - A unique identifier for the call
- ``offer`` : "offer object" - The session description
- ``version`` : "integer" - The version of the VoIP specification this
message adheres to. This specification is version 0.
- ``lifetime`` : "integer" - The time in milliseconds that the invite is
valid for. Once the invite age exceeds this value, clients should discard
it. They should also no longer show the call as awaiting an answer in the
UI.
Optional keys:
None.
Example:
``{ "version" : 0, "call_id": "12345", "offer": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" } }``
Paul "LeoNerd" Evans
committed
``Offer Object``
Required keys:
- ``type`` : "string" - The type of session description, in this case
'offer'
- ``sdp`` : "string" - The SDP text of the session description
Paul "LeoNerd" Evans
committed
``m.call.candidates``
This event is sent by callers after sending an invite and by the callee after
answering. Its purpose is to give the other party additional ICE candidates to
try using to communicate.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages adheres to. his specification is version 0.
- ``candidates`` : "array of candidate objects" - Array of object
describing the candidates.
Paul "LeoNerd" Evans
committed
``Candidate Object``
Paul "LeoNerd" Evans
committed
Required Keys:
- ``sdpMid`` : "string" - The SDP media type this candidate is intended
for.
- ``sdpMLineIndex`` : "integer" - The index of the SDP 'm' line this
candidate is intended for
- ``candidate`` : "string" - The SDP 'a' line of the candidate
Paul "LeoNerd" Evans
committed
``m.call.answer``
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages
- ``answer`` : "answer object" - Object giving the SDK answer
Paul "LeoNerd" Evans
committed
``Answer Object``
Paul "LeoNerd" Evans
committed
Required keys:
- ``type`` : "string" - The type of session description. 'answer' in this
case.
- ``sdp`` : "string" - The SDP text of the session description
Paul "LeoNerd" Evans
committed
``m.call.hangup``
Sent by either party to signal their termination of the call. This can be sent
either once the call has has been established or before to abort the call.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages
Paul "LeoNerd" Evans
committed
Message Exchange
----------------
A call is set up with messages exchanged as follows:
Paul "LeoNerd" Evans
committed
::
Paul "LeoNerd" Evans
committed
Caller Callee
m.call.invite ----------->
m.call.candidate -------->
[more candidates events]
User answers call
<------ m.call.answer
[...]
<------ m.call.hangup
Or a rejected call:
Paul "LeoNerd" Evans
committed
::
Paul "LeoNerd" Evans
committed
Caller Callee
m.call.invite ----------->
m.call.candidate -------->
[more candidates events]
User rejects call
<------- m.call.hangup
Paul "LeoNerd" Evans
committed
Calls are negotiated according to the WebRTC specification.
Paul "LeoNerd" Evans
committed
Glare
-----
This specification aims to address the problem of two users calling each other
at roughly the same time and their invites crossing on the wire. It is a far
better experience for the users if their calls are connected if it is clear
that their intention is to set up a call with one another.
Paul "LeoNerd" Evans
committed
In Matrix, calls are to rooms rather than users (even if those rooms may only
contain one other user) so we consider calls which are to the same room.
Paul "LeoNerd" Evans
committed
The rules for dealing with such a situation are as follows:
Paul "LeoNerd" Evans
committed
- If an invite to a room is received whilst the client is preparing to send an
invite to the same room, the client should cancel its outgoing call and
instead automatically accept the incoming call on behalf of the user.
- If an invite to a room is received after the client has sent an invite to
the same room and is waiting for a response, the client should perform a
lexicographical comparison of the call IDs of the two calls and use the
lesser of the two calls, aborting the greater. If the incoming call is the
lesser, the client should accept this call on behalf of the user.
Paul "LeoNerd" Evans
committed
The call setup should appear seamless to the user as if they had simply placed
a call and the other party had accepted. Thusly, any media stream that had been
setup for use on a call should be transferred and used for the call that
replaces it.
Paul "LeoNerd" Evans
committed
Paul "LeoNerd" Evans
committed
Profiles
========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
- Metadata extensibility
Paul "LeoNerd" Evans
committed
Internally within Matrix users are referred to by their user ID, which is
typically a compact unique identifier. Profiles grant users the ability to see
human-readable names for other users that are in some way meaningful to them.
Additionally, profiles can publish additional information, such as the user's
age or location.
A Profile consists of a display name, an avatar picture, and a set of other
metadata fields that the user may wish to publish (email address, phone
numbers, website URLs, etc...). This specification puts no requirements on the
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
display name other than it being a valid unicode string. Avatar images are not
stored directly; instead the home server stores an ``http``-scheme URL where
clients may fetch it from.
Client API
----------
The client API for profile management consists of the following REST calls.
Fetching a user account displayname::
GET $PREFIX/profile/:user_id/displayname
Returned content: JSON object containing the following keys:
displayname: string of freeform text
This call may be used to fetch the user's own displayname or to query the name
of other users; either locally or on remote systems hosted on other home
servers.
Setting a new displayname::
PUT $PREFIX/profile/:user_id/displayname
Content: JSON object containing the following keys:
displayname: string of freeform text
Fetching a user account avatar URL::
GET $PREFIX/profile/:user_id/avatar_url
Returned content: JSON object containing the following keys:
avatar_url: string containing an http-scheme URL
As with displayname, this call may be used to fetch either the user's own, or
other users' avatar URL.
Setting a new avatar URL::
PUT $PREFIX/profile/:user_id/avatar_url
Content: JSON object containing the following keys:
avatar_url: string containing an http-scheme URL
Fetching combined account profile information::
GET $PREFIX/profile/:user_id
Returned content: JSON object containing the following keys:
displayname: string of freeform text
avatar_url: string containing an http-scheme URL
At the current time, this API simply returns the displayname and avatar URL
information, though it is intended to return more fields about the user's
profile once they are defined. Client implementations should take care not to
expect that these are the only two keys returned as future versions of this
specification may yield more keys here.
Server API
----------
The server API for profiles is based entirely on the following Federation
Queries. There are no additional EDU or PDU types involved, other than the
implicit ``m.presence`` and ``m.room.member`` events (see section below).
Querying profile information::
Query type: profile
Arguments:
user_id: the ID of the user whose profile to return
field: (optional) string giving a field name
Returns: JSON object containing the following keys:
displayname: string of freeform text
avatar_url: string containing an http-scheme URL
If the query contains the optional ``field`` key, it should give the name of a
result field. If such is present, then the result should contain only a field
of that name, with no others present. If not, the result should contain as much
of the user's profile as the home server has available and can make public.
Events on Change of Profile Information
---------------------------------------
Because the profile displayname and avatar information are likely to be used in
many places of a client's display, changes to these fields cause an automatic