The peek code needs to make sure it sets the pagination token /after/ adding
the events to the timeline, otherwise it will get reset when the events
are added.
When a /sync request fails, we spin up a keep-alive poll to /_matrix/client/r0
which 400s. We treat any HTTP response code as a success for the purposes of
polling the server. When a successful poll is done, we shoot the current /sync
request in the head immediately (via a hacky abort() on the promise) and retry
the /sync.
This provides optional support for fetching old events via the /context API,
and paginating backwards and forwards from them, eventually merging into the
live timeline.
To support it, events are now stored in an EventTimeline, rather than directly
in an array in the Room; the old names are maintained as references for
compatibility.
The feature has to be enabled explicitly, otherwise it would be impossible for
existing clients to back-paginate to the old events after a gappy /sync.
Still TODO here:
* An object which provides a window into the timelines to make them possible to
use. This will be a separate PR.
* Rewrite the 'EventContext' used by the searchRoomEvents API in terms of an
EventTimeline - it is essentially a subset.
After much discussion, the HS will now behave the same for guests/non-guests
wrt joining a room (you get the entire room state on join). This leave "peeking"
which never triggers a join. This can be implemented for guests by doing a
room initial sync followed by a specific /events poll with a specific room_id.
This means there are 2 sync streams: /sync and the peek /events. Architected
so you can only have 1 peek stream in progress at a time (if this were arbitrary
we'd quickly run into concurrent in-flight browser request limits (5).
This fixesvector-web/vector-im#536
The bug here is that we were assuming `setTimeout` would fire after the
requested time. This is not true when the machine is asleep. We now timestamp
before and after `setTimeout` and reset the attempt count if we have waited
more than twice what we originally requested. This allows for some jitter which
is to be expected.
The ability to set a local timeout is applicable to any request, so move it
to http-api.js - We only use this on /sync requests currently. This simplifies
the SyncApi since it doesn't need to worry about it anymore -- the request
promise just gets rejected if the timer expires.
Whilst testing I noticed a weird anomaly which I cannot explain. Playing with
Chrome's network debugger, once you recover from a black hole (0kbps, 90s RTT)
the subsequent requests take 20s to return *even though there is no throttling*.
This was causing issues when using a local timer of timeout= and BUFFER_PERIOD_MS
when timeout=1 due to attempts>1 - they were being knifed before the response
could return. The 20s latency was entirely artifical (checked synapse logs and
they were sub 1s), but I cannot find anywhere in the JS-SDK or browser-requests
where this would be the cause. This persisted even when BUFFER_PERIOD_MS was
changed from 20s to 10s.