Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Sync RM across instances of Riot #805

Merged
merged 19 commits into from
Apr 21, 2017
Merged

Conversation

lukebarnard1
Copy link
Contributor

Luke Barnard added 9 commits April 12, 2017 15:04
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
@@ -388,6 +388,8 @@ module.exports = React.createClass({
isVisibleReadMarker = visible;
}

// XXX: there should be no need for a ghost tile - we should just use a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

@lukebarnard1 lukebarnard1 Apr 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but I don't understand why that means you don't need a ghost. It exists to hold the animation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not really

@@ -180,6 +182,7 @@ var TimelinePanel = React.createClass({
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't forget to remove it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

&& 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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialise this in componentWillMount please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

});
console.log('TimelinePanel: Read marker sent to the server ', this.state.readMarkerEventId, );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? looks spammy

@@ -706,7 +735,7 @@ var TimelinePanel = React.createClass({

// 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];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh. Has this been broken for a while?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@@ -414,9 +417,10 @@ var TimelinePanel = React.createClass({
} else if(lastEv && this.getReadMarkerPosition() === 0) {
// 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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... except that the true argument is called inhibitSetState - so I don't think it will.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah

if (ev.getType() !== "m.fully_read") return;

const markerEventId = ev.getContent().event_id;
console.log('TimelinePanel: Read marker received from server', markerEventId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? looks spammy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true!

const markerEventId = ev.getContent().event_id;
console.log('TimelinePanel: Read marker received from server', markerEventId);

this.setState({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@@ -956,16 +985,10 @@ var TimelinePanel = React.createClass({
_setReadMarker: function(eventId, eventTs, inhibitSetState) {
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment still looks valid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair point!

@lukebarnard1 lukebarnard1 removed their assignment Apr 19, 2017
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@richvdh richvdh assigned lukebarnard1 and unassigned richvdh Apr 19, 2017
// 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If sendReadReceipt is called, it'll return a promise this line is not reached.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, yes.

).catch(() => {
).catch((e) => {
// /read_markers API is not implemented on this HS, fallback to just RR
if (e.errcode === 'M_UNRECOGNIZED') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what should be the behaviour for other errors? should we not set last_rr_sent_event_id = undefined so that we retry?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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")
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants