mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-03-16 08:24:09 +01:00
Merge pull request #52 from matrix-org/spec-file-structure
Spec file structure
This commit is contained in:
commit
a2cfb89086
|
|
@ -4,6 +4,7 @@ from docutils.core import publish_file
|
||||||
import fileinput
|
import fileinput
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -14,11 +15,65 @@ stylesheets = {
|
||||||
"stylesheet_path": ["basic.css", "nature.css"]
|
"stylesheet_path": ["basic.css", "nature.css"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def glob_spec_to(out_file_name):
|
title_style_matchers = {
|
||||||
|
"=": re.compile("^=+$"),
|
||||||
|
"-": re.compile("^-+$")
|
||||||
|
}
|
||||||
|
TOP_LEVEL = "="
|
||||||
|
SECOND_LEVEL = "-"
|
||||||
|
FILE_FORMAT_MATCHER = re.compile("^[0-9]+_[0-9]{2}[a-z]*_.*\.rst$")
|
||||||
|
|
||||||
|
|
||||||
|
def check_valid_section(filename, section):
|
||||||
|
if not re.match(FILE_FORMAT_MATCHER, filename):
|
||||||
|
raise Exception(
|
||||||
|
"The filename of " + filename + " does not match the expected format " +
|
||||||
|
"of '##_##_words-go-here.rst'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# we need TWO new lines else the next file's title gets merged
|
||||||
|
# the last paragraph *WITHOUT RST PRODUCING A WARNING*
|
||||||
|
if not section[-2:] == "\n\n":
|
||||||
|
raise Exception(
|
||||||
|
"The file " + filename + " does not end with 2 new lines."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enforce some rules to reduce the risk of having mismatched title
|
||||||
|
# styles.
|
||||||
|
title_line = section.split("\n")[1]
|
||||||
|
if title_line != (len(title_line) * title_line[0]):
|
||||||
|
raise Exception(
|
||||||
|
"The file " + filename + " doesn't have a title style line on line 2"
|
||||||
|
)
|
||||||
|
|
||||||
|
# anything marked as xx_00_ is the start of a new top-level section
|
||||||
|
if re.match("^[0-9]+_00_", filename):
|
||||||
|
if not title_style_matchers[TOP_LEVEL].match(title_line):
|
||||||
|
raise Exception(
|
||||||
|
"The file " + filename + " is a top-level section because it matches " +
|
||||||
|
"the filename format ##_00_something.rst but has the wrong title " +
|
||||||
|
"style: expected '" + TOP_LEVEL + "' but got '" +
|
||||||
|
title_line[0] + "'"
|
||||||
|
)
|
||||||
|
# anything marked as xx_xx_ is the start of a sub-section
|
||||||
|
elif re.match("^[0-9]+_[0-9]{2}_", filename):
|
||||||
|
if not title_style_matchers[SECOND_LEVEL].match(title_line):
|
||||||
|
raise Exception(
|
||||||
|
"The file " + filename + " is a 2nd-level section because it matches " +
|
||||||
|
"the filename format ##_##_something.rst but has the wrong title " +
|
||||||
|
"style: expected '" + SECOND_LEVEL + "' but got '" +
|
||||||
|
title_line[0] + "' - If this is meant to be a 3rd/4th/5th-level section " +
|
||||||
|
"then use the form '##_##b_something.rst' which will not apply this " +
|
||||||
|
"check."
|
||||||
|
)
|
||||||
|
|
||||||
|
def cat_spec_sections_to(out_file_name):
|
||||||
with open(out_file_name, "wb") as outfile:
|
with open(out_file_name, "wb") as outfile:
|
||||||
for f in sorted(glob.glob("../specification/*.rst")):
|
for f in sorted(glob.glob("../specification/*.rst")):
|
||||||
with open(f, "rb") as infile:
|
with open(f, "rb") as infile:
|
||||||
outfile.write(infile.read())
|
section = infile.read()
|
||||||
|
check_valid_section(os.path.basename(f), section)
|
||||||
|
outfile.write(section)
|
||||||
|
|
||||||
|
|
||||||
def rst2html(i, o):
|
def rst2html(i, o):
|
||||||
|
|
@ -67,7 +122,7 @@ def cleanup_env():
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
prepare_env()
|
prepare_env()
|
||||||
glob_spec_to("tmp/full_spec.rst")
|
cat_spec_sections_to("tmp/full_spec.rst")
|
||||||
run_through_template("tmp/full_spec.rst")
|
run_through_template("tmp/full_spec.rst")
|
||||||
shutil.copy("../supporting-docs/howtos/client-server.rst", "tmp/howto.rst")
|
shutil.copy("../supporting-docs/howtos/client-server.rst", "tmp/howto.rst")
|
||||||
run_through_template("tmp/howto.rst")
|
run_through_template("tmp/howto.rst")
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Typing Notifications
|
Typing Notifications
|
||||||
====================
|
--------------------
|
||||||
|
|
||||||
Client APIs
|
Client APIs
|
||||||
-----------
|
~~~~~~~~~~~
|
||||||
|
|
||||||
To set "I am typing for the next N msec"::
|
To set "I am typing for the next N msec"::
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ To set "I am no longer typing"::
|
||||||
Content: { "typing": false }
|
Content: { "typing": false }
|
||||||
|
|
||||||
Client Events
|
Client Events
|
||||||
-------------
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
All room members will receive an event on the event stream::
|
All room members will receive an event on the event stream::
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ 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.
|
should mark as not typing, any user ID who is not in that list.
|
||||||
|
|
||||||
Server APIs
|
Server APIs
|
||||||
-----------
|
~~~~~~~~~~~
|
||||||
|
|
||||||
Servers will emit EDUs in the following form::
|
Servers will emit EDUs in the following form::
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Receipts
|
Receipts
|
||||||
========
|
--------
|
||||||
|
|
||||||
Receipts are used to publish which events in a room the user or their devices
|
Receipts are used to publish which events in a room the user or their devices
|
||||||
have interacted with. For example, which events the user has read. For
|
have interacted with. For example, which events the user has read. For
|
||||||
|
|
@ -7,7 +7,7 @@ efficiency this is done as "up to" markers, i.e. marking a particular event
|
||||||
as, say, ``read`` indicates the user has read all events *up to* that event.
|
as, say, ``read`` indicates the user has read all events *up to* that event.
|
||||||
|
|
||||||
Client-Server API
|
Client-Server API
|
||||||
-----------------
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Clients will receive receipts in the following format::
|
Clients will receive receipts in the following format::
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ other users. The server will automatically set the ``ts`` field.
|
||||||
|
|
||||||
|
|
||||||
Server-Server API
|
Server-Server API
|
||||||
-----------------
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Receipts are sent across federation as EDUs with type ``m.receipt``. The
|
Receipts are sent across federation as EDUs with type ``m.receipt``. The
|
||||||
format of the EDUs are::
|
format of the EDUs are::
|
||||||
|
|
@ -73,5 +73,5 @@ format of the EDUs are::
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
These are always sent as deltas to previously sent reciepts.
|
These are always sent as deltas to previously sent receipts.
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Room History Visibility
|
Room History Visibility
|
||||||
=======================
|
-----------------------
|
||||||
|
|
||||||
Whether a member of a room can see the events that happened in a room from
|
Whether a member of a room can see the events that happened in a room from
|
||||||
before they joined the room is controlled by the ``history_visibility`` key
|
before they joined the room is controlled by the ``history_visibility`` key
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Signing Events
|
Signing Events
|
||||||
==============
|
--------------
|
||||||
|
|
||||||
Canonical JSON
|
Canonical JSON
|
||||||
--------------
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Matrix events are represented using JSON objects. If we want to sign JSON
|
Matrix events are represented using JSON objects. If we want to sign JSON
|
||||||
events we need to encode the JSON as a binary string. Unfortunately the same
|
events we need to encode the JSON as a binary string. Unfortunately the same
|
||||||
|
|
@ -38,7 +38,7 @@ using this representation.
|
||||||
).encode("UTF-8")
|
).encode("UTF-8")
|
||||||
|
|
||||||
Grammar
|
Grammar
|
||||||
~~~~~~~
|
+++++++
|
||||||
|
|
||||||
Adapted from the grammar in http://tools.ietf.org/html/rfc7159 removing
|
Adapted from the grammar in http://tools.ietf.org/html/rfc7159 removing
|
||||||
insignificant whitespace, fractions, exponents and redundant character escapes
|
insignificant whitespace, fractions, exponents and redundant character escapes
|
||||||
|
|
@ -69,14 +69,14 @@ insignificant whitespace, fractions, exponents and redundant character escapes
|
||||||
/ %x75.30.30.31 (%x30-39 / %x61-66) ; u001X
|
/ %x75.30.30.31 (%x30-39 / %x61-66) ; u001X
|
||||||
|
|
||||||
Signing JSON
|
Signing JSON
|
||||||
------------
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
We can now sign a JSON object by encoding it as a sequence of bytes, computing
|
We can now sign a JSON object by encoding it as a sequence of bytes, computing
|
||||||
the signature for that sequence and then adding the signature to the original
|
the signature for that sequence and then adding the signature to the original
|
||||||
JSON object.
|
JSON object.
|
||||||
|
|
||||||
Signing Details
|
Signing Details
|
||||||
~~~~~~~~~~~~~~~
|
+++++++++++++++
|
||||||
|
|
||||||
JSON is signed by encoding the JSON object without ``signatures`` or keys grouped
|
JSON is signed by encoding the JSON object without ``signatures`` or keys grouped
|
||||||
as ``unsigned``, using the canonical encoding described above. The JSON bytes are then signed using the
|
as ``unsigned``, using the canonical encoding described above. The JSON bytes are then signed using the
|
||||||
|
|
@ -133,7 +133,7 @@ and additional signatures.
|
||||||
return json_object
|
return json_object
|
||||||
|
|
||||||
Checking for a Signature
|
Checking for a Signature
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
++++++++++++++++++++++++
|
||||||
|
|
||||||
To check if an entity has signed a JSON object a server does the following
|
To check if an entity has signed a JSON object a server does the following
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ To check if an entity has signed a JSON object a server does the following
|
||||||
the check fails. Otherwise the check succeeds.
|
the check fails. Otherwise the check succeeds.
|
||||||
|
|
||||||
Signing Events
|
Signing Events
|
||||||
--------------
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Signing events is a more complicated process since servers can choose to redact
|
Signing events is a more complicated process since servers can choose to redact
|
||||||
non-essential parts of an event. Before signing the event it is encoded as
|
non-essential parts of an event. Before signing the event it is encoded as
|
||||||
Loading…
Reference in a new issue