Sync RM across instances of Riot#805
Conversation
As detailed here https://docs.google.com/document/d/1UWqdS-e1sdwkLDUY0wA4gZyIkRp-ekjsLZ8k6g_Zvso/edit, the RM state is no longer kept locally, but rather server-side. The client now uses it's locally-calculated RM to update the server and receives server updates via the per-room account data. The sending of the RR has been bundled in to reduce traffic when sending both. In effect, whenever a RR is sent the RM is sent with it but using the new API. This uses a js-sdk change which has set to be finalised and so might change.
Put a XXX to indicate that the ghost tile should be replaced with something mor e stable. As it stands, the ghost will appear, potentially at a different position to the RMs actual position
| isVisibleReadMarker = visible; | ||
| } | ||
|
|
||
| // XXX: there should be no need for a ghost tile - we should just use a |
There was a problem hiding this comment.
you may be right that there is no need for a ghost tile, but I don't think the reason for its presence is to start the RM animation.
There was a problem hiding this comment.
From what I can see, the ghost tile is the one that animates and the ref on the ghost is used to start the animation. This could be so much better. The non-ghost isn't even swapped out (as in there are states where both can be shown), so the client sometimes shows two markers.
There was a problem hiding this comment.
ok, but I don't understand why that means you don't need a ghost. It exists to hold the animation.
There was a problem hiding this comment.
We could reuse the original marker and start the animation by calling Velocity on it before it moves. Instead of using a ref on the ghost, we'd use it on the original.
| } else { | ||
| initialReadMarker = this._getCurrentReadReceipt(); | ||
| } | ||
| console.info('Read marker initially', initialReadMarker); |
There was a problem hiding this comment.
No, not really
| MatrixClientPeg.get().on("Room.redaction", this.onRoomRedaction); | ||
| MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt); | ||
| MatrixClientPeg.get().on("Room.localEchoUpdated", this.onLocalEchoUpdated); | ||
| MatrixClientPeg.get().on("Room.accountData", this.onAccountData); |
| && this.last_rr_sent_event_id != lastReadEvent.getId()) { | ||
| if ((lastReadEventIndex > currentReadUpToEventIndex && | ||
| this.last_rr_sent_event_id != lastReadEvent.getId()) || | ||
| this.last_rm_sent_event_id != this.state.readMarkerEventId) { |
There was a problem hiding this comment.
initialise this in componentWillMount please
| this.last_rr_sent_event_id = undefined; | ||
| this.last_rm_sent_event_id = undefined; | ||
| }); | ||
| console.log('TimelinePanel: Read marker sent to the server ', this.state.readMarkerEventId, ); |
| // the messagePanel doesn't know where the read marker is. | ||
| // if we know the timestamp of the read marker, make a guess based on that. | ||
| var rmTs = TimelinePanel.roomReadMarkerTsMap[this.props.timelineSet.roomId]; | ||
| const rmTs = TimelinePanel.roomReadMarkerTsMap[this.props.timelineSet.room.roomId]; |
There was a problem hiding this comment.
huh. Has this been broken for a while?
There was a problem hiding this comment.
Looks like it! This is reached if MessagePanel has not got the related event paginated in.
It doesn't look like much is done with the result of TimelinePanel.getReadMarkerPosition() other than checking that it's in the view-port when updateReadMarker is called (which might explain why we were seeing it following when scrolling down) and specifying whether it's visible to MessagePanel.
| // we know we're stuckAtBottom, so we can advance the RM | ||
| // immediately, to save a later render cycle | ||
|
|
||
| // This call will setState with readMarkerEventId = lastEv.getId() |
There was a problem hiding this comment.
... except that the true argument is called inhibitSetState - so I don't think it will.
| if (ev.getType() !== "m.fully_read") return; | ||
|
|
||
| const markerEventId = ev.getContent().event_id; | ||
| console.log('TimelinePanel: Read marker received from server', markerEventId); |
| const markerEventId = ev.getContent().event_id; | ||
| console.log('TimelinePanel: Read marker received from server', markerEventId); | ||
|
|
||
| this.setState({ |
There was a problem hiding this comment.
it seems like a problem that we aren't updating roomReadMarkerTsMap here.
I suspect we actually no longer need roomReadMarkerTsMap, but if that's true, let's get rid of it (preferably in a separate PR) rather than leave it in an inconsistent state.
| var roomId = this.props.timelineSet.room.roomId; | ||
|
|
||
| if (TimelinePanel.roomReadMarkerMap[roomId] == eventId) { | ||
| // don't update the state (and cause a re-render) if there is |
There was a problem hiding this comment.
this comment still looks valid?
This will become redundant when there is server support for directionality of the RM
| } | ||
| // it failed, so allow retries next time the user is active | ||
| this.last_rr_sent_event_id = undefined; | ||
| this.last_rm_sent_event_id = undefined; |
There was a problem hiding this comment.
won't this mean we hit the API every time the user moves the mouse? I feel like we should leave this set if sendReadReceipt succeeds.
There was a problem hiding this comment.
If sendReadReceipt is called, it'll return a promise this line is not reached.
| ).catch(() => { | ||
| ).catch((e) => { | ||
| // /read_markers API is not implemented on this HS, fallback to just RR | ||
| if (e.errcode === 'M_UNRECOGNIZED') { |
There was a problem hiding this comment.
what should be the behaviour for other errors? should we not set last_rr_sent_event_id = undefined so that we retry?
There was a problem hiding this comment.
Actually, yes I think that's the Right Way to do it
Indicate that setting the RR was a failure and that hitting the API should be retried (in the case where the errcode !== "M_UNRECOGNISED")
This uses the new RM syncing API: