Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Implement Read Marker API #2120

Merged
merged 15 commits into from Apr 13, 2017

Conversation

Projects
None yet
2 participants
Contributor

lukebarnard1 commented Apr 11, 2017 edited

This implements the design at https://docs.google.com/document/d/1UWqdS-e1sdwkLDUY0wA4gZyIkRp-ekjsLZ8k6g_Zvso/edit#heading=h.8jqdhkapw60, summarised below.

Update: see #2128 for further alterations. The summary below has been updated.

m.read_marker event

{
    "content": {
        "event_id”: “$123456789098765hhjGslf:matrix.org"
    },
    "room_id": "!someroomid:matrix.org",
    "type": "m.read_marker"
}

To update it, the client sends a PUT.

RESTful HTTP endpoint

PUT /_matrix/client/r0/rooms/%21someroomid%3Amatrix.org/read_markers HTTP/1.1
Content-Type: application/json

{
	"m.read": "$347926718ewsc:example.com",
	"m.read_marker": "$4536432343kljf:example.com"
}

The REST API hits:

  • the RR handler if “m.read” has been set. This is optional and means that we don’t end up doing one call for RM and one separate call for RR, which is the common case when the user has caught up on their scrollback;
  • the RM handler if “m.read_marker” has been set. This handler asserts that the RM event ID is ahead in the stream in comparison to the current one and then uses the room account data API to store the m.read_marker event.

lukebarnard1 added some commits Apr 11, 2017

Finish implementing RM endpoint
 - This change causes a 405 to be sent if "m.read_marker" is set via /account_data
 - This also fixes-up the RM endpoint so that it actually Works.
synapse/handlers/read_marker.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+# Copyright 2015, 2016 OpenMarket Ltd
@erikjohnston

erikjohnston Apr 11, 2017

Owner

Should be: # Copyright 2017 Vector Creations Ltd

synapse/handlers/read_marker.py
+ """
+
+ # Get ordering for existing read marker
+ with (yield self.read_marker_linearizer.queue(room_id + "_" + user_id)):
@erikjohnston

erikjohnston Apr 11, 2017

Owner

Just use a tuple: (room_id, user_id)

synapse/handlers/read_marker.py
+ retcols=["topological_ordering", "stream_ordering"],
+ keyvalues={"event_id": event_id},
+ allow_none=True
+ )
@erikjohnston

erikjohnston Apr 11, 2017

Owner

This should be a function inside the storage function. Conventionally functions that start with _ are private.

This also should have a desc="..." field so that that metrics work correctly. Usually its just the name of the calling function

synapse/handlers/read_marker.py
+ if existing_to > new_to:
+ should_update = False
+ elif existing_to == new_to and existing_so >= new_so:
+ should_update = False
@erikjohnston

erikjohnston Apr 11, 2017

Owner

I'd move this entire block of code into the storage function and have a dedicated is_event_after function or some such

@erikjohnston erikjohnston changed the title from Luke/read markers to Implement Read Marker API Apr 11, 2017

Owner

erikjohnston commented Apr 11, 2017

Also, you upset pep8:

$ flake8 synapse tests 
synapse/handlers/read_marker.py:20:1: F401 'synapse.util.logcontext.PreserveLoggingContext' imported but unused
synapse/handlers/read_marker.py:22:1: F401 'synapse.types.get_domain_from_id' imported but unused
synapse/handlers/read_marker.py:28:1: E302 expected 2 blank lines, found 1
synapse/rest/client/v2_alpha/account_data.py:87:17: E128 continuation line under-indented for visual indent
synapse/rest/client/v2_alpha/account_data.py:88:17: E128 continuation line under-indented for visual indent
synapse/rest/client/v2_alpha/account_data.py:89:13: E124 closing bracket does not match visual indentation
synapse/rest/client/v2_alpha/read_marker.py:18:1: F401 'synapse.api.errors.SynapseError' imported but unused
synapse/rest/client/v2_alpha/read_marker.py:48:43: E703 statement ends with a semicolon

lukebarnard1 added some commits Apr 11, 2017

Contributor

lukebarnard1 commented Apr 12, 2017

Actually, it turns out that there's a bug if you haven't set a RM for a room previously. In the handler on line 46 it assumes that there is a m.read_marker key.

Contributor

lukebarnard1 commented Apr 12, 2017

Fixed!

synapse/handlers/read_marker.py
+ the read marker has changed.
+ """
+
+ # Get ordering for existing read marker
@erikjohnston

erikjohnston Apr 12, 2017

Owner

Outdated comment?

synapse/handlers/read_marker.py
+
+ # Get ordering for existing read marker
+ with (yield self.read_marker_linearizer.queue((room_id, user_id))):
+ account_data = yield self.store.get_account_data_for_room(user_id, room_id)
@erikjohnston

erikjohnston Apr 12, 2017

Owner

We probably should be using a storage function that pulls out based on type too. I think there already is one?

@lukebarnard1

lukebarnard1 Apr 12, 2017

Contributor

There's one for global_account_data but not for_room

synapse/handlers/read_marker.py
+
+ existing_read_marker = None
+ if "m.read_marker" in account_data:
+ existing_read_marker = account_data["m.read_marker"]
@erikjohnston

erikjohnston Apr 12, 2017

Owner

This could also be written as:

existing_read_marker = account_data.get("m.read_marker", None)
synapse/handlers/read_marker.py
+ user_id, room_id, "m.read_marker", content
+ )
+ self.notifier.on_new_event(
+ "account_data_key", max_id, users=[user_id], rooms=[room_id]
@erikjohnston

erikjohnston Apr 12, 2017

Owner

We don't need to notify the entire room about this change, just the user.

+ raise SynapseError(
+ 405,
+ "Cannot set m.read_marker through this API. "
+ "Use /rooms/!roomId:server.name/read_marker"
@erikjohnston

erikjohnston Apr 12, 2017

Owner

For future reference we tend to put spaces at the start:

"Cannot set m.read_marker through this API."
" Use /rooms/!roomId:server.name/read_marker"

This makes it more obvious that there is at least one space, which is quite important for e.g. SQL

+
+ def __init__(self, hs):
+ super(ReadMarkerRestServlet, self).__init__()
+ self.hs = hs
@erikjohnston

erikjohnston Apr 12, 2017

Owner

Try to avoid taking a reference to hs if possible, and instead just pull out everything you need. This is for cleanliness and makes it clearer what the dependencies of this class is.

+ body = parse_json_object_from_request(request)
+
+ if "m.read" in body:
+ read_event_id = body["m.read"]
@erikjohnston

erikjohnston Apr 12, 2017

Owner

I usually do:

read_event_id = body.get("m.read", None)
if read_event_id:
    ...

but its a matter of taste

synapse/storage/events.py
+ if to_1 > to_2:
+ is_after = False
+ elif to_1 == to_2 and so_1 >= so_2:
+ is_after = False
@erikjohnston

erikjohnston Apr 12, 2017

Owner

I think you can actually write this as:

is_after = (to_1, so_1) > (to_2, so_2)
@lukebarnard1

lukebarnard1 Apr 12, 2017

Contributor

Sadly,

>>> ( 1, 2 ) < ( 1, 2 )
False
>>> ( 1, 2 ) < ( 1, 3 )
True

So we'll have to go for the form with two comparisons. is_event_after is now also an accurate name with this change...

@erikjohnston

erikjohnston Apr 13, 2017

Owner

That's exactly what you want though, isn't it?

Owner

erikjohnston commented Apr 12, 2017

Just a few nits, nothing particularly important. Feel free to ignore the various style comments depending on your taste

lukebarnard1 added some commits Apr 12, 2017

lukebarnard1 added a commit to matrix-org/matrix-js-sdk that referenced this pull request Apr 12, 2017

Implement API for setting RM
This is now stored on the server with similar treatment to RRs. The server will only store the specified eventId as the current read marker for a room if the event is ahead in the stream when compared to the existing RM. The exception is when the RM has never been set for this room for this user, in which case the event ID will be stored as the RM without any comparison.

This API also allows for an optional RR event ID to be sent in the same request. This is because it might be the common case for some clients to update the RM at the same time as updating the RR.

See design: https://docs.google.com/document/d/1UWqdS-e1sdwkLDUY0wA4gZyIkRp-ekjsLZ8k6g_Zvso/edit

See server-side PR: matrix-org/synapse#2120

@lukebarnard1 lukebarnard1 referenced this pull request in matrix-org/matrix-js-sdk Apr 12, 2017

Merged

Implement API for setting RM #419

synapse/storage/events.py
+ """
+ to_1, so_1 = yield self._get_event_ordering(event_id1)
+ to_2, so_2 = yield self._get_event_ordering(event_id2)
+ defer.returnValue(to_1 > to_2 and so_1 > so_2)
@erikjohnston

erikjohnston Apr 13, 2017

Owner

This is not equivalent to (to_1, so_1) > (to_2, so_2)?

@lukebarnard1

lukebarnard1 Apr 13, 2017

Contributor

in IRL we disproved my lovely boolean algebra; it had an error in it. sads.

Owner

erikjohnston commented Apr 13, 2017

lgtm

@lukebarnard1 lukebarnard1 merged commit 78f0ddb into develop Apr 13, 2017

8 checks passed

Sytest Dendron (Commit) Build #1970 origin/luke/read-markers succeeded in 9 min 18 sec
Details
Sytest Dendron (Merged PR) Build finished.
Details
Sytest Postgres (Commit) Build #2800 origin/luke/read-markers succeeded in 7 min 53 sec
Details
Sytest Postgres (Merged PR) Build finished.
Details
Sytest SQLite (Commit) Build #2869 origin/luke/read-markers succeeded in 5 min 54 sec
Details
Sytest SQLite (Merged PR) Build finished.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details

lukebarnard1 added a commit to matrix-org/matrix-js-sdk that referenced this pull request Apr 20, 2017

Implement API for setting RM (#419)
* Implement API for setting RM

This is now stored on the server with similar treatment to RRs. The server will only store the specified eventId as the current read marker for a room if the event is ahead in the stream when compared to the existing RM. The exception is when the RM has never been set for this room for this user, in which case the event ID will be stored as the RM without any comparison.

This API also allows for an optional RR event ID to be sent in the same request. This is because it might be the common case for some clients to update the RM at the same time as updating the RR.

See design: https://docs.google.com/document/d/1UWqdS-e1sdwkLDUY0wA4gZyIkRp-ekjsLZ8k6g_Zvso/edit

See server-side PRs: matrix-org/synapse#2120, matrix-org/synapse#2128

@lukebarnard1 lukebarnard1 referenced this pull request in matrix-org/matrix-doc May 8, 2017

Open

Add new Read Marker API to docs #910

psaavedra added a commit to psaavedra/synapse that referenced this pull request May 19, 2017

Merge tag 'v0.21.0' into v0.21.0_no_federate_by_default
Changes in synapse v0.21.0 (2017-05-18)
=======================================

No changes since v0.21.0-rc3

Changes in synapse v0.21.0-rc3 (2017-05-17)
===========================================

Features:

* Add per user rate-limiting overrides (PR #2208)
* Add config option to limit maximum number of events requested by ``/sync``
  and ``/messages`` (PR #2221) Thanks to @psaavedra!

Changes:

* Various small performance fixes (PR #2201, #2202, #2224, #2226, #2227, #2228,
  #2229)
* Update username availability checker API (PR #2209, #2213)
* When purging, don't de-delta state groups we're about to delete (PR #2214)
* Documentation to check synapse version (PR #2215) Thanks to @hamber-dick!
* Add an index to event_search to speed up purge history API (PR #2218)

Bug fixes:

* Fix API to allow clients to upload one-time-keys with new sigs (PR #2206)

Changes in synapse v0.21.0-rc2 (2017-05-08)
===========================================

Changes:

* Always mark remotes as up if we receive a signed request from them (PR #2190)

Bug fixes:

* Fix bug where users got pushed for rooms they had muted (PR #2200)

Changes in synapse v0.21.0-rc1 (2017-05-08)
===========================================

Features:

* Add username availability checker API (PR #2183)
* Add read marker API (PR #2120)

Changes:

* Enable guest access for the 3pl/3pid APIs (PR #1986)
* Add setting to support TURN for guests (PR #2011)
* Various performance improvements (PR #2075, #2076, #2080, #2083, #2108,
  #2158, #2176, #2185)
* Make synctl a bit more user friendly (PR #2078, #2127) Thanks @APwhitehat!
* Replace HTTP replication with TCP replication (PR #2082, #2097, #2098,
  #2099, #2103, #2014, #2016, #2115, #2116, #2117)
* Support authenticated SMTP (PR #2102) Thanks @DanielDent!
* Add a counter metric for successfully-sent transactions (PR #2121)
* Propagate errors sensibly from proxied IS requests (PR #2147)
* Add more granular event send metrics (PR #2178)

Bug fixes:

* Fix nuke-room script to work with current schema (PR #1927) Thanks
  @zuckschwerdt!
* Fix db port script to not assume postgres tables are in the public schema
  (PR #2024) Thanks @jerrykan!
* Fix getting latest device IP for user with no devices (PR #2118)
* Fix rejection of invites to unreachable servers (PR #2145)
* Fix code for reporting old verify keys in synapse (PR #2156)
* Fix invite state to always include all events (PR #2163)
* Fix bug where synapse would always fetch state for any missing event (PR #2170)
* Fix a leak with timed out HTTP connections (PR #2180)
* Fix bug where we didn't time out HTTP requests to ASes  (PR #2192)

Docs:

* Clarify doc for SQLite to PostgreSQL port (PR #1961) Thanks @benhylau!
* Fix typo in synctl help (PR #2107) Thanks @HarHarLinks!
* ``web_client_location`` documentation fix (PR #2131) Thanks @matthewjwolff!
* Update README.rst with FreeBSD changes (PR #2132) Thanks @feld!
* Clarify setting up metrics (PR #2149) Thanks @encks!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment