Merge branch 'master' into daniel/threepidinvites-2

pull/977/head
Daniel Wagner-Hall 9 years ago
commit 21a40b317d

@ -6,6 +6,34 @@
.. in Jenkins. Comments like this are ignored by both RST and the templating .. in Jenkins. Comments like this are ignored by both RST and the templating
.. system. Add the newest release notes beneath this comment. .. system. Add the newest release notes beneath this comment.
Specification changes in v0.2.0 (2015-10-02)
============================================
This update fundamentally restructures the specification. The specification has
been split into more digestible "modules" which each describe a particular
function (e.g. typing). This was done in order make the specification easier to
maintain and help define which modules are mandatory for certain types
of clients. Types of clients along with the mandatory modules can be found in a
new "Feature Profiles" section. This update also begins to aggressively
standardise on using Swagger and JSON Schema to document HTTP endpoints and
Events respectively. It also introduces a number of new concepts to Matrix.
Additions:
- New section: Feature Profiles.
- New section: Receipts.
- New section: Room history visibility.
- New event: ``m.receipt``.
- New event: ``m.room.canonical_alias``
- New event: ``m.room.history_visibility``
- New keys: ``/createRoom`` - allows room "presets" using ``preset`` and
``initial_state`` keys.
- New endpoint: ``/tokenrefresh`` - Related to refreshing access tokens.
Modifications:
- Convert most of the older HTTP APIs to Swagger documentation.
- Convert most of the older event formats to JSON Schema.
- Move selected client-server sections to be "Modules".
Specification changes in v0.1.0 (2015-06-01) Specification changes in v0.1.0 (2015-06-01)
============================================ ============================================
- First numbered release. - First numbered release.

@ -34,7 +34,7 @@ def check_parameter(filepath, request, parameter):
example = None example = None
try: try:
example_json = schema.get('example') example_json = schema.get('example')
if example_json: if example_json and not schema.get("format") == "byte":
example = json.loads(example_json) example = json.loads(example_json)
except Exception as e: except Exception as e:
raise ValueError("Error parsing JSON example request for %r" % ( raise ValueError("Error parsing JSON example request for %r" % (

@ -15,16 +15,22 @@ paths:
summary: Upload some content to the content repository. summary: Upload some content to the content repository.
produces: ["application/json"] produces: ["application/json"]
parameters: parameters:
- in: header
name: Content-Type
type: string
description: The content type of the file being uploaded
x-example: "Content-Type: audio/mpeg"
- in: body - in: body
name: content name: "<content>"
description: The content to be uploaded. description: The content to be uploaded.
required: true required: true
schema: schema:
type: string type: string
example: "<bytes>"
format: byte format: byte
responses: responses:
200: 200:
description: Information about the uploaded content. description: The MXC URI for the uploaded content.
schema: schema:
type: object type: object
required: ["content_uri"] required: ["content_uri"]
@ -32,6 +38,11 @@ paths:
content_uri: content_uri:
type: string type: string
description: "The MXC URI to the uploaded content." description: "The MXC URI to the uploaded content."
examples:
"application/json": |-
{
"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
}
"/download/{serverName}/{mediaId}": "/download/{serverName}/{mediaId}":
get: get:
summary: "Download content from the content repository." summary: "Download content from the content repository."
@ -40,18 +51,27 @@ paths:
- in: path - in: path
type: string type: string
name: serverName name: serverName
x-example: matrix.org
required: true required: true
description: | description: |
The server name from the ``mxc://`` URI (the authoritory component) The server name from the ``mxc://`` URI (the authoritory component)
- in: path - in: path
type: string type: string
name: mediaId name: mediaId
x-example: ascERGshawAWawugaAcauga
required: true required: true
description: | description: |
The media ID from the ``mxc://`` URI (the path component) The media ID from the ``mxc://`` URI (the path component)
responses: responses:
200: 200:
description: "The content downloaded." description: "The content that was previously uploaded."
headers:
Content-Type:
description: "The content type of the file that was previously uploaded."
type: "string"
Content-Disposition:
description: "The name of the file that was previously uploaded, if set."
type: "string"
schema: schema:
type: file type: file
"/thumbnail/{serverName}/{mediaId}": "/thumbnail/{serverName}/{mediaId}":
@ -63,30 +83,44 @@ paths:
type: string type: string
name: serverName name: serverName
required: true required: true
x-example: matrix.org
description: | description: |
The server name from the ``mxc://`` URI (the authoritory component) The server name from the ``mxc://`` URI (the authoritory component)
- in: path - in: path
type: string type: string
name: mediaId name: mediaId
x-example: ascERGshawAWawugaAcauga
required: true required: true
description: | description: |
The media ID from the ``mxc://`` URI (the path component) The media ID from the ``mxc://`` URI (the path component)
- in: query - in: query
type: integer type: integer
x-example: 64
name: width name: width
description: The desired width of the thumbnail. description: |-
The *desired* width of the thumbnail. The actual thumbnail may not
match the size specified.
- in: query - in: query
type: integer type: integer
x-example: 64
name: height name: height
description: The desired height of the thumbnail. description: |-
The *desired* height of the thumbnail. The actual thumbnail may not
match the size specified.
- in: query - in: query
type: string type: string
enum: ["crop", "scale"] enum: ["crop", "scale"]
name: method name: method
x-example: "scale"
description: The desired resizing method. description: The desired resizing method.
responses: responses:
200: 200:
description: "A thumbnail of the requested content." description: "A thumbnail of the requested content."
headers:
Content-Type:
description: "The content type of the thumbnail."
type: "string"
enum: ["image/jpeg", "image/png"]
schema: schema:
type: file type: file

@ -0,0 +1,77 @@
swagger: '2.0'
info:
title: "Matrix Client-Server v1 Typing API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/api/v1
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/rooms/{roomId}/typing/{userId}":
put:
summary: Informs the server that the user has started or stopped typing.
description: |-
This tells the server that the user is typing for the next N
milliseconds where N is the value specified in the ``timeout`` key.
Alternatively, if ``typing`` is ``false``, it tells the server that the
user has stopped typing.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
description: The user who has started to type.
required: true
x-example: "@alice:example.com"
- in: path
type: string
name: roomId
description: The room in which the user is typing.
required: true
x-example: "!wefh3sfukhs:example.com"
- in: body
name: typingState
description: The current typing state.
required: true
schema:
type: object
example: |-
{
"typing": true,
"timeout": 30000
}
properties:
typing:
type: boolean
description: |-
Whether the user is typing or not. If ``false``, the ``timeout``
key can be omitted.
timeout:
type: integer
description: The length of time in milliseconds to mark this user as typing.
required: ["typing"]
responses:
200:
description: The new typing state was set.
examples:
application/json: |-
{}
schema:
type: object # empty json object
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/error.yaml"

@ -0,0 +1 @@
../../../event-schemas/schema/v1/core-event-schema

@ -0,0 +1,10 @@
type: object
description: A Matrix-level Error
properties:
errcode:
type: string
description: An error code.
error:
type: string
description: A human-readable error message.
required: ["errcode"]

@ -0,0 +1,12 @@
{
"type": "object",
"properties": {
"events": {
"type": "array",
"description": "List of events",
"items": {
"type": "object"
}
}
}
}

@ -0,0 +1,42 @@
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description":
"The maximum number of events to return."
},
"types": {
"type": "array",
"description":
"A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_types": {
"type": "array",
"description":
"A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"senders": {
"type": "array",
"description":
"A list of senders IDs to include. If this list is absent then all senders are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_senders": {
"type": "array",
"description":
"A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
}
}
}

@ -0,0 +1,12 @@
{
"type": "object",
"properties": {
"events": {
"type": "array",
"description": "List of event ids",
"items": {
"type": "string"
}
}
}
}

@ -0,0 +1,22 @@
{
"type": "object",
"allOf": [{"$ref": "definitions/event_filter.json"}],
"properties": {
"rooms": {
"type": "array",
"description":
"A list of room IDs to include. If this list is absent then all rooms are included. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
},
"not_rooms": {
"type": "array",
"description":
"A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter. A '*' can be used as a wildcard to match any sequence of characters.",
"items": {
"type": "string"
}
}
}
}

@ -0,0 +1,44 @@
{
"type": "object",
"properties": {
"room": {
"type": "object",
"properties": {
"state": {
"description":
"The state events to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
},
"timeline": {
"description":
"The message and state update events to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
},
"ephemeral": {
"description":
"The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms.",
"allOf": [{"$ref": "definitions/room_event_filter.json"}]
}
}
},
"presence": {
"description":
"The presence updates to include.",
"allOf": [{"$ref": "definitions/event_filter.json"}]
},
"event_format": {
"description":
"The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'.",
"type": "string",
"enum": ["client", "federation"]
},
"event_fields": {
"type": "array",
"description":
"List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\\'. A server may include more fields than were requested.",
"items": {
"type": "string"
}
}
}
}

@ -0,0 +1,14 @@
{
"type": "object",
"allOf": [{"$ref":"definitions/room_event_batch.json"}],
"properties": {
"limited": {
"type": "boolean",
"description": "Whether there are more events on the server"
},
"prev_batch": {
"type": "string",
"description": "If the batch was limited then this is a token that can be supplied to the server to retrieve more events"
}
}
}

@ -0,0 +1,139 @@
swagger: '2.0'
info:
title: "Matrix Client-Server v2 filter API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
basePath: /_matrix/client/v2_alpha
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/user/{userId}/filter":
post:
summary: Upload a new filter.
description: |-
Uploads a new filter definition to the homeserver.
Returns a filter ID that may be used in /sync requests to
retrict which events are returned to the client.
security:
- accessToken: []
parameters:
- in: path
type: string
name: userId
required: true
description:
The id of the user uploading the filter. The access token must be
authorized to make requests for this user id.
x-example: "@alice:example.com"
- in: body
name: filter
required: true
description: The filter to upload.
schema:
type: object
allOf:
- $ref: "definitions/sync_filter.json"
example: |-
{
"room": {
"state": {
"types": ["m.room.*"],
"not_rooms": ["!726s6s6q:example.com"]
},
"timeline": {
"limit": 10,
"types": ["m.room.message"],
"not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"]
},
"emphemeral": {
"types": ["m.receipt", "m.typing"],
"not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"]
}
},
"presence": {
"types": ["m.presence"],
"not_senders": ["@alice:example.com"]
},
"event_format": "client",
"event_fields": ["type", "content", "sender"]
}
responses:
200:
description: The filter was created.
examples:
application/json: |-
{
"filter_id": "66696p746572"
}
schema:
type: object
properties:
filter_id:
type: string
description: |-
The ID of the filter that was created.
"/user/{userId}/filter/{filterId}":
get:
summary: Download a filter
parameters:
- in: path
name: userId
type: string
description: |-
The user ID to download a filter for.
x-example: "@alice:example.com"
required: true
- in: path
name: filterId
type: string
description: |-
The filter ID to download.
x-example: "66696p746572"
required: true
responses:
200:
description: |-
"The filter defintion"
examples:
application/json: |-
{
"room": {
"state": {
"types": ["m.room.*"],
"not_rooms": ["!726s6s6q:example.com"]
},
"timeline": {
"limit": 10,
"types": ["m.room.message"],
"not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"]
},
"emphemeral": {
"types": ["m.receipt", "m.typing"],
"not_rooms": ["!726s6s6q:example.com"],
"not_senders": ["@spam:example.com"]
}
},
"presence": {
"types": ["m.presence"],
"not_senders": ["@alice:example.com"]
},
"event_format": "client",
"event_fields": ["type", "content", "sender"]
}
schema:
type: object
allOf:
- $ref: "definitions/sync_filter.json"

@ -47,6 +47,7 @@ paths:
required: true required: true
x-example: "$1924376522eioj:example.com" x-example: "$1924376522eioj:example.com"
- in: body - in: body
name: receipt
description: |- description: |-
Extra receipt information to attach to ``content`` if any. The Extra receipt information to attach to ``content`` if any. The
server will automatically set the ``ts`` field. server will automatically set the ``ts`` field.

@ -0,0 +1,286 @@
swagger: '2.0'
info:
title: "Matrix Client-Server v2 sync API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
basePath: /_matrix/client/v2_alpha
consumes:
- application/json
produces:
- application/json
securityDefinitions:
accessToken:
type: apiKey
description: The user_id or application service access_token
name: access_token
in: query
paths:
"/sync":
get:
summary: Synchronise the client's state and receive new messages.
description: |-
Synchronise the client's state with the latest state on the server.
Client's use this API when they first log in to get an initial snapshot
of the state on the server, and then continue to call this API to get
incremental deltas to the state, and to receive new messages.
security:
- accessToken: []
parameters:
- in: query
name: filter
type: string
description: |-
The ID of a filter created using the filter API.
x-example: "66696p746572"
- in: query
name: since
type: string
description: |-
A point in time to continue a sync from.
x-example: "s72594_4483_1934"
- in: query
name: set_presence
type: string
enum: ["offline"]
description: |-
Controls whether the client is automatically marked as online by
polling this API. If this parameter is omitted then the client is
automatically marked as online when it uses this API. Otherwise if
the parameter is set to "offline" then the client is not marked as
being online when it uses this API.
x-example: "offline"
- in: query
name: timeout
type: integer
description: |-
The maximum time to poll in milliseconds before returning this
request.
x-example: 30000
responses:
200:
description:
The initial snapshot or delta for the client to use to update their
state.
schema:
type: object
properties:
next_batch:
type: string
description: |-
The batch token to supply in the ``since`` param of the next
``/sync`` request.
rooms:
title: Rooms
type: object
description: |-
Updates to rooms.
properties:
joined:
title: Joined
type: object
additionalProperties:
title: Joined Room
type: object
properties:
event_map:
title: EventMap
type: object
description: |-
A map from event ID to events for this room. The
events are referenced from the ``timeline`` and
``state`` keys for this room.
additionalProperties:
title: Event
description: An event object.
type: object
allOf:
- $ref: "core-event-schema/event.json"
state:
title: State
type: object
description: |-
The state updates for the room.
allOf:
- $ref: "definitions/room_event_batch.json"
timeline:
title: Timeline
type: object
description: |-
The timeline of messages and state changes in the
room.
allOf:
- $ref: "definitions/timeline_batch.json"
ephemeral:
title: Ephemeral
type: object
description: |-
The ephemeral events in the room that aren't
recorded in the timeline or state of the room.
e.g. typing.
allOf:
- $ref: "definitions/event_batch.json"
invited:
title: Invited
type: object
description: |-
The rooms that the user has been invited to.
additionalProperties:
title: Invited Room
type: object
properties:
invite_state:
title: InviteState
type: object
description: |-
The state of a room that the user has been invited
to. These state events may only have the `sender``,
``type``, ``state_key`` and ``content`` keys
present. These events do not replace any state that
the client already has for the room, for example if
the client has archived the room. Instead the
client should keep two separate copies of the
state: the one from the ``invite_state`` and one
from the archived ``state``. If the client joins
the room then the current state will be given as a
delta against the archived ``state`` not the
``invite_state``.
allOf:
- $ref: "definitions/event_batch.json"
archived:
title: Archived
type: object
description: |-
The rooms that the user has left or been banned from. The
entries in the room_map will lack an ``ephemeral`` key.
additionalProperties:
title: Archived Room
type: object
properties:
event_map:
title: EventMap
type: object
description: |-
A map from event ID to events for this room. The
events are referenced from the ``timeline`` and
``state`` keys for this room.
additionalProperties:
title: Event
description: An event object.
type: object
allOf:
- $ref: "core-event-schema/event.json"
state:
title: State
type: object
description: |-
The state updates for the room up to the point when
the user left.
allOf:
- $ref: "definitions/room_event_batch.json"
timeline:
title: Timeline
type: object
description: |-
The timeline of messages and state changes in the
room up to the point when the user left.
allOf:
- $ref: "definitions/timeline_batch.json"
presence:
title: Presence
type: object
description: |-
The updates to the presence status of other users.
allOf:
- $ref: "definitions/event_batch.json"
examples:
application/json: |-
{
"next_batch": "s72595_4483_1934",
"presence": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.presence",
"content": {"presence": "online"}
}
]
},
"rooms": {
"joined": {
"!726s6s6q:example.com": {
"event_map": {
"$66697273743031:example.com": {
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@alice:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795
},
"$7365636s6r6432:example.com": {
"sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "join"},
"origin_server_ts": 1417731086795
},
"$74686972643033:example.com": {
"sender": "@alice:example.com",
"type": "m.room.message",
"unsigned": {"age": "124524", "txn_id": "1234"},
"content": {
"body": "I am a fish",
"msgtype": "m.text"
},
"origin_server_ts": 1417731086797
}
},
"state": {
"events": [
"$66697273743031:example.com",
"$7365636s6r6432:example.com"
]
},
"timeline": {
"events": [
"$7365636s6r6432:example.com",
"$74686972643033:example.com"
],
"limited": true,
"prev_batch": "t34-23535_0_0"
},
"ephemeral": {
"events": [
{
"room_id": "!726s6s6q:example.com",
"type": "m.typing",
"content": {"user_ids": ["@alice:example.com"]}
}
]
}
}
},
"invited": {
"!696r7674:example.com": {
"invite_state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.name",
"state_key": "",
"content": {"name": "My Room Name"}
},
{
"sender": "@alice:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "invite"}
}
]
}
}
},
"archived": {}
}
}

@ -10,6 +10,6 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nopt": "^3.0.2", "nopt": "^3.0.2",
"swagger-parser": "^2.4.1" "swagger-parser": "^3.2.1"
} }
} }

@ -26,11 +26,10 @@ if (!opts.schema) {
} }
var errFn = function(err, api, metadata) { var errFn = function(err, api) {
if (!err) { if (!err) {
return; return;
} }
console.log(metadata);
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}; };
@ -46,11 +45,12 @@ if (isDir) {
files.forEach(function(f) { files.forEach(function(f) {
var suffix = ".yaml"; var suffix = ".yaml";
if (f.indexOf(suffix, f.length - suffix.length) > 0) { if (f.indexOf(suffix, f.length - suffix.length) > 0) {
parser.parse(path.join(opts.schema, f), function(err, api, metadata) { parser.validate(path.join(opts.schema, f), function(err, api, metadata) {
if (!err) { if (!err) {
console.log("%s is valid.", f); console.log("%s is valid.", f);
} }
else { else {
console.error("%s is not valid.", f);
errFn(err, api, metadata); errFn(err, api, metadata);
} }
}); });
@ -59,12 +59,12 @@ if (isDir) {
}); });
} }
else{ else{
parser.parse(opts.schema, function(err, api, metadata) { parser.validate(opts.schema, function(err, api) {
if (!err) { if (!err) {
console.log("%s is valid", opts.schema); console.log("%s is valid", opts.schema);
} }
else { else {
errFn(err, api, metadata); errFn(err, api);
} }
}); });
}; };

@ -0,0 +1,7 @@
{
"type": "m.typing",
"room_id": "!z0mnsuiwhifuhwwfw:matrix.org",
"content": {
"user_ids": ["@alice:matrix.org", "@bob:example.com"]
}
}

@ -12,6 +12,10 @@
"creator": { "creator": {
"type": "string", "type": "string",
"description": "The ``user_id`` of the room creator. This is set by the homeserver." "description": "The ``user_id`` of the room creator. This is set by the homeserver."
},
"m.federate": {
"type": "boolean",
"description": "Whether users on other servers can join this room. Defaults to ``true`` if key does not exist."
} }
}, },
"required": ["creator"] "required": ["creator"]

@ -0,0 +1,28 @@
{
"type": "object",
"title": "Typing Event",
"description": "Informs the client of the list of users currently typing.",
"properties": {
"content": {
"type": "object",
"properties": {
"user_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "The list of user IDs typing in this room, if any."
}
},
"required": ["user_ids"]
},
"type": {
"type": "string",
"enum": ["m.typing"]
},
"room_id": {
"type": "string"
}
},
"required": ["type", "room_id", "content"]
}

@ -4,6 +4,6 @@ set -ex
(cd event-schemas/ && ./check_examples.py) (cd event-schemas/ && ./check_examples.py)
(cd api && ./check_examples.py) (cd api && ./check_examples.py)
(cd scripts && ./gendoc.py) (cd scripts && ./gendoc.py -v)
(cd api && npm install && node validator.js -s "client-server/v1") (cd api && npm install && node validator.js -s "client-server/v1" && node validator.js -s "client-server/v2_alpha")
(cd event-schemas/ && ./check.sh) (cd event-schemas/ && ./check.sh)

@ -261,6 +261,7 @@ def run_through_template(input, set_verbose):
cwd="../templating" cwd="../templating"
) )
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
print e.output
with open(tmpfile, 'r') as f: with open(tmpfile, 'r') as f:
sys.stderr.write(f.read() + "\n") sys.stderr.write(f.read() + "\n")
raise raise

@ -278,3 +278,9 @@ td[colspan]:not([colspan="1"]) {
thead { thead {
background: #eeeeee; background: #eeeeee;
} }
div.admonition-rationale {
background-color: #efe;
border: 1px solid #ccc;
}

@ -60,11 +60,10 @@ func (u *User) IsTrusted() bool {
} }
const ( const (
pullsPrefix = "https://api.github.com/repos/matrix-org/matrix-doc/pulls" pullsPrefix = "https://api.github.com/repos/matrix-org/matrix-doc/pulls"
matrixDocCloneURL = "https://github.com/matrix-org/matrix-doc.git" matrixDocCloneURL = "https://github.com/matrix-org/matrix-doc.git"
) )
func gitClone(url string, shared bool) (string, error) { func gitClone(url string, shared bool) (string, error) {
directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10)) directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10))
cmd := exec.Command("git", "clone", url, directory) cmd := exec.Command("git", "clone", url, directory)
@ -80,21 +79,22 @@ func gitClone(url string, shared bool) (string, error) {
} }
func gitCheckout(path, sha string) error { func gitCheckout(path, sha string) error {
cmd := exec.Command("git", "checkout", sha) return runGitCommand(path, []string{"checkout", sha})
cmd.Dir = path }
err := cmd.Run()
if err != nil { func gitFetchAndMerge(path string) error {
return fmt.Errorf("error checking out repo: %v", err) if err := runGitCommand(path, []string{"fetch"}); err != nil {
return err
} }
return nil return runGitCommand(path, []string{"merge"})
} }
func gitFetch(path string) error { func runGitCommand(path string, args []string) error {
cmd := exec.Command("git", "fetch") cmd := exec.Command("git", args...)
cmd.Dir = path cmd.Dir = path
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("error fetching repo: %v", err) return fmt.Errorf("error running %q: %v", strings.Join(cmd.Args, " "), err)
} }
return nil return nil
} }
@ -145,7 +145,7 @@ type server struct {
// generateAt generates spec from repo at sha. // generateAt generates spec from repo at sha.
// Returns the path where the generation was done. // Returns the path where the generation was done.
func (s *server) generateAt(sha string) (dst string, err error) { func (s *server) generateAt(sha string) (dst string, err error) {
err = gitFetch(s.matrixDocCloneURL) err = gitFetchAndMerge(s.matrixDocCloneURL)
if err != nil { if err != nil {
return return
} }
@ -362,6 +362,8 @@ func main() {
http.HandleFunc("/diff/html/", s.serveHTMLDiff) http.HandleFunc("/diff/html/", s.serveHTMLDiff)
http.HandleFunc("/healthz", serveText("ok")) http.HandleFunc("/healthz", serveText("ok"))
http.HandleFunc("/", listPulls) http.HandleFunc("/", listPulls)
fmt.Printf("Listening on port %d\n", *port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
} }

@ -180,6 +180,8 @@ of a "Room".
Event Graphs Event Graphs
~~~~~~~~~~~~ ~~~~~~~~~~~~
.. _sect:event-graph:
Events exchanged in the context of a room are stored in a directed acyclic graph Events exchanged in the context of a room are stored in a directed acyclic graph
(DAG) called an ``event graph``. The partial ordering of this graph gives the (DAG) called an ``event graph``. The partial ordering of this graph gives the
chronological ordering of events within the room. Each event in the graph has a chronological ordering of events within the room. Each event in the graph has a
@ -332,49 +334,6 @@ Usage of an IS is not required in order for a client application to be part of
the Matrix ecosystem. However, without one clients will not be able to look up the Matrix ecosystem. However, without one clients will not be able to look up
user IDs using 3PIDs. user IDs using 3PIDs.
Presence
~~~~~~~~
Each user has the concept of presence information. This encodes:
* Whether the user is currently online
* How recently the user was last active (as seen by the server)
* Whether a given client considers the user to be currently idle
* Arbitrary information about the user's current status (e.g. "in a meeting").
This information is collated from both per-device (online; idle; last_active) and
per-user (status) data, aggregated by the user's homeserver and transmitted as
an ``m.presence`` event. This is one of the few events which are sent *outside
the context of a room*. Presence events are sent to all users who subscribe to
this user's presence through a presence list or by sharing membership of a room.
.. TODO
How do we let users hide their presence information?
.. TODO
The last_active specifics should be moved to the detailed presence event section
Last activity is tracked by the server maintaining a timestamp of the last time
it saw a pro-active event from the user. Any event which could be triggered by a
human using the application is considered pro-active (e.g. sending an event to a
room). An example of a non-proactive client activity would be a client setting
'idle' presence status, or polling for events. This timestamp is presented via a
key called ``last_active_ago``, which gives the relative number of milliseconds
since the message is generated/emitted that the user was last seen active.
N.B. in v1 API, status/online/idle state are muxed into a single 'presence'
field on the ``m.presence`` event.
Presence Lists
~~~~~~~~~~~~~~
Each user's home server stores a "presence list". This stores a list of user IDs
whose presence the user wants to follow.
To be added to this list, the user being added must be invited by the list owner
and accept the invitation. Once accepted, both user's HSes track the
subscription.
Profiles Profiles
~~~~~~~~ ~~~~~~~~

@ -1,5 +1,5 @@
Client-Server API v1 Client-Server API
==================== =================
Overview Overview
-------- --------
@ -779,13 +779,65 @@ options which can be set when creating a room:
This will tell the server to invite everyone in the list to the newly This will tell the server to invite everyone in the list to the newly
created room. created room.
``creation_content``
Type:
Object
Optional:
Yes
Value:
Extra keys to be added to the content of the ``m.room.create``. The server
will clober the following keys: ``creator``. Future versions of this
spec may allow the server to clobber other keys if required.
Description:
Allows clients to add keys to the content of ``m.room.create``.
``preset``
Type:
String
Optional:
Yes
Value:
``private_chat``, ``trusted_private_chat`` or ``public_chat``
Description:
Convenience parameter for setting various default state events based on a
preset.
Three presets are defined:
- ``private_chat``: Sets the ``join_rules`` to ``invite`` and
``history_visibility`` to ``shared``
- ``trusted_private_chat``: Set the ``join_rules`` to ``invite``,
``history_visibility`` to ``shared`` and gives all invitees the same
power level as the creator.
- ``public_chat``: Sets the ``join_rules`` to ``public`` and
``history_visibility`` to ``shared``
``initial_state``
Type:
List
Optional:
Yes
Value:
A list of state events to set in the new room.
Description:
Allows the user to override the default state events set in the new room.
The expected format of the state events are an object with ``type``,
``state_key`` and ``content`` keys set.
Takes precedence over events set by ``presets``, but gets overriden by
``name`` and ``topic`` keys.
Example:: Example::
{ {
"visibility": "public", "preset": "public_chat",
"room_alias_name": "thepub", "room_alias_name": "thepub",
"name": "The Grand Duke Pub", "name": "The Grand Duke Pub",
"topic": "All about happy hour" "topic": "All about happy hour",
"creation_content": {
"m.federate": false
}
} }
The home server will create a ``m.room.create`` event when the room is created, The home server will create a ``m.room.create`` event when the room is created,
@ -1084,6 +1136,27 @@ Profiles
{{profile_http_api}} {{profile_http_api}}
Events on Change of Profile Information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Because the profile display name and avatar information are likely to be used in
many places of a client's display, changes to these fields cause an automatic
propagation event to occur, informing likely-interested parties of the new
values. This change is conveyed using two separate mechanisms:
- a ``m.room.member`` event is sent to every room the user is a member of,
to update the ``displayname`` and ``avatar_url``.
- a ``m.presence`` presence status update is sent, again containing the new
values of the ``displayname`` and ``avatar_url`` keys, in addition to the
required ``presence`` key containing the current presence state of the user.
Both of these should be done automatically by the home server when a user
successfully changes their display name or avatar URL fields.
Additionally, when home servers emit room membership events for their own
users, they should include the display name and avatar URL fields in these
events so that clients already have these details to hand, and do not have to
perform extra round trips to query it.
Security Security
-------- --------

@ -14,7 +14,8 @@ irrespective of the underlying homeserver implementation.
Passive Application Services Passive Application Services
---------------------------- ----------------------------
"Passive" application services can only observe events from a given home server. "Passive" application services can only observe events from a given home server,
and inject events into a room they are participating in.
They cannot prevent events from being sent, nor can they modify the content of They cannot prevent events from being sent, nor can they modify the content of
the event being sent. In order to observe events from a homeserver, the the event being sent. In order to observe events from a homeserver, the
homeserver needs to be configured to pass certain types of traffic to the homeserver needs to be configured to pass certain types of traffic to the

@ -3,44 +3,31 @@ Content repository
.. _module:content: .. _module:content:
HTTP API This module allows users to upload content to their homeserver which is
-------- retrievable from other homeservers. Its' purpose is to allow users to share
attachments in a room. Content locations are represented as Matrix Content (MXC)
URIs. They look like::
Uploads are POSTed to a resource which returns a token which is used to GET mxc://<server-name>/<media-id>
the download. Uploads are POSTed to the sender's local homeserver, but are
downloaded from the recipient's local homeserver, which must thus first transfer
the content from the origin homeserver using the same API (unless the origin
and destination homeservers are the same). The upload/download API is::
=> POST /_matrix/media/v1/upload HTTP/1.1 <server-name> : The name of the homeserver where this content originated, e.g. matrix.org
Content-Type: <media-type> <media-id> : An opaque ID which identifies the content.
<media> Uploads are POSTed to a resource on the user's local homeserver which returns a
token which is used to GET the download. Content is downloaded from the
recipient's local homeserver, which must first transfer the content from the
origin homeserver using the same API (unless the origin and destination
homeservers are the same).
<= HTTP/1.1 200 OK Client behaviour
Content-Type: application/json ----------------
{ "content-uri": "mxc://<server-name>/<media-id>" } Clients can upload and download content using the following HTTP APIs.
=> GET /_matrix/media/v1/download/<server-name>/<media-id> HTTP/1.1 {{content_repo_http_api}}
<= HTTP/1.1 200 OK
Content-Type: <media-type>
Content-Disposition: attachment;filename=<upload-filename>
<media>
Clients can get thumbnails by supplying a desired width and height and
thumbnailing method::
=> GET /_matrix/media/v1/thumbnail/<server_name>
/<media-id>?width=<w>&height=<h>&method=<m> HTTP/1.1
<= HTTP/1.1 200 OK
Content-Type: image/jpeg or image/png
<thumbnail>
Thumbnails
~~~~~~~~~~
The thumbnail methods are "crop" and "scale". "scale" tries to return an The thumbnail methods are "crop" and "scale". "scale" tries to return an
image where either the width or the height is smaller than the requested image where either the width or the height is smaller than the requested
size. The client should then scale and letterbox the image if it needs to size. The client should then scale and letterbox the image if it needs to
@ -49,6 +36,9 @@ width and height are close to the requested size and the aspect matches
the requested size. The client should scale the image if it needs to fit the requested size. The client should scale the image if it needs to fit
within a given rectangle. within a given rectangle.
Server behaviour
----------------
Homeservers may generate thumbnails for content uploaded to remote Homeservers may generate thumbnails for content uploaded to remote
homeservers themselves or may rely on the remote homeserver to thumbnail homeservers themselves or may rely on the remote homeserver to thumbnail
the content. Homeservers may return thumbnails of a different size to that the content. Homeservers may return thumbnails of a different size to that
@ -58,13 +48,19 @@ Homeservers must never upscale images.
Security considerations Security considerations
----------------------- -----------------------
The HTTP GET endpoint does not require any authentication. Knowing the URL of
the content is sufficient to retrieve the content, even if the entity isn't in
the room.
Homeservers have additional concerns:
- Clients may try to upload very large files. Homeservers should not store files - Clients may try to upload very large files. Homeservers should not store files
that are too large and should not serve them to clients. that are too large and should not serve them to clients.
- Clients may try to upload very large images. Homeservers should not attempt to - Clients may try to upload very large images. Homeservers should not attempt to
generate thumbnails for images that are too large. generate thumbnails for images that are too large.
- Remote homeservers may host very large files or images. Homeserver should not - Remote homeservers may host very large files or images. Homeservers should not
proxy or thumbnail large files or images from remote homeservers. proxy or thumbnail large files or images from remote homeservers.
- Clients may try to upload a large number of files. Homeservers should limit the - Clients may try to upload a large number of files. Homeservers should limit the

@ -3,63 +3,110 @@ Presence
.. _module:presence: .. _module:presence:
Each user has the concept of presence information. This encodes the Each user has the concept of presence information. This encodes:
"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 * Whether the user is currently online
which are sent *outside the context of a room*. The basic piece of presence * How recently the user was last active (as seen by the server)
information is represented by the ``presence`` key, which is an enum of one * Whether a given client considers the user to be currently idle
of the following: * Arbitrary information about the user's current status (e.g. "in a meeting").
This information is collated from both per-device (``online``, ``idle``,
``last_active``) and per-user (status) data, aggregated by the user's homeserver
and transmitted as an ``m.presence`` event. This is one of the few events which
are sent *outside the context of a room*. Presence events are sent to all users
who subscribe to this user's presence through a presence list or by sharing
membership of a room.
A presence list is a list of user IDs whose presence the user wants to follow.
To be added to this list, the user being added must be invited by the list owner
who must accept the invitation.
User's presence state is represented by the ``presence`` key, which is an enum
of one of the following:
- ``online`` : The default state when the user is connected to an event - ``online`` : The default state when the user is connected to an event
stream. stream.
- ``unavailable`` : The user is not reachable at this time. - ``unavailable`` : The user is not reachable at this time e.g. they are
- ``offline`` : The user is not connected to an event stream. idle.
- ``offline`` : The user is not connected to an event stream or is
explicitly suppressing their profile information from being sent.
- ``free_for_chat`` : The user is generally willing to receive messages - ``free_for_chat`` : The user is generally willing to receive messages
moreso than default. moreso than default.
- ``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).
In addition, the server maintains a timestamp of the last time it saw a
pro-active event 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`` counts as a
proactive event, whereas in the other direction it will not). This timestamp
is presented via a key called ``last_active_ago``, which gives the relative
number of milliseconds since the message is generated/emitted that the user
was last seen active.
Events Events
------ ------
{{presence_events}} {{presence_events}}
Presence HTTP API Client behaviour
----------------- ----------------
.. TODO-spec
- Define how users receive presence invites, and how they accept/decline them Clients can manually set/get their presence/presence list using the HTTP APIs
listed below.
{{presence_http_api}} {{presence_http_api}}
Idle timeout
~~~~~~~~~~~~
Clients SHOULD implement an "idle timeout". This is a timer which fires after
a period of inactivity on the client. The definition of inactivity varies
depending on the client. For example, web implementations may determine
inactivity to be not moving the mouse for a certain period of time. When this
timer fires it should set the presence state to ``unavailable``. When the user
becomes active again (e.g. by moving the mouse) the client should set the
presence state to ``online``. A timeout value between 1 and 5 minutes is
recommended.
Server behaviour
----------------
Each user's home server stores a "presence list" per user. Once a user accepts
a presence list, both user's HSes must track the subscription.
Propagating profile information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Because the profile display name and avatar information are likely to be used in
many places of a client's display, changes to these fields SHOULD cause an
automatic propagation event to occur, informing likely-interested parties of the
new values. One of these change mechanisms SHOULD be via ``m.presence`` events.
These events should set ``displayname`` and ``avatar_url`` to the new values
along with the presence-specific keys. This SHOULD be done automatically by the
home server when a user successfully changes their display name or avatar URL.
.. admonition:: Rationale
The intention for sending this information in ``m.presence`` is so that any
"user list" can display the *current* name/presence for a user ID outside the
scope of a room e.g. for a user page. This is bundled into a single event for
several reasons. The user's display name can change per room. This
event provides the "canonical" name for the user. In addition, the name is
bundled into a single event for the ease of client implementations. If this
was not done, the client would need to search all rooms for their own
membership event to pull out the display name.
Last active ago
~~~~~~~~~~~~~~~
The server maintains a timestamp of the last time it saw a
pro-active event from the user. A pro-active event may be sending a message to a
room or changing presence state to a higher level of availability. Levels of
availability are defined from low to high as follows:
Events on Change of Profile Information - ``offline``
--------------------------------------- - ``unavailable``
Because the profile displayname and avatar information are likely to be used in - ``online``
many places of a client's display, changes to these fields cause an automatic - ``free_for_chat``
propagation event to occur, informing likely-interested parties of the new
values. This change is conveyed using two separate mechanisms:
- a ``m.room.member`` event is sent to every room the user is a member of, Based on this list, changing state from ``unavailable`` to ``online`` counts as
to update the ``displayname`` and ``avatar_url``. a pro-active event, whereas ``online`` to ``unavailable`` does not. This
- a ``m.presence`` presence status update is sent, again containing the new values of the timestamp is presented via a key called ``last_active_ago`` which gives the
``displayname`` and ``avatar_url`` keys, in addition to the required relative number of milliseconds since the pro-active event.
``presence`` key containing the current presence state of the user.
Both of these should be done automatically by the home server when a user Security considerations
successfully changes their displayname or avatar URL fields. -----------------------
Additionally, when home servers emit room membership events for their own Presence information is shared with all users who share a room with the target
users, they should include the displayname and avatar URL fields in these user. In large public rooms this could be undesirable.
events so that clients already have these details to hand, and do not have to
perform extra roundtrips to query it.

@ -1,49 +1,46 @@
Typing Notifications Typing Notifications
-------------------- ====================
.. _module:typing: .. _module:typing:
Client APIs Users may wish to be informed when another user is typing in a room. This can be
~~~~~~~~~~~ achieved using typing notifications. These are ephemeral events scoped to a
``room_id``. This means they do not form part of the `Event Graph`_ but still
have a ``room_id`` key.
To set "I am typing for the next N msec":: .. _Event Graph: `sect:event-graph`_
PUT .../rooms/<room_id>/typing/<user_id> Events
Content: { "typing": true, "timeout": N } ------
# timeout is in milliseconds; suggested no more than 20 or 30 seconds
This should be re-sent by the client to continue informing the server the user {{m_typing_event}}
is still typing; a safety margin of 5 seconds before the expected
timeout runs out is recommended. Just keep declaring a new timeout, it will
replace the old one.
To set "I am no longer typing":: Client behaviour
----------------
PUT ../rooms/<room_id>/typing/<user_id> When a client receives an ``m.typing`` event, it MUST use the user ID list to
Content: { "typing": false } **REPLACE** its knowledge of every user who is currently typing. The reason for
this is that the server *does not remember* users who are not currently typing
as that list gets big quickly. The client should mark as not typing any user ID
who is not in that list.
Client Events It is recommended that clients store a ``boolean`` indicating whether the user
~~~~~~~~~~~~~ is typing or not. Whilst this value is ``true`` a timer should fire periodically
every N seconds to send a typing HTTP request. The value of N is recommended to
be no more than 20-30 seconds. This request should be re-sent by the client to
continue informing the server the user is still typing. As subsequent
requests will replace older requests, a safety margin of 5 seconds before the
expected timeout runs out is recommended. When the user stops typing, the
state change of the ``boolean`` to ``false`` should trigger another HTTP request
to inform the server that the user has stopped typing.
All room members will receive an event on the event stream:: {{typing_http_api}}
{ Server behaviour
"type": "m.typing", ----------------
"room_id": "!room-id-here:matrix.org",
"content": {
"user_ids": ["list of", "every user", "who is", "currently typing"]
}
}
The client must use this list to *REPLACE* its knowledge of every user who is Servers MUST emit typing EDUs in a different form to ``m.typing`` events which
currently typing. The reason for this is that the server DOES NOT remember are shown to clients. This form looks like::
users who are not currently typing, as that list gets big quickly. The client
should mark as not typing, any user ID who is not in that list.
Server APIs
~~~~~~~~~~~
Servers will emit EDUs in the following form::
{ {
"type": "m.typing", "type": "m.typing",
@ -54,10 +51,16 @@ Servers will emit EDUs in the following form::
} }
} }
Server EDUs don't (currently) contain timing information; it is up to This does not contain timing information so it is up to originating homeservers
originating HSes to ensure they eventually send "stop" notifications. to ensure they eventually send "stop" notifications.
.. TODO .. TODO
((This will eventually need addressing, as part of the wider typing/presence ((This will eventually need addressing, as part of the wider typing/presence
timer addition work)) timer addition work))
Security considerations
-----------------------
Clients may not wish to inform everyone in a room that they are typing and
instead only specific users in the room.

@ -1 +1,25 @@
<div id="footer"><div id="footerContent">&copy 2014-2015 Matrix.org</div></div> <div id="footer"><div id="footerContent">&copy 2014-2015 Matrix.org</div></div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-54779209-1', 'auto');
ga('send', 'pageview');
</script>
<script type='text/javascript'>
/* <![CDATA[ */
var tocplus = {"smooth_scroll":"1"};
/* ]]> */
</script>
<script type='text/javascript' src='https://matrix.org/blog/wp-content/plugins/table-of-contents-plus/front.min.js?ver=1509'></script>
<script type='text/javascript' src='https://matrix.org/blog/wp-content/themes/Divi-child/js/jquery.fitvids.js?ver=2.2'></script>
<script type='text/javascript' src='https://matrix.org/blog/wp-content/themes/Divi-child/js/waypoints.min.js?ver=2.2'></script>
<script type='text/javascript' src='https://matrix.org/blog/wp-content/themes/Divi-child/js/jquery.magnific-popup.js?ver=2.2'></script>
<script type='text/javascript'>
/* <![CDATA[ */
var et_custom = {"ajaxurl":"https:\/\/matrix.org\/blog\/wp-admin\/admin-ajax.php","images_uri":"https:\/\/matrix.org\/blog\/wp-content\/themes\/Divi-child\/images","et_load_nonce":"dc61fa2f94","subscription_failed":"Please, check the fields below to make sure you entered the correct information.","fill":"Fill","field":"field","invalid":"Invalid email","captcha":"Captcha","prev":"Prev","next":"Next"};
/* ]]> */
</script>
<script type='text/javascript' src='https://matrix.org/blog/wp-content/themes/Divi-child/js/custom.js?ver=2.2'></script>

@ -12,5 +12,20 @@
<link rel="stylesheet" href="{{ "/css/basic.css" | prepend: site.baseurl }}"> <link rel="stylesheet" href="{{ "/css/basic.css" | prepend: site.baseurl }}">
<link rel="stylesheet" href="{{ "/css/nature.css" | prepend: site.baseurl }}"> <link rel="stylesheet" href="{{ "/css/nature.css" | prepend: site.baseurl }}">
<link rel='stylesheet' id='toc-screen-css' href='https://matrix.org/blog/wp-content/plugins/table-of-contents-plus/screen.min.css?ver=1509' type='text/css' media='all' />
<link rel='stylesheet' id='divi-fonts-css' href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,700italic,800italic,400,300,700,800&#038;subset=latin,latin-ext' type='text/css' media='all' />
<link rel='stylesheet' id='divi-style-css' href='https://matrix.org/blog/wp-content/themes/Divi-child/style.css?ver=2.2' type='text/css' media='all' />
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}"> <link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}">
<link rel="alternate" type="application/rss+xml" title="{{ site.title }}" href="{{ "/feed.xml" | prepend: site.baseurl | prepend: site.url }}" /> <link rel="alternate" type="application/rss+xml" title="{{ site.title }}" href="{{ "/feed.xml" | prepend: site.baseurl | prepend: site.url }}" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-54779209-1', 'auto');
ga('send', 'pageview');
</script>

@ -1,22 +1,33 @@
<div id="header"> <header id="main-header" class="et_nav_text_color_dark et-fixed-header">
<div id="headerContent"> <div class="container clearfix" >
<a href="https://matrix.org/blog/">
<a href="/#about2" class="navButton">About</a> <img src="https://matrix.org/blog/wp-content/uploads/2015/01/logo1.png" alt="Matrix.org" id="logo" />
<a href="/docs/howtos" class="navButton">HOWTOs</a> </a>
<a href="/docs/spec" class="navButton">Spec</a> <div id="et-top-navigation">
<a href="/docs/api" class="navButton">APIs</a> <nav id="top-menu-nav">
<a href="/code" class="navButton">Code</a> <ul id="top-menu" class="nav"><li id="menu-item-17" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-17"><a href="http://matrix.org/">Home</a></li>
<a href="/jira" class="navButton">JIRA</a> <li id="menu-item-794" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-794"><a href="https://matrix.org/blog/try-matrix-now">Try Matrix Now!</a></li>
<a href="/blog/faq" class="navButton">FAQ</a> <li id="menu-item-348" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-348"><a href="/docs/howtos">HOWTOs</a></li>
<a href="/blog" class="navButton">Blog</a> <li id="menu-item-349" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-349"><a href="/docs/spec">Spec</a></li>
<script> <li id="menu-item-350" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-350"><a href="/docs/api">APIs</a></li>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ <li id="menu-item-351" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-351"><a href="/code">Code</a></li>
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), <li id="menu-item-352" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-352"><a href="/jira">JIRA</a></li>
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) <li id="menu-item-347" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-347"><a href="https://matrix.org/blog/faq/">FAQ</a></li>
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); <li id="menu-item-353" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-353"><a href="/blog">Blog</a></li>
</ul>
ga('create', 'UA-54779209-1', 'auto'); </nav>
ga('send', 'pageview'); <div id="et_top_search">
</script> <span id="et_search_icon"></span>
</div> <form role="search" method="get" class="et-search-form et-hidden" action="https://matrix.org/blog/">
</div> <input type="search" class="et-search-field" placeholder="Search &hellip;" value="" name="s" title="Search for:" />
</form>
</div>
<div id="et_mobile_nav_menu">
<a href="#" class="mobile_nav closed">
<span class="select_page">Select Page</span>
<span class="mobile_menu_bar"></span>
</a>
</div>
</div> <!-- #et-top-navigation -->
</div> <!-- .container -->
</header> <!-- #main-header -->

@ -4,9 +4,12 @@
{% include head.html %} {% include head.html %}
</head> </head>
<body> <body class="blog et_fixed_nav et_cover_background linux et_right_sidebar chrome">
<div class="page-content" id="page">
<div class="page-content" id="page-container" style="padding-top: 78px;">
{% include nav.html %} {% include nav.html %}
<div id="main-content">
<div class="wrapper" id="wrapper"> <div class="wrapper" id="wrapper">
<div class="document_foo" id="document"> <div class="document_foo" id="document">
{{ content }} {{ content }}

@ -33,6 +33,8 @@ You can use multiple clients with the same user, so you might want to also look
## Run a server and/or client yourself ## Run a server and/or client yourself
You can clone our open source projects and run clients and servers yourself. Here is how:
### Running your own client: ### Running your own client:
You can run your own Matrix client; there are [numerous clients available](https://matrix.org/blog/try-matrix-now/). You can take Matrix.org's [reference client](https://github.com/matrix-org/matrix-angular-sdk) and use it as-is - or modify it any way you want! Since it's written in JavaScript, running a client is [really easy](https://github.com/matrix-org/matrix-angular-sdk#running)! You can run your own Matrix client; there are [numerous clients available](https://matrix.org/blog/try-matrix-now/). You can take Matrix.org's [reference client](https://github.com/matrix-org/matrix-angular-sdk) and use it as-is - or modify it any way you want! Since it's written in JavaScript, running a client is [really easy](https://github.com/matrix-org/matrix-angular-sdk#running)!
@ -98,6 +100,7 @@ curl -XGET "http://localhost:8008/_matrix/client/api/v1/events?access_token=YOUR
"end": "s39_18_0", "end": "s39_18_0",
"start": "s39_18_0" "start": "s39_18_0"
} }
7. Even if there are no new events (as in the example above), there will be some pagination stream response keys. The client should make subsequent requests using the value of the "end" key (in this case s39_18_0) as the from query parameter e.g. 7. Even if there are no new events (as in the example above), there will be some pagination stream response keys. The client should make subsequent requests using the value of the "end" key (in this case s39_18_0) as the from query parameter e.g.
``` ```
http://localhost:8008/_matrix/client/api/v1/events?access _token=YOUR_ACCESS_TOKEN&from=s39_18_0 http://localhost:8008/_matrix/client/api/v1/events?access _token=YOUR_ACCESS_TOKEN&from=s39_18_0
@ -105,6 +108,8 @@ http://localhost:8008/_matrix/client/api/v1/events?access _token=YOUR_ACCESS_TOK
8. This ensures that you only get new events. Now you have initial rooms and presence, and a stream of events - a good client should be able to process all these events and present them to the user. And potentially you might want to add functionality to generate events as well (such as messages from the user, for example) - again please consult the [client-server API spec](http://matrix.org/docs/howtos/client-server.html)! 8. This ensures that you only get new events. Now you have initial rooms and presence, and a stream of events - a good client should be able to process all these events and present them to the user. And potentially you might want to add functionality to generate events as well (such as messages from the user, for example) - again please consult the [client-server API spec](http://matrix.org/docs/howtos/client-server.html)!
|
### Write your own server: ### Write your own server:
We are still working on the server-server spec, so the best thing to do if you are interested in writing a server, is to come talk to us in [#matrix:matrix.org](https://matrix.org/beta/#/room/%23matrix:matrix.org). We are still working on the server-server spec, so the best thing to do if you are interested in writing a server, is to come talk to us in [#matrix:matrix.org](https://matrix.org/beta/#/room/%23matrix:matrix.org).

@ -19,9 +19,7 @@ Categories
[Standard](#standard) [Standard](#standard)
[APIs](#apis) [Implementations](#implementations)
[Reference Implementations](#reference-implementations)
| |
@ -31,65 +29,98 @@ FAQ Content
* TOC * TOC
{:toc} {:toc .toc}
### General ### General
##### What is Matrix? ##### What is Matrix?
Matrix is an ambitious new open standard for open, distributed, Matrix is an open standard for interoperable, decentralised,
real-time communication over IP. It defines interoperable Instant real-time communication over IP. It can be used to power Instant
Messaging and VoIP, providing pragmatic HTTP APIs and open source Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere
reference implementations for creating and running your own real-time you need a standard HTTP API for publishing and subscribing to
communication infrastructure. data whilst tracking the conversation history.
|
Matrix defines the standard, and provides open source reference implementations
of Matrix-compatible Servers, Clients, Client SDKs and Application Services
to help you create new communication solutions or extend the capabilities
and reach of existing ones.
##### What is Matrix's Mission? ##### What is Matrix's Mission?
Matrix.org's initial inspiration and goal has been to fix the problem of Matrix's initial goal is to fix the problem of fragmented IP communications:
fragmented IP communications. But Matrix's real potential and ultimate letting users message and call each other without having to care what app
mission is to be a generic messaging and data synchronisation system for the other user is on - making it as easy as sending an email.
the web - allowing people, services and devices to easily communicate
with each other with full history. |
The longer term goal is for Matrix to act as a generic HTTP messaging and data
synchronisation system for the whole web - allowing people, services and devices
to easily communicate with each other, empowering users to own and control their
data and select the services and vendors they want to use.
##### What does Matrix provide? ##### What does Matrix provide?
Today Matrix provides a new [open standard](/docs/spec), Matrix provides:
[APIs](/docs/api) to integrate a service to the Matrix ecosystem and
reference [open source - [Open Standard](/docs/spec) HTTP APIs for transferring JSON messages (e.g. instant messages, WebRTC signalling), including:
implementations](http://github.com/matrix-org/synapse) of the standard. - [Client\<-\>Server API](/docs/spec#client-server-api-v1) - defines how Matrix compatible clients communicate with Matrix homeservers.
- [Server\<-\>Server API](/docs/spec#federation-api) - defines how Matrix homeservers exchange messages and synchronise history with each other.
- [Application Service API](/docs/spec/#application-service-api) - defines how to extend the functionality of Matrix with 'integrations' and bridge to other networks.
- [Modules](/docs/spec/#modules) - specifies features that must be implemented by particular classes of clients.
- Open source reference implementations of:
- Clients (Web (React), iOS, Android)
- Client SDKs (Javascript, Web (React), iOS, Android)
- Homeservers (Synapse)
- Application Services (bridges to IRC, Slack, Skype, Lync and more...)
- The actual ecosystem and community of everyone running Matrix servers and services
- Loads of 3rd party contributions of clients, SDKs, servers and services.
You can find the full list of Matrix enabled projects at https://matrix.org/blog/try-matrix-now.
##### What does this mean for users? ##### What does this mean for users?
The aim is to provide an analogous ecosystem to email - one where you The aim is to provide an analogous ecosystem to email - one where you
can communicate with pretty much anyone, without caring what app or can communicate with pretty much anyone, without caring what app or
server they are using, using whichever app & server you chose to use, server they are using, using whichever app & server you chose to use,
and a nice neutral identity system like an e-mail address or phone and use a neutral identity system like an e-mail address or phone
number to discover people to talk to. number to discover people to talk to.
##### What kind of company is Matrix.org? ##### What kind of company is Matrix.org?
Matrix is an open initiative which acts as a neutral custodian of the Matrix is an open initiative which acts as a neutral custodian of the
Matrix standard. It's not actually incorporated anywhere at the moment Matrix standard. It's not actually incorporated anywhere at the moment
but we are looking at the best legal structure for the future. We are but we are looking at the best legal structure for the future (and as
committed to keeping the Matrix project open. of October 2015 we have hopefully found one). Whatever the legal
structure, we are committed to keeping the Matrix project open.
##### Who is funding Matrix.org? ##### Who is funding Matrix.org?
We have been given permission by our employers, Amdocs, to work on Most of the current core contributors to Matrix work at
Matrix as an independent non-profit initiative. [Amdocs](http://amdocs.com), who have kindly given us permission to work
on Matrix as an independent non-profit initiative. Other contributors
are funded by their own employers or donate their own time to the project.
##### Who is building Matrix? ##### Who is building Matrix?
We're a team of ~10 people with decades of experience building custom The core team is ~10 people with extensive experience in building custom
VoIP and Messaging apps for mobile network operators. Most of us have VoIP and Messaging apps for mobile network operators. Most of us have
day jobs at Amdocs or OpenMarket, but we are supported by a mix of day jobs at [Amdocs](http://amdocs.com) or [OpenMarket](http://openmarket.com),
freelancers and volunteers. but there are an increasing number of contributors from other companies and
folks all over the internet.
##### Why are you called Matrix? ##### Why are you called Matrix?
We are called Matrix because we provide a structure in which all We are called Matrix because we provide a structure in which all
communication can be matrixed together. communication can be matrixed together.
|
No, it's nothing to do with the film (although you could go and build virtual
worlds on top of Matrix if you wanted :)
##### Why have you released this as open source? ##### Why have you released this as open source?
We believe that any open standard defining interoperable communication We believe that any open standard defining interoperable communication
@ -102,16 +133,18 @@ and build on top of it.
##### What do you mean by open? ##### What do you mean by open?
Matrix is an open standard, meaning that we have freely published the Matrix is an open standard, meaning that we have freely published the
details for how to interface with Matrix compliant servers and clients, details for how to communicate interoperably using the Matrix set of
and encourage anyone and everyone to interface with them.  We also HTTP APIs. We encourage anyone and everyone to use the APIs and build
their own projects which implement them and so benefit from
interoperability with the rest of the Matrix ecosystem. We also
ensure the standard is not encumbered by any known patent licensing ensure the standard is not encumbered by any known patent licensing
requirements. requirements.
| |
Matrix is also open source, meaning that we have released the source Matrix is also open source, meaning that we have released the source
code of the reference servers and clients to the public domain under the code of the reference servers, clients and services to the public domain
[Apache Licence v2](http://www.apache.org/licenses/LICENSE-2.0.html), to under the [Apache Licence v2](http://www.apache.org/licenses/LICENSE-2.0.html), to
encourage anyone and everyone to run their own servers and clients, and encourage anyone and everyone to run their own servers and clients, and
enhance them and contribute their enhancements as they see fit. enhance them and contribute their enhancements as they see fit.
@ -120,7 +153,7 @@ enhance them and contribute their enhancements as they see fit.
Federation allows separate deployments of a communication service to Federation allows separate deployments of a communication service to
communicate with each other - for instance a mail server run by Google communicate with each other - for instance a mail server run by Google
federates with a mail server run by Microsoft when you send email from federates with a mail server run by Microsoft when you send email from
@gmail.com to @outlook.com. @gmail.com to @hotmail.com.
| |
@ -145,16 +178,18 @@ VoIP and IM.
##### Why has no-one done this before? ##### Why has no-one done this before?
There have been several attempts before including SIP, XMPP and RCS. There have been several attempts before including SIP, XMPP and RCS.
 All of these have had some level of success, but  All of these have had some level of success, but many different
technological/usability/economic factors have ended up limiting their technological/usability/economic factors have ended up limiting their
success in providing true open federation. success. Unfortunately, we've not ended up in a world where everyone
has a SIP URI or Jabber ID on their business card, or a phone that
actually uses RCS.
##### What is the difference between Matrix and IRC? ##### What is the difference between Matrix and IRC?
We love IRC.  In fact, as of today the core Matrix team still uses it as We love IRC.  In fact, as of today the core Matrix team still uses it as
our primary communication tool. Between us we've written IRCds, IRC bots our primary communication tool. Between us we've written IRCds, IRC bots
and admined dreamforge, UnrealIRCd, epona, ircservices and several and admined dreamforge, UnrealIRCd, epona, ircservices and several
others.  That said, it has some limitations that Matrix seeks to improve others. That said, it has some limitations that Matrix seeks to improve
on: on:
- Text only - Text only
@ -163,18 +198,24 @@ on:
- No presence support - No presence support
- Fragmented identity model - Fragmented identity model
- No open federation - No open federation
- No standard APIs, just an archaic TCP line protocol - No standard APIs, just a rather limited TCP line protocol
- Non-standardised federation protocol - Non-standardised federation protocol
- No built-in end-to-end encryption - No built-in end-to-end encryption
- Disruptive net-splits - Disruptive net-splits
- Non-extensible - Non-extensible
[IRCv3](http://ircv3.net) exists and is addressing some of issues;
this is great news and we wish them well. It's almost a contradiction
in terms to get competitive between openly interoperable communication
projects - we look forward to increasing the richness of Matrix\<-\>IRC
bridges as the project progresses.
##### What is the difference between Matrix and XMPP? ##### What is the difference between Matrix and XMPP?
The Matrix team used XMPP (Openfire, ejabberd, spectrum, asmack, The Matrix team used XMPP (Openfire, ejabberd, spectrum, asmack,
XMPPFramework) for IM before starting to experiment with open HTTP APIs XMPPFramework) for IM before starting to experiment with open HTTP APIs
as an alternative.   The main issues with XMPP that drove us in this as an alternative in around 2012. The main issues with XMPP that
direction were: drove us in this direction were:
- Not particularly web-friendly - you can't easily speak XMPP from a - Not particularly web-friendly - you can't easily speak XMPP from a
web browser. (N.B. Nowadays you have options like XMPP-FTW and web browser. (N.B. Nowadays you have options like XMPP-FTW and
@ -182,8 +223,8 @@ direction were:
- Single logical server per MUC is a single point of control and - Single logical server per MUC is a single point of control and
availability. (MUCs can be distributed over multiple physical availability. (MUCs can be distributed over multiple physical
servers, but they still sit behind a single logical JID and domain. servers, but they still sit behind a single logical JID and domain.
FMUC improves this with a similar approach to Matrix, but at time of FMUC improves this with a similar approach to Matrix, but as of Oct
writing there are no open implementations.) 2015 there are no open source implementations.)
- History synchronisation is very much a second class citizen feature - History synchronisation is very much a second class citizen feature
- Stanzas aren't framed or reliably delivered without extensions. (See - Stanzas aren't framed or reliably delivered without extensions. (See
[wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Four:_XMPP_is_unreliable_without_a_bunch_of_extensions.) [wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Four:_XMPP_is_unreliable_without_a_bunch_of_extensions.)
@ -191,7 +232,8 @@ direction were:
- Multiple device support is limited. (Apparently Carbons and MAM help - Multiple device support is limited. (Apparently Carbons and MAM help
with this) with this)
- Baseline feature set is so minimal that fragmentation of features - Baseline feature set is so minimal that fragmentation of features
between clients and servers is common between clients and servers is common, especially as interoperability
profiles for features have fallen behind (as of July 2015)
- No strong identity system (i.e. no standard E2E PKI, unless you - No strong identity system (i.e. no standard E2E PKI, unless you
count X.509 certs, which [are count X.509 certs, which [are
questionable](http://www.thoughtcrime.org/blog/ssl-and-the-future-of-authenticity/)) questionable](http://www.thoughtcrime.org/blog/ssl-and-the-future-of-authenticity/))
@ -199,31 +241,42 @@ direction were:
bandwidth-efficient transports. (Since the time of writing a [Push bandwidth-efficient transports. (Since the time of writing a [Push
XEP has appeared](http://xmpp.org/extensions/xep-0357.html), and XEP has appeared](http://xmpp.org/extensions/xep-0357.html), and
[wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Three:_It.27s_too_bandwidth-inefficient_for_mobile.) [wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Three:_It.27s_too_bandwidth-inefficient_for_mobile.)
claims that XMPP runs fine over a 9600bps + 30s latency link.) claims that XMPP runs "fine" over a 9600bps + 30s latency link.)
The whole subject of XMPP vs Matrix seems to bring out the worst in The whole subject of XMPP vs Matrix seems to bring out the worst in
people. We think of the standards as being quite different; at its core people. Rather than fighting over which open interoperable communication
standard works the best, we should just collaborate and bridge everything
together. The more federation and interoperability the better.
|
We think of Matrix and XMPP as being quite different; at its core
Matrix can be thought of as an eventually consistent global JSON db with Matrix can be thought of as an eventually consistent global JSON db with
an HTTP API and pubsub semantics - whilst XMPP can be thought of as a an HTTP API and pubsub semantics - whilst XMPP can be thought of as a
message passing protocol. You can use them both to build chat systems; message passing protocol. You can use them both to build chat systems;
you can use them both to build pubsub systems; each comes with different you can use them both to build pubsub systems; each comes with different
tradeoffs. Matrix has a 'kitchen sink' baseline of functionality; XMPP tradeoffs. Matrix has a deliberately extensive 'kitchen sink' baseline
has a deliberately minimal baseline set of functionality. If XMPP does of functionality; XMPP has a deliberately minimal baseline set of
what you need it to do, then we're genuinely happy for you :) Meanwhile, functionality. If XMPP does what you need it to do, then we're genuinely
rather than competing, an XMPP Bridge like [Skaverat's xmpptrix happy for you :) Meanwhile, rather than competing, an XMPP Bridge like
beta](https://github.com/SkaveRat/xmpptrix) has potential to let both [Skaverat's xmpptrix beta](https://github.com/SkaveRat/xmpptrix) or
environments coexist and make the most of each other's benefits. [jfred's matrix-xmpp-bridge](https://github.com/jfrederickson/matrix-xmpp-bridge)
or Matrix.org's own [matrix-appservice-purple](https://github.com/matrix-org/matrix-appservice-purple)
has potential to let both environments coexist and make the most of each
other's benefits.
##### What is the difference between Matrix and PSYC? ##### What is the difference between Matrix and PSYC?
PSYC is a open federated messaging protocol loosely inspired by IRC.  In PSYC is a open federated messaging protocol loosely inspired by IRC.  In
version 1 it was a standalone protocol, and in version 2 it is being version 1 it was a standalone protocol, and in version 2 it is being
reutilised as the messaging layer on top of GNUnet.  We honestly don't reutilised as a messaging layer on top of GNUnet.  We honestly don't
know that much about it, beyond trying to use psycd as an XMPP\<-\>IRC know that much about it, beyond trying to use psycd as an XMPP\<-\>IRC
bridge in 2010. Matrix differentiates primarily by providing simple HTTP bridge in 2010. Matrix differentiates primarily by providing simple HTTP
APIs rather than the more exotic compact line protocol in PSYC v1 or the APIs rather than the more exotic compact line protocol in PSYC v1 or the
complicated GNUnet stack in v2.  Meanwhile, Matrix doesn't provide of comprehensive GNUnet stack in v2, and Matrix focuses more on decentralised
the metadata protection guarantees that GNUnet/PSYC aims for. conversation history rather than just decentralised chat servers.
On the other hand, Matrix doesn't provide the metadata protection
guarantees that GNUnet/PSYC aims for.
| |
@ -233,29 +286,56 @@ PSYC's views on Matrix.
##### What is the difference between Matrix and Tox? ##### What is the difference between Matrix and Tox?
Tox.im looks to be a very cool clone of Skype - a fully decentralised Tox.im looks to be a very cool clone of Skype - a fully decentralised
peer-to-peer network.  Matrix is deliberately not peer-to-peer; instead peer-to-peer network.  Matrix is deliberately not a 'pure' peer-to-peer
each user has a well-defined homeserver which stores his data and that system; instead each user has a well-defined homeserver which stores
he can depend upon.  Matrix provides HTTP APIs; Tox.im provides C APIs. his data and that he can depend upon.  Matrix provides HTTP APIs;
 We haven't actually played with Tox at all yet. Tox.im provides C APIs. As of October 2015 Tox doesn't seem to have an
answer yet for decentralised conversation history storage.
##### How does Matrix compare with something like Trillian or Pidgin? ##### How does Matrix compare with something like Trillian or Pidgin?
Trillian and Pidgin and similar aggregating IM clients merge all your IM Trillian and Pidgin and similar aggregating IM clients merge all your IM
activity into a single user experience.  However, your history and activity into a single app.  However, your history and
identity is still fragmented across the networks.  People can't find you identity is still fragmented across the networks.  People can't find you
easily, and your history is fragmented (other than on the device easily, and your history is fragmented (other than on the device
where the client runs).   And rather than being able to chose the right where the client runs).   And rather than being able to chose the right
app for the job when communicating with people, you are pushed towards app for the job when communicating with people, you are pushed towards
relying on a specific aggregation app. relying on a specific aggregation app.
Matrix lets you get the best of both worlds by linking to all the
different networks (XMPP, AIM, ICQ, Lync, Skype etc) on the serverside,
using bridges which can be run by anyone. Matrix then provides a simple
standard HTTP API to access any of these networks, and lets you choose
whichever client you prefer (either as a 'native' Matrix client or using
a non-Matrix client from one of the networks which has been bridged in).
##### What Matrix compliant apps are there? ##### What Matrix compliant apps are there?
None yet, other than our examples.  It's early days :) Quite a few, ranging from the glossy mass-market to the geeky command-line. There's even an emacs macro. Check out [https://matrix.org/blog/try-matrix-now] for the current
list of Matrix enabled projects.
##### What bridges to other networks are available?
##### Why do you think existing apps will ever join this? The number of 'bridges' which integrate existing communication networks into
Matrix are growing on a daily basis - both written by the Matrix core team
and contributed by the wider community. The full list can be seen at
https://matrix.org/blog/try-matrix-now, but the core ones as of Oct 2015 include:
* [matrix-appservice-irc](https://github.com/matrix-org/matrix-appservice-irc) - an increasingly comprehensive Matrix\<-\>IRC bridge
* [matrix-appservice-verto](https://github.com/matrix-org/matrix-appservice-verto) - links from Matrix to FreeSWITCH via the Verto protocol
* [matrix-appservice-slack](https://github.com/matrix-org/matrix-appservice-slack) - a basic bridge to Slack
* [matrix-appservice-purple](https://github.com/matrix-org/matrix-appservice-purple) - lets you access any of the 20+ protocols supported by
[libpurple](https://developer.pidgin.im/wiki/WhatIsLibpurple), including
Skype, Lync, XMPP, etc)
* [matrix-appservice-bridge](https://github.com/matrix-org/matrix-appservice-bridge) - a general NodeJS framework for writing bridges
Writing new bridges is incredibly fun and easy - see the [matrix-appservice-bridge HOWTO](https://github.com/matrix-org/matrix-appservice-bridge/blob/master/HOWTO.md)
for an example of how to write a fully functional Slack bridge in less than 100 lines of code!
##### Why do you think existing apps will ever join this officially?
We firmly believe it is what is right for the consumer. As people begin We firmly believe it is what is right for the consumer. As people begin
to use interoperable communications tools service providers will see the to use interoperable communications tools, service providers will see the
benefit and compete on quality of service, security and features rather benefit and compete on quality of service, security and features rather
than relying on locking people into their walled garden. We believe as than relying on locking people into their walled garden. We believe as
soon as users see the availability and benefits of interoperable soon as users see the availability and benefits of interoperable
@ -264,28 +344,27 @@ services they will demand it.
##### Why aren't you doing this through the IETF? or W3C? or 3GPP? ##### Why aren't you doing this through the IETF? or W3C? or 3GPP?
We do recognise the advantages of working with existing standards We do recognise the advantages of working with existing standards
bodies. We have been focused on writing code and getting it out. As bodies. We have been focused on writing code and getting it out, and the standard has been evolving rapidly since initial release in September 2014.
Matrix matures it may well be appropriate to work with an official Once the standard has matured sufficiently it may well be appropriate to work with an official
standard body. standard body to maintain it going forwards.
|
### Quick Start ### Quick Start
##### How do I get an account and get started? ##### How do I get an account and get started?
The quickest way is to just jump to the demo webclient at The quickest way is to pick a client from https://matrix.org/blog/try-matrix-now and sign up.
[http://matrix.org/beta](http://matrix.org/beta) and sign up.  Please note that you can point the Please note that you can point clients to access any homeserver - you don't have to use matrix.org,
webclient to access any homeserver - you don't have to use matrix.org,
although as of day 1, matrix.org is the only communal homeserver although as of day 1, matrix.org is the only communal homeserver
available. available.
##### What can I actually do with this? ##### What can I actually do with this?
The demo webclient provides a simple chatroom interface to Matrix - A typical client provides a simple chatroom interface to Matrix -
letting the user interact with users and rooms anywhere within the letting the user interact with users and rooms anywhere within the
Matrix federation.  Text and image messages are supported, and basic Matrix federation.  Text and image messages are supported, and basic
voice-only VoIP calling via WebRTC is supported in one-to-one rooms. voice-only VoIP calling via WebRTC is supported in one-to-one rooms.
(As of October 2015, experimental multi-way calling is also available
on Vector.im).
##### How do I connect my homeserver to the public Matrix network? ##### How do I connect my homeserver to the public Matrix network?
@ -295,11 +374,21 @@ for details
##### How do I Matrix-enable my existing app? ##### How do I Matrix-enable my existing app?
See the [Client-Server API If your app doesn't have any communication capability already, you'll want
HOWTO](http://matrix.org/docs/howtos/client-server.html) for an example to use one of the Matrix client SDKs to add it in. These come in different
of how to use Matrix's client-server API to let your app communicate levels of sophistication - ranging from a simple HTTP API wrapper (like matrix-js-sdk, matrix-ios-sdk or matrix-android-sdk)
with users via Matrix.  We're currently working out the best way to through to reusable UI components (like matrix-react-sdk and matrix-ios-kit). Pick
integrate your application's existing identity system with Matrix. the one for your platform, or a 3rd party one if none of the above work for you,
and get plugging it in. You'll probably also want to read the [Client-Server API
HOWTO](http://matrix.org/docs/howtos/client-server.html) too.
If you already have communication infrastructure set up (XMPP, custom HTTP, or whatever),
then you'll want to run a bridge to expose it to the wider Matrix ecosystem.
See [matrix-appservice-bridge HOWTO](https://github.com/matrix-org/matrix-appservice-bridge/blob/master/HOWTO.md) for a
guide of how to write bridges using the matrix-appservice-bridge framework, or co-opt one
from the list at https://matrix.org/blog/try-matrix-now.
[Application Service API](/docs/spec/#application-service-api) gives the details of the API
that bridges have to implement.
##### How can I write a client on Matrix? ##### How can I write a client on Matrix?
@ -308,16 +397,20 @@ HOWTO](http://matrix.org/docs/howtos/client-server.html) and the [API
docs](/docs/api) and [the Spec](/docs/spec) for all the details you need docs](/docs/api) and [the Spec](/docs/spec) for all the details you need
to write a client. to write a client.
##### *How can I help out with this?* ##### How can I help out with this?
Install synapse and tell us how you get on. Critique the spec.  Write Come say hi on #matrix:matrix.org! Install synapse and tell us how you get on. Critique the spec.  Write
clients.  Just come say hi on [\#matrix:matrix.org](/alpha) or the clients. Write bridges! Run bridges! Nose around in [Jira](https://matrix.org/jira) and
[mailing lists](/mailman/listinfo/matrix-users)! send us some pull requests on github to fix some bugs or add some features! You could even
try to write a homeserver (but be warned, Matrix's architecture makes homeservers orders of
magnitude harder than clients or bridges.)
See [CONTRIBUTING.rst](http://github.com/matrix-org/synapse/tree/master/CONTRIBUTING.rst) for
full details on how to contribute to the project. All are welcome!
##### Where can I get support? ##### Where can I get support?
[\#matrix:matrix.org](/alpha), \#matrix on irc.freenode.net or \#matrix:matrix.org aka \#matrix on irc.freenode.is your best bet.
the [mailing lists](/mailman/listinfo/matrix-users) are your best bets.
##### How do I register custom matrix event types? ##### How do I register custom matrix event types?
@ -327,66 +420,108 @@ use the [mailing list](/mailman/listinfo/matrix-users) for now.
##### How mature is this? ##### How mature is this?
We started working on Matrix in July 2014, and have opened it to the We started working on Matrix in July 2014, and opened it to the
public in September 2014.  It's early days, and under no circumstances public in September 2014. We got all the core features in place in December 2014
should you use Matrix or Synapse for anything other than experimentation and entered beta, and since then have been iterating away on the beta refining the
and learning at this point.  Obviously the spec and apps are maturing architecture and APIs, fixing bugs and scalability, and adding new features, clients,
rapidly, but as of the time of writing APIs are not frozen and the apps bridges etc.
are very much a work in progress.
As of October 2015 (synapse 0.10) it's good for serious experimentation and
non-production services and can absolutely be used in the real world. However, we're
still in beta and we'll want to freeze the spec and implement clustering and other
nice features before we really declare it ready for production.
### Standard
##### What is a client?
Users in Matrix use one or more clients to communicate. This could be any combination of a web client, a command line client, a mobile client - or embedded clients built into existing apps. It could even be a piece of hardware (e.g. a drone) that is Matrix enabled.
##### Can I use Matrix without installing a Matrix client?
Sure. An ever increasing number of protocols are being bridged into Matrix, so if you use something like IRC on Freenode you may well be indirectly benefiting from Matrix, as others may be connected into the IRC channel via Matrix.
##### What is a home server?
A user's clients connect to a single homeserver, which stores the communication history and account information for that user, and shares data with the wider Matrix ecosystem by synchronising communication history with other homeservers.
##### What is an identity server?
Users in Matrix are identified internally via their matrix user ID (MXID). However, existing 3rd party ID (3PID) namespaces such as email addresses or phone numbers should be used publically to identify Matrix users, at least for invitation purposes. A Matrix "Identity" describes both the user ID and any other existing IDs from third party namespaces linked to their account.
| |
*Sorry, the FAQ is still work in progress, the rest of it will up Matrix users can link third-party IDs (3PIDs) to their user ID. Linking 3PIDs creates a mapping from a 3PID to a user ID. This mapping can then be used by Matrix users in order to discover the MXIDs of their contacts.
soon!* *In the mean time, don't hesitate to get in touch on
[\#matrix:matrix.org](/alpha) or the [mailing
lists](/mailman/listinfo/matrix-users)!*
| |
### Standard In order to ensure that the mapping from 3PID to user ID is genuine, a globally federated cluster of trusted "Identity Servers" (IS) are used to verify the 3PID and persist and replicate the mappings.
Usage of an IS is not required in order for a client application to be part of the Matrix ecosystem. However, without one clients will not be able to look up user IDs using 3PIDs.
##### What is a home server? |
##### What is an identity sever? The precise architecture of identity servers is currently in flux and subject to change as we work to fully decentralise them.
##### Where do my conversations get stored? ##### Where do my conversations get stored?
Each homeserver stores the communication history and account information for all of its clients, and shares data with the wider Matrix ecosystem by synchronising communication history with other homeservers and their clients. Clients typically communicate with each other by emitting events in the context of a virtual room. Room data is replicated across all of the homeservers *whose users are participating in a given room*.
##### What is a 3PID? ##### What is a 3PID?
Third-party IDs (3PIDs) are IDs from other systems or contexts, such as email addresses, social network accounts and phone numbers.
##### How do you do VoIP calls on Matrix? ##### How do you do VoIP calls on Matrix?
Voice (and video) over Matrix uses the WebRTC 1.0 standard to transfer call media (i.e. the actual voice and video traffic). Matrix is used to signal the establishment and termination of the call by sending call events, like any other event. Currently calls are only supported in rooms with exactly two participants - however, one of those participants may be a conferencing bridge. We're looking at better ways to do group calling.
##### Can I log into other homeservers with my username and password? ##### Can I log into other homeservers with my username and password?
Currently, no. We are looking at options for decentralising or migrating user accounts between multiple servers, and might add this feature at a later stage.
##### Why Apache Licence? ##### Why Apache Licence?
The Apache Licence is a permissive licence. We want the Matrix protocol itself to be free and open, but people are free to create both free and commercial apps and services that uses the protocol. In our opinion, any Matrix-service only enhances the Matrix ecosystem.
##### Can I write a Matrix homeserver? ##### Can I write a Matrix homeserver?
Yes. Matrix is just a spec, so implementations of the spec are very welcome! It should be noted that as of October 2015, changes are still being made to the spec, so if you want to write a Matrix homeserver, it is strongly recommended that you chat to the Matrix.org devs in #matrix:matrix.org first! You can also read about the [Federation API here]( https://github.com/matrix-org/matrix-doc/blob/master/specification/30_server_server_api.rst).
##### How secure is this? ##### How secure is this?
##### Why aren't you using an ORM layer like SqlAlchemy?   Server-server traffic is mandatorily TLS from the outset. Server-client traffic mandates transport layer encryption other than for tinkering. Servers maintain a public/private key pair, and sign the integrity of all messages in the context of the historical conversation, preventing tampering. Server keys are distributed using a PERSPECTIVES-style system.
| End-to-end encryption is coming shortly to clients for both 1:1 and group chats to protect user data stored on servers, using the [Olm](https://matrix.org/git/olm) cryptographic ratchet implementation. As of October 2015 this is blocked on implementing the necessary key distribution and fingerprint management.
Privacy of metadata is not currently protected from server administrators - a malicious homeserver administrator can see who is talking to who and when, but not what is being said (once E2E encryption is enabled). See [this presentation from Jardin Entropique](http://matrix.org/~matthew/2015-06-26%20Matrix%20Jardin%20Entropique.pdf) for a more comprehensive discussion of privacy in Matrix.
### Implementations
### APIs ##### What is Synapse?
Synapse is a reference "homeserver" implementation of Matrix from the core development team at matrix.org, written in Python 2/Twisted. It is intended to showcase the concept of Matrix and let folks see the spec in the context of a codebase and let you run your own homeserver and generally help bootstrap the ecosystem.
##### How do I join the global Matrix federation? ##### How do I join the global Matrix federation?
You can download and run one of the available Matrix servers - please see [this guide](http://matrix.org/docs/guides/getting_involved.html#run) for details!
##### What ports do I have to open up to join the global Matrix federation? ##### What ports do I have to open up to join the global Matrix federation?
| We recommend servers use port 8448 for server\<-\>server HTTPS traffic. Look at ["Setting up Federation"](https://github.com/matrix-org/synapse#setting-up-federation) in the Synapse readme file for details.
### Reference Implementations Client\<-\>Server traffic can talk directly to Synapse via port 8448, but as by default Synapse creates a self-signed TLS certificate this can cause problems for clients which can't easily trust self-signed certificates (e.g. most web browsers). Instead, you can proxy access to Synapse's HTTP listener on port 8008 via an existing HTTPS proxy with a valid certificate (e.g. an nginx listening on port 443), or you can point Synapse at a valid X.509 signed TLS certificate. In future, Synapse will probably use letsencrypt to autogenerate valid certificates rather than self-signed ones during installation, simplifying this process enormously.
##### What is Matrix built on - and why? You can also put Synapse entirely behind an existing TLS load balancer and not expose port 8448 at all. In this situation, Synapse will need to be configured to share the same *public* TLS certificate as the load balancer (as Synapse uses the public certificate for identity in other areas too, and it has to match the certificate that other servers see when they connect).
##### How do I run my own home server? ##### How do I run my own homeserver?
Follow the instructions for the homeserver you want to run. If you want to run Synapse, the reference homeserver from Matrix.org, follow [these instructions](https://github.com/matrix-org/synapse#synapse-installation).
##### Can I run my own identity server? ##### Can I run my own identity server?
Yes - the reference implementation is Yes - the reference implementation is
[sydent](https://github.com/matrix-org/sydent) and you can run your own [sydent](https://github.com/matrix-org/sydent) and you can run your own
ID server cluster that tracks 3rd party to Matrix ID mappings. If you ID server cluster that tracks 3rd party to Matrix ID mappings. This won't be very useful right now, though, and we don't recommend it.
want your server to participate in the global replicated Matrix ID If you want your server to participate in the global replicated Matrix ID
service then please get in touch with us. Meanwhile, we are looking at service then please get in touch with us. Meanwhile, we are looking at
ways of decentralising the 'official' Matrix identity service so that ways of decentralising the 'official' Matrix identity service so that
identity servers are 100% decentralised and can openly federate with identity servers are 100% decentralised and can openly federate with
@ -394,20 +529,65 @@ each other. **N.B. that you can use Matrix without ever using the
identity service - it exists only to map 3rd party IDs (e.g. email identity service - it exists only to map 3rd party IDs (e.g. email
addresses) to matrix IDs to aid user discovery**. addresses) to matrix IDs to aid user discovery**.
##### What is Synapse? ##### What are Synapse's platform requirements?
Synapse will use as much RAM as you give it in order to cache conversations in RAM to avoid hitting the database. For small deployments (<50 active users) around 512MB of RAM is probably okay. You can configure the amount of RAM used by synapse with the event_cache_size config parameter - the more events in the cache, the more RAM required. Synapse itself requires relatively little diskspace other than for logging (which as of October 2015 is quite verbose for debugging purposes), but as it caches the content of all the file attachments (images, videos etc) viewed by its users, you may need to size storage appropriately. Synapse is currently effectively single threaded, and will never use more than 1 core.
|
For better performance, one should back Synapse with a Postgres database rather than the default SQLite - see https://github.com/matrix-org/synapse/tree/master/README.rst#using-postgresql for details.
##### Why is Synapse in Python/Twisted? ##### Why is Synapse in Python/Twisted?
##### What are Synapse's platform requirements? This is because both provide a mature and well known event-driven async IO framework for writing serverside code. Whilst this has been okay for our initial experimentation and proof of concept, it's likely that future homeserver work will be written in a more strongly typed language (e.g. Go).
##### Why aren't you using an ORM layer like SqlAlchemy in Synapse?
##### What are the Synapse webclient's requirements? Synapse is *very* database dependent (as of Oct 2015; this is improving in the near future however), and we like having the flexibility to sculpt our own queries.
##### Where is the mobile app? ##### Where can I find a mobile app?
The "Matrix Console" reference apps (ugly, geeky and powerful - intended for early adopter powerusers) can be downloaded from the [Google Play store](https://play.google.com/store/apps/details?id=org.matrix.androidsdk.alpha)
and [Apple store](https://itunes.apple.com/gb/app/matrix-console/id970074271).
|
For the Android app, you can also install the latest development version
built by [Jenkins](http://www.matrix.org/jenkins/job/AndroidConsoleDevelop/lastBuild/artifact/console/build/outputs/apk/console-alpha-debug.apk).
##### Where can I find a web app?
As of Oct 2015, the best web app options are to use [Vector.im](https://vector.im) - a glossy web client written on top of [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk), or the original [AngularJS based client](https://matrix.org/beta), which has serious performance problems and is not currently being maintained. In future a "Matrix Console" reference web app built on matrix-react-sdk will be released by matrix.org to complement the mobile apps above.
|
##### What decides the room member order on the webclient? ### QUESTIONS TO BE ANSWERED!
This FAQ is a constant work in progress - patches and pull requests are *very* welcome to help us improve it. Some of the frequent questions where we need to write an answer include:
* How do I rename servers?
* How do I change the TLS key of my server?
* How do I maintain my synapse's DB (e.g. prune old conversations)?
* How do I maintain my synapse's content repository (e.g. prune old content)?
* What are redactions?
* Why is the spec so big, especially relative to the XMPP baseline spec?
* How do I contribute to the spec?
* What is the privacy policy on Matrix.org?
* How precisely does E2E work?
* How does Matrix actually work architecturally?
* What IOT use cases are there for Matrix?
* Why is are the Matrix reference implementations written in so many different languages?
* How does push work?
* What's on the roadmap?
* How can I use Matrix to talk on Freenode or other IRC networks?
* Where can I learn more about Matrix? (link to PDFs of other presentations etc)
* Why HTTP? Doesn't HTTP suck?
* Why don't you use websockets?
* Why is synapse so resource intensive immediately after federating for the first time?
* \[your question goes here...\]
| |
Any other question? Please contact us on Any other questions? Please contact us in
[\#matrix:matrix.org](/alpha) or the [mailing [\#matrix:matrix.org](https://matrix.org/beta/#/room/%23matrix:matrix.org) or the [mailing
lists](/mailman/listinfo/matrix-users)! lists](/mailman/listinfo/matrix-users)!

@ -53,5 +53,10 @@ h1,h2,h3,h4,h5 {
#document { #document {
margin-top: 10px; /* We want a little whitespace before the page content starts */ margin-top: 10px; /* We want a little whitespace before the page content starts */
width: 1080px;
}
#wrapper {
max-width: 1080px;
} }

@ -31,18 +31,18 @@ Response format:
{% for table in endpoint.res_tables -%} {% for table in endpoint.res_tables -%}
{{"``"+table.title+"``" if table.title else "" }} {{"``"+table.title+"``" if table.title else "" }}
================== ================= =========================================== =================== ================= ==========================================
Param Type Description Param Type Description
================== ================= =========================================== =================== ================= ==========================================
{% for row in table.rows -%} {% for row in table.rows -%}
{# -#} {# -#}
{# Row type needs to prepend spaces to line up with the type column (19 ch) -#} {# Row type needs to prepend spaces to line up with the type column (20 ch) -#}
{# Desc needs to prepend the required text (maybe) and prepend spaces too -#} {# Desc needs to prepend the required text (maybe) and prepend spaces too -#}
{# It also needs to then wrap inside the desc col (43 ch width) -#} {# It also needs to then wrap inside the desc col (42 ch width) -#}
{# -#} {# -#}
{{row.key}}{{row.type|indent(19-row.key|length)}}{{row.desc|wrap(43,row.req_str | indent(18 - (row.type|length))) |indent_block(37)}} {{row.key}}{{row.type|indent(20-row.key|length)}}{{row.desc|wrap(42,row.req_str | indent(18 - (row.type|length))) |indent_block(38)}}
{% endfor -%} {% endfor -%}
================== ================= =========================================== =================== ================= ==========================================
{% endfor %} {% endfor %}
{% endif -%} {% endif -%}

@ -168,6 +168,13 @@ class MatrixUnits(Units):
# assign value expected for this param # assign value expected for this param
val_type = param.get("type") # integer/string val_type = param.get("type") # integer/string
if param.get("enum"):
val_type = "enum"
desc += (
" One of: %s" % json.dumps(param.get("enum"))
)
refType = Units.prop(param, "schema/$ref/") # Error,Event refType = Units.prop(param, "schema/$ref/") # Error,Event
schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads
if not val_type and refType: if not val_type and refType:
@ -270,17 +277,27 @@ class MatrixUnits(Units):
if good_response: if good_response:
self.log("Found a 200 response for this API") self.log("Found a 200 response for this API")
res_type = Units.prop(good_response, "schema/type") res_type = Units.prop(good_response, "schema/type")
res_name = Units.prop(good_response, "schema/name")
if res_type and res_type not in ["object", "array"]: if res_type and res_type not in ["object", "array"]:
# response is a raw string or something like that # response is a raw string or something like that
endpoint["res_tables"].append({ good_table = {
"title": None, "title": None,
"rows": [{ "rows": [{
"key": good_response["schema"].get("name", ""), "key": "<" + res_type + ">" if not res_name else res_name,
"type": res_type, "type": res_type,
"desc": res.get("description", ""), "desc": res.get("description", ""),
"req_str": "" "req_str": ""
}] }]
}) }
if good_response.get("headers"):
for (header_name, header) in good_response.get("headers").iteritems():
good_table["rows"].append({
"key": header_name,
"type": "Header<" + header["type"] + ">",
"desc": header["description"],
"req_str": ""
})
endpoint["res_tables"].append(good_table)
elif res_type and Units.prop(good_response, "schema/properties"): elif res_type and Units.prop(good_response, "schema/properties"):
# response is an object: # response is an object:
schema = good_response["schema"] schema = good_response["schema"]
@ -352,7 +369,7 @@ class MatrixUnits(Units):
self.log("Reading swagger API: %s" % filename) self.log("Reading swagger API: %s" % filename)
with open(os.path.join(path, filename), "r") as f: with open(os.path.join(path, filename), "r") as f:
# strip .yaml # strip .yaml
group_name = filename[:-5] group_name = filename[:-5].replace("-", "_")
if is_v2: if is_v2:
group_name = "v2_" + group_name group_name = "v2_" + group_name
api = yaml.load(f.read()) api = yaml.load(f.read())

Loading…
Cancel
Save