A chat network
A group messaging network
An ecosystem
With bridges!
And bots!
An open network for secure, decentralized communication
An open network for secure, decentralized communication
An open network for secure, decentralized communication
[1] gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md
[2] matrix.org/blog/2016/11/21/matrixs-olm-end-to-end-encryption-security-assessment-released-and-implemented-cross-platform-on-riot-at-last
[3] gitlab.matrix.org/matrix-org/mls-ts/-/blob/decentralised2/decentralised.org
An open network for secure, decentralized communication
An open network for secure, decentralized communication
Run Synapse:
python -m synapse.app.homeserver \
--config-path homeserver.yaml
Ask the server what version it is:
$ curl -s 'http://localhost:8008/_matrix/client/versions'
{
"versions": [ ..., "v1.2" ],
"unstable_features": { ... }
}
Ask to register a new user:
$ curl -s '.../_matrix/client/r0/register' -d '{}'
{
"session": "sEdCvdBIiRxwqxULhKyBGNMx",
"flows": [ { "stages": [ "m.login.dummy" ] } ],
"params": {}
}
Register the user:
$ curl -s '.../_matrix/client/v1/register' -d '{
"auth": { "type": "m.login.dummy" },
"username": "curluser1",
"password": "mypassword"
}'
{
"user_id": "@curluser1:localhost",
"home_server": "localhost",
"access_token": "syt_Y3VybHVzZXIx_...",
"device_id": "HHOGSCKLWW"
}
Find the types of login:
$ curl -s '.../_matrix/client/r0/login'
{
"flows": [
{ "type": "m.login.password" },
{ "type": "m.login.application_service" },
...
]
}
Log in:
$ curl -s '.../matrix/client/v1/login' -d '{
"type":"m.login.password",
"identifier": { "user": "@curluser1:localhost", "type": "m.id.user" },
"password":"mypassword"
}'
{
"user_id": "@curluser1:localhost",
"access_token": "syt_Y3VybHVzZXIx_...",
"home_server": "localhost",
"device_id": "HEUUQYFAMG",
"well_known": { ... }
}
(Register another user:)
$ curl -s '.../_matrix/client/v1/register' -d '{
"auth": { "type": "m.login.dummy" },
"username": "curluser2",
"password": "mypassword"
}'
Create a room:
$ curl -s '.../_matrix/client/r0/createRoom'
-H 'Authorization: Bearer syt_Y3VybHVzZXIx_...'
-d '{"invite":["@curluser2:localhost"]}'
{
"room_id": "!JRyYpMzvxJMAhVAPSv:localhost"
}
Sync: (initial sync)
$ curl -s '.../_matrix/client/r0/sync'
-H 'Authorization: Bearer syt_Y3VybHVzZXIx_...'
{
"next_batch": "s41_4149_0_7_28_1_2_17_1",
"account_data": { ...
"presence": { ...
"rooms": {
"join": {
"!JRyYpMzvxJMAhVAPSv:localhost": {
"timeline": { "events": [ {
"type": "m.room.create",
...
Sync again:
$ curl -s '.../v1/sync?since=s41_4149_0_7_28_1_2_17_1'
-H 'Authorization: Bearer syt_Y3VybHVzZXIx_...'
{
"next_batch": "s41_4159_0_7_28_1_2_17_1",
"presence": {
...
As user2, sync to find the invite:
$ curl -s '.../_matrix/client/v1/sync'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
{
"next_batch": "s41_4165_0_7_28_1_2_17_1",
"account_data": { ... }, "presence": { ... },
"rooms": {
"invite": {
"!JRyYpMzvxJMAhVAPSv:localhost": {
"invite_state": {
"events": [
{ "type": "m.room.create",
...
"events": [ ...
{
"type": "m.room.member",
"state_key": "@curluser1:localhost",
"content": {
"membership": "join",
"displayname": "curluser1"
},
"sender": "@curluser1:localhost"
},
...
"events": [ ...
{
"type": "m.room.member",
"state_key": "@curluser2:localhost",
"content": {
"membership": "invite",
"displayname": "curluser2"
},
"sender": "@curluser1:localhost",
"event_id": "$rMb..."
...
}
...
As user2, check what rooms we are in:
$ curl -s '.../_matrix/client/r0/joined_rooms'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
{
"joined_rooms": []
}
As user2, accept the invite:
$ curl -s '.../r0/rooms/!JRyYpMzvxJMAhVAPSv:localhost/join'
-H 'Authorization: Bearer syt_Y3VybHVzZXIy_...'
-d '{ "roomId": "!JRyYpMzvxJMAhVAPSv:localhost" }'
{
"room_id": "!JRyYpMzvxJMAhVAPSv:localhost"
}
As user2, check again:
$ curl -s '.../_matrix/client/r0/joined_rooms'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
{
"joined_rooms": [
"!JRyYpMzvxJMAhVAPSv:localhost"
]
}
As user2, sync again:
$ curl -s '.../_matrix/client/r0/sync?since=s41_4165_0_7_28_1_2_17_1'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
{
...
"rooms": {
"join": {
"!JRyYpMzvxJMAhVAPSv:localhost": {
... events here ...
...
As user1, sync:
$ curl -s '.../_matrix/client/v1/sync?since=s41_4159_0_7_28_1_2_17_1'
-H 'Authorization: Bearer syt_Y3VybHVzZXIx_...'
{ ...
"events": [
{
"type": "m.room.member",
"sender": "@curluser2:localhost",
...
}
As user1, say something:
$ curl -s -X PUT '.../v1/rooms/!JRyYpMzvxJMAhVAPSv:localhost
/send/m.room.message/mytransaction-A'
-d '{ "body": "Hello from curl!", "msgtype": "m.text" }'
-H 'Authorization: Bearer syt_Y3VybHVzZXIx_...'
{
"event_id": "$F_CZ9..."
}
As user2, sync:
$ curl -s '.../v1/sync?since=s42_4186_0_7_28_1_2_17_1'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
...
"rooms": { "join": { "!JRyYpMzvxJMAhVAPSv:localhost": {
"timeline": { "events": [ {
"content": {
"body": "Hello from curl!",
"msgtype": "m.text"
},
"sender": "@curluser1:localhost",
"event_id": "$F_CZ9...",
...
Syncing is a long poll ...
$ curl -s '.../v1/sync?timeout=1000000&since=s43_5796_0_7_28_1_2_17_1'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
...
... that returns when something happens
$ curl -s '.../v1/sync?timeout=1000000&since=s43_5796_0_7_28_1_2_17_1'
-H 'Authorization: Bearer abc_Y3VybHVzZXIy_...'
...
"rooms": { "join": { "!JRyYpMzvxJMAhVAPSv:localhost": {
"timeline": { "events": [ {
"content": {
"body": "It works!",
"msgtype": "m.text"
},
"sender": "@curluser1:localhost",
"event_id": "$F_CZ9...",
...
"content" is what a client sends
{
"content": {
"body": "hello",
"msgtype": "m.text"
},
"event_id": "$14606535757KCGXo:localhost",
"origin_server_ts": 1460653575105,
"sender": "@example:localhost",
"type": "m.room.message",
"unsigned": { "age": 800348 }
}
The server assigns ID, sender etc.
{
"content": {
"body": "hello",
"msgtype": "m.text"
},
"event_id": "$14606535757KCGXo:localhost",
"origin_server_ts": 1460653575105,
"sender": "@example:localhost",
"type": "m.room.message",
"unsigned": { "age": 800348 }
}
The type is part of the URL we sent
$ curl -s -X PUT '.../send/m.room.message/mytransaction-A'
...
"content": ...
"event_id": "$14606535757KCGXo:localhost",
"origin_server_ts": 1460653575105,
"sender": "@example:localhost",
"type": "m.room.message",
"unsigned": { "age": 800348 }
}
The content can vary
{
"content": {
"body": "What *is* this?",
"formatted_body": "What <b>is</b> this?",
"format": "org.matrix.custom.html",
"msgtype": "m.text"
},
...
Or maybe even like this4:
"type": "m.message",
"content": {
"m.message": [
{
"mimetype": "text/plain",
"body": "Something _new_?"
},
{
"mimetype": "text/html",
"body": "Something <i>new</i>?"
}
...
[4] artificialworlds.net/blog/2022/03/08/comparison-of-matrix-events-before-and-after-extensible-events/
There are:
Some message events:
Normal messages we have already seen:
{
"content": {
"body": "What *is* this?",
"formatted_body": "What <b>is</b> this?",
"format": "org.matrix.custom.html",
"msgtype": "m.text"
},
...
Redactions destroy another event's content:
{
"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 }
}
Polls allow asking a question:
{
"type": "org.matrix.msc3381.poll.start",
"content": {
"org.matrix.msc3381.poll.start": {
"question": { "m.text": "Which?" },
"answers": [
{ "id": "a", "m.text": "A, of course" },
{ "id": "b", "m.text": "But B!" },
]
},
...
Polls are unstable.
This is allowed/encouraged.
Find out more about polls in MSC33815.
Some state events:
Creation of a room:
{
"content": {
"creator": "@example:example.org",
"room_version": "9",
...
},
"state_key": "",
"type": "m.room.create",
...
Name of a room:
{
"content": {
"name": "The best room"
},
"state_key": "",
"type": "m.room.name",
...
Membership of a person
{
"content": {
"displayname": "Alice Margatroid",
"membership": "join",
...
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
...
Ephemeral events don't last long
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
}
(Note: no event id)
The event graph
A split brain
A state conflict
In what order did important things happen?
Kahn's algorithm: no in-arrows means new
Kahn's algorithm: no in-arrows means new
Kahn's algorithm: no in-arrows means new
Kahn's algorithm: no in-arrows means new
Resolve ties using Matrix-specifics e.g. timestamp
Chat requires a distributed real-time database
A distributed real-time database is exactly what we need for many, many other things:
Matrix was always designed with this in mind.
Video conferences and voice rooms
Collaborative creativity
[7] github.com/toger5/TheBoard
[8] npmjs.com/package/@collabs/collabs
[9] github.com/YousefED/Matrix-CRDT
[10] fosdem.org/2022/schedule/event/matrix_filesystem/
Immersive environments
[11] Third Room: youtu.be/e26UJRCGfGk
Peer-to-peer
Find out more about Matrix at
matrix.org, especially:
The epic "Mega Matrix Holiday Special 2021" blog post
These slides:
http://artificialworlds.net/presentations/matrix-is-a-distributed-real-time-database