|
|
|
|
53
|
|
53
|
|
54
|
Now that we know what a room is, let's talk about what's passing inside of one. Earlier, I've been talking about messages, which are actually called "events". Technically speaking, a Matrix event is a JSON object that's sent in a room and dispatched to all other members of the room. It, of course, has an ID that's generated by the homeserver hosting the user who sent the message, taking the general form we saw earlier and the `$` sigil character. This JSON has metadata, such as a class name to identify different event types, an author, a creation timestamp, etc. It basically looks like this:
|
54
|
Now that we know what a room is, let's talk about what's passing inside of one. Earlier, I've been talking about messages, which are actually called "events". Technically speaking, a Matrix event is a JSON object that's sent in a room and dispatched to all other members of the room. It, of course, has an ID that's generated by the homeserver hosting the user who sent the message, taking the general form we saw earlier and the `$` sigil character. This JSON has metadata, such as a class name to identify different event types, an author, a creation timestamp, etc. It basically looks like this:
|
55
|
|
55
|
|
56
|
-```json
|
|
|
|
|
56
|
+{{< highlight json >}}
|
57
|
{
|
57
|
{
|
58
|
"origin_server_ts": 1526072700313,
|
58
|
"origin_server_ts": 1526072700313,
|
59
|
"sender": "@Alice:matrix.alice.tld",
|
59
|
"sender": "@Alice:matrix.alice.tld",
|
|
|
|
|
69
|
"type": "m.room.message",
|
69
|
"type": "m.room.message",
|
70
|
"room_id": "!TCnDZIwFBeQyBCciFD:matrix.alice.tld"
|
70
|
"room_id": "!TCnDZIwFBeQyBCciFD:matrix.alice.tld"
|
71
|
}
|
71
|
}
|
72
|
-```
|
|
|
|
|
72
|
+{{< / highlight >}}
|
73
|
|
73
|
|
74
|
The example above is an event sent from Alice to Bob and Charlie in the room they're all in. It's a message, as hinted at by the `m.room.message` class name in the `type` property. The `content` property, which must be an object, contains the event's actual content. In this case, we can see the message is text, and the text itself. This precision is needed because `m.room.message` can be a text, but also an image, a video, a notice, etc. as mentioned in [the spec](https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-message).
|
74
|
The example above is an event sent from Alice to Bob and Charlie in the room they're all in. It's a message, as hinted at by the `m.room.message` class name in the `type` property. The `content` property, which must be an object, contains the event's actual content. In this case, we can see the message is text, and the text itself. This precision is needed because `m.room.message` can be a text, but also an image, a video, a notice, etc. as mentioned in [the spec](https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-message).
|
75
|
|
75
|
|
|
|
|
|
107
|
|
107
|
|
108
|
The request body is a JSON which takes the following form:
|
108
|
The request body is a JSON which takes the following form:
|
109
|
|
109
|
|
110
|
-```json
|
|
|
|
|
110
|
+{{< highlight json >}}
|
111
|
{
|
111
|
{
|
112
|
"username": "Alice",
|
112
|
"username": "Alice",
|
113
|
"password": "1L0v3M4tr!x",
|
113
|
"password": "1L0v3M4tr!x",
|
114
|
}
|
114
|
}
|
115
|
-```
|
|
|
|
|
115
|
+{{< / highlight >}}
|
116
|
|
116
|
|
117
|
Here, the `username` and `password` properties are exactly what you think it is. The Matrix ID generated for a new user contains what's provided in the `username` property as the `localpart`.
|
117
|
Here, the `username` and `password` properties are exactly what you think it is. The Matrix ID generated for a new user contains what's provided in the `username` property as the `localpart`.
|
118
|
|
118
|
|
119
|
Fire this request. You'll now get a `401` status code along with some JSON, which looks like this:
|
119
|
Fire this request. You'll now get a `401` status code along with some JSON, which looks like this:
|
120
|
|
120
|
|
121
|
-```json
|
|
|
|
|
121
|
+{{< highlight json >}}
|
122
|
{
|
122
|
{
|
123
|
"flows": [
|
123
|
"flows": [
|
124
|
{
|
124
|
{
|
|
|
|
|
135
|
"params": {},
|
135
|
"params": {},
|
136
|
"session": "HrvSksPaKpglatvIqJHVEfkd"
|
136
|
"session": "HrvSksPaKpglatvIqJHVEfkd"
|
137
|
}
|
137
|
}
|
138
|
-```
|
|
|
|
|
138
|
+{{< / highlight >}}
|
139
|
|
139
|
|
140
|
Now, this enpoint uses a part of the spec called the [User-Interactive Authentication API](https://matrix.org/docs/spec/client_server/r0.3.0.html#user-interactive-authentication-api). This means that authentication can be seen as flows of consecutive stages. That's exactly what we have here: two flows, each containing one stage. This example is a very simple one, but it can get quite more complex, such as:
|
140
|
Now, this enpoint uses a part of the spec called the [User-Interactive Authentication API](https://matrix.org/docs/spec/client_server/r0.3.0.html#user-interactive-authentication-api). This means that authentication can be seen as flows of consecutive stages. That's exactly what we have here: two flows, each containing one stage. This example is a very simple one, but it can get quite more complex, such as:
|
141
|
|
141
|
|
142
|
-```json
|
|
|
|
|
142
|
+{{< highlight json >}}
|
143
|
{
|
143
|
{
|
144
|
"flows": [
|
144
|
"flows": [
|
145
|
{
|
145
|
{
|
|
|
|
|
161
|
},
|
161
|
},
|
162
|
"session": "qxATPqBPdTsaMBmOPkxZngXR"
|
162
|
"session": "qxATPqBPdTsaMBmOPkxZngXR"
|
163
|
}
|
163
|
}
|
164
|
-```
|
|
|
|
|
164
|
+{{< / highlight >}}
|
165
|
|
165
|
|
166
|
Here we can see two flows, one with a single stage, the other one with two stages. Note that there's also a parameter in the `params` object, to be used with the `m.login.recaptcha` flow.
|
166
|
Here we can see two flows, one with a single stage, the other one with two stages. Note that there's also a parameter in the `params` object, to be used with the `m.login.recaptcha` flow.
|
167
|
|
167
|
|
|
|
|
|
169
|
|
169
|
|
170
|
To register against this stage, we'll only add a few lines to our initial request's JSON:
|
170
|
To register against this stage, we'll only add a few lines to our initial request's JSON:
|
171
|
|
171
|
|
172
|
-```json
|
|
|
|
|
172
|
+{{< highlight json >}}
|
173
|
{
|
173
|
{
|
174
|
"auth": {
|
174
|
"auth": {
|
175
|
"type": "m.login.dummy",
|
175
|
"type": "m.login.dummy",
|
|
|
|
|
178
|
"username": "Alice",
|
178
|
"username": "Alice",
|
179
|
"password": "1L0v3M4tr!x",
|
179
|
"password": "1L0v3M4tr!x",
|
180
|
}
|
180
|
}
|
181
|
-```
|
|
|
|
|
181
|
+{{< / highlight >}}
|
182
|
|
182
|
|
183
|
Note that the value to the `session` property in the newly added `auth` object is the value from `sessions` taken from the homeserver's response to our intial request. This `auth` object will tell the homeserver that this request is a follow-up to the initial request, using the stage `m.login.dummy`. The homeserver will automatically recognise the flow we're using, and will succeed (because we use `m.login.dummy`), returning this JSON along with a `200` status code:
|
183
|
Note that the value to the `session` property in the newly added `auth` object is the value from `sessions` taken from the homeserver's response to our intial request. This `auth` object will tell the homeserver that this request is a follow-up to the initial request, using the stage `m.login.dummy`. The homeserver will automatically recognise the flow we're using, and will succeed (because we use `m.login.dummy`), returning this JSON along with a `200` status code:
|
184
|
|
184
|
|
185
|
-```json
|
|
|
|
|
185
|
+{{< highlight json >}}
|
186
|
{
|
186
|
{
|
187
|
"access_token": "olic0yeVa1pore2Kie4Wohsh",
|
187
|
"access_token": "olic0yeVa1pore2Kie4Wohsh",
|
188
|
"device_id": "FOZLAWNKLD",
|
188
|
"device_id": "FOZLAWNKLD",
|
189
|
"home_server": "matrix.project.tld",
|
189
|
"home_server": "matrix.project.tld",
|
190
|
"user_id": "@Alice:matrix.project.tld"
|
190
|
"user_id": "@Alice:matrix.project.tld"
|
191
|
}
|
191
|
}
|
192
|
-```
|
|
|
|
|
192
|
+{{< / highlight >}}
|
193
|
|
193
|
|
194
|
Let's see what we have here:
|
194
|
Let's see what we have here:
|
195
|
|
195
|
|
|
|
|
|
208
|
|
208
|
|
209
|
Before responding, the homeserver will create the room, fire a few state events in it (such as the initial `m.room.create` state event or a join event for your user). It should then respond with a `200` status code and a JSON body looking like this:
|
209
|
Before responding, the homeserver will create the room, fire a few state events in it (such as the initial `m.room.create` state event or a join event for your user). It should then respond with a `200` status code and a JSON body looking like this:
|
210
|
|
210
|
|
211
|
-```json
|
|
|
|
|
211
|
+{{< highlight json >}}
|
212
|
{
|
212
|
{
|
213
|
"room_id": "!RtZiWTovChPysCUIgn:matrix.project.tld"
|
213
|
"room_id": "!RtZiWTovChPysCUIgn:matrix.project.tld"
|
214
|
}
|
214
|
}
|
215
|
-```
|
|
|
|
|
215
|
+{{< / highlight >}}
|
216
|
|
216
|
|
217
|
Here you are, you have created and joined your very first room! As you might have guessed, the value for the `room_id` property is the ID of the newly created room.
|
217
|
Here you are, you have created and joined your very first room! As you might have guessed, the value for the `room_id` property is the ID of the newly created room.
|
218
|
|
218
|
|
|
|
|
|
222
|
|
222
|
|
223
|
The request should return a JSON array containing state events such as:
|
223
|
The request should return a JSON array containing state events such as:
|
224
|
|
224
|
|
225
|
-```json
|
|
|
|
|
225
|
+{{< highlight json >}}
|
226
|
{
|
226
|
{
|
227
|
"age": 654742,
|
227
|
"age": 654742,
|
228
|
"content": {
|
228
|
"content": {
|
|
|
|
|
238
|
"age": 654742
|
238
|
"age": 654742
|
239
|
}
|
239
|
}
|
240
|
}
|
240
|
}
|
241
|
-```
|
|
|
|
|
241
|
+{{< / highlight >}}
|
242
|
|
242
|
|
243
|
Now let's try to send our own state event in the room, shall we? I order to do that, you'll need to send a `PUT` request to the [`/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`](https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype) endpoint, repacing the room's ID, the event's type and its state key with the right values. Note that if your state key is an empty string, you can just omit it from the URL. Again, don't forget to append your access token!
|
243
|
Now let's try to send our own state event in the room, shall we? I order to do that, you'll need to send a `PUT` request to the [`/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`](https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype) endpoint, repacing the room's ID, the event's type and its state key with the right values. Note that if your state key is an empty string, you can just omit it from the URL. Again, don't forget to append your access token!
|
244
|
|
244
|
|
|
|
|
|
246
|
|
246
|
|
247
|
Let's create a `tld.project.foo` event with `bar` as its state key, and `{"baz": "qux"}` as its content. To achieve that, let's send a `PUT` request to `/_matrix/client/r0/rooms/!RtZiWTovChPysCUIgn:matrix.project.tld/state/tld.project.foo/bar?access_token=olic0yeVa1pore2Kie4Wohsh` (from which I've stripped the protocol scheme and FQDN so it doesn't appear too in the post) with the fillowing content:
|
247
|
Let's create a `tld.project.foo` event with `bar` as its state key, and `{"baz": "qux"}` as its content. To achieve that, let's send a `PUT` request to `/_matrix/client/r0/rooms/!RtZiWTovChPysCUIgn:matrix.project.tld/state/tld.project.foo/bar?access_token=olic0yeVa1pore2Kie4Wohsh` (from which I've stripped the protocol scheme and FQDN so it doesn't appear too in the post) with the fillowing content:
|
248
|
|
248
|
|
249
|
-```json
|
|
|
|
|
249
|
+{{< highlight json >}}
|
250
|
{
|
250
|
{
|
251
|
"baz": "qux"
|
251
|
"baz": "qux"
|
252
|
}
|
252
|
}
|
253
|
-```
|
|
|
|
|
253
|
+{{< / highlight >}}
|
254
|
|
254
|
|
255
|
The homeserver then responds with an object only containing an `event_id` property, which contains the ID of the newly created state event.
|
255
|
The homeserver then responds with an object only containing an `event_id` property, which contains the ID of the newly created state event.
|
256
|
|
256
|
|
257
|
If we retry the request we previously made to retrieve the whole room state, we can now see our event:
|
257
|
If we retry the request we previously made to retrieve the whole room state, we can now see our event:
|
258
|
|
258
|
|
259
|
-```json
|
|
|
|
|
259
|
+{{< highlight json >}}
|
260
|
{
|
260
|
{
|
261
|
"age": 58357,
|
261
|
"age": 58357,
|
262
|
"content": {
|
262
|
"content": {
|
|
|
|
|
272
|
"age": 58357
|
272
|
"age": 58357
|
273
|
}
|
273
|
}
|
274
|
}
|
274
|
}
|
275
|
-```
|
|
|
|
|
275
|
+{{< / highlight >}}
|
276
|
|
276
|
|
277
|
Note that sending an update of a state event is done the same way as sending a new state event with the same class name and the same state key.
|
277
|
Note that sending an update of a state event is done the same way as sending a new state event with the same class name and the same state key.
|
278
|
|
278
|
|
|
|
|
|
292
|
|
292
|
|
293
|
Inviting someone into a room is also quite simple, and only requires a `POST` request on the [`/_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-rooms-roomid-invite) endpoint. The request's body must contain the invited Matrix ID as such:
|
293
|
Inviting someone into a room is also quite simple, and only requires a `POST` request on the [`/_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-rooms-roomid-invite) endpoint. The request's body must contain the invited Matrix ID as such:
|
294
|
|
294
|
|
295
|
-```json
|
|
|
|
|
295
|
+{{< highlight json >}}
|
296
|
{
|
296
|
{
|
297
|
"user_id": "@Bob:matrix.bob.tld"
|
297
|
"user_id": "@Bob:matrix.bob.tld"
|
298
|
}
|
298
|
}
|
299
|
-```
|
|
|
|
|
299
|
+{{< / highlight >}}
|
300
|
|
300
|
|
301
|
Note that the request is the same if Bob has registered on the same server as Alice.
|
301
|
Note that the request is the same if Bob has registered on the same server as Alice.
|
302
|
|
302
|
|
|
|
|
|
304
|
|
304
|
|
305
|
In the next request on the [`/_matrix/client/r0/sync`](https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-sync) he'll made, Bob will now see an `invite` object inside the `rooms` one contaning the invite Alice sent him, containing a few events including the invite event:
|
305
|
In the next request on the [`/_matrix/client/r0/sync`](https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-r0-sync) he'll made, Bob will now see an `invite` object inside the `rooms` one contaning the invite Alice sent him, containing a few events including the invite event:
|
306
|
|
306
|
|
307
|
-```json
|
|
|
|
|
307
|
+{{< highlight json >}}
|
308
|
{
|
308
|
{
|
309
|
"invite": {
|
309
|
"invite": {
|
310
|
"!RtZiWTovChPysCUIgn:matrix.project.tld": {
|
310
|
"!RtZiWTovChPysCUIgn:matrix.project.tld": {
|
|
|
|
|
331
|
}
|
331
|
}
|
332
|
}
|
332
|
}
|
333
|
}
|
333
|
}
|
334
|
-```
|
|
|
|
|
334
|
+{{< / highlight >}}
|
335
|
|
335
|
|
336
|
Now Bob will be able to join the room by sending a simple `POST` request to the [`/_matrix/client/r0/rooms/{roomId}/join`](https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-rooms-roomid-join) endpoint.
|
336
|
Now Bob will be able to join the room by sending a simple `POST` request to the [`/_matrix/client/r0/rooms/{roomId}/join`](https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-rooms-roomid-join) endpoint.
|
337
|
|
337
|
|