Add Timeline documentation
parent
016290d9e1
commit
6134702d25
|
@ -0,0 +1,108 @@
|
||||||
|
# Timeline
|
||||||
|
|
||||||
|
Given the complex nature of the Timeline design, it deserves some explanation of
|
||||||
|
the design. This document aims to describe how the Elm SDK designs the Timeline,
|
||||||
|
so that other projects may learn from it.
|
||||||
|
|
||||||
|
## API endpoint disambiguations
|
||||||
|
|
||||||
|
Generally speaking, there are a few API endpoints with similar design:
|
||||||
|
|
||||||
|
- The [`/sync` endpoint](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3sync),
|
||||||
|
which gets the events that the homeserver received most recently.
|
||||||
|
- The [`/messages` endpoint](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3roomsroomidmembers),
|
||||||
|
which gets any events in the topological order.
|
||||||
|
|
||||||
|
As noted in the Matrix spec:
|
||||||
|
|
||||||
|
> Events are ordered in this API according to the arrival time of the event on
|
||||||
|
> the homeserver. This can conflict with other APIs which order events based on
|
||||||
|
> their partial ordering in the event graph. This can result in duplicate events
|
||||||
|
> being received (once per distinct API called). Clients SHOULD de-duplicate
|
||||||
|
> events based on the event ID when this happens.
|
||||||
|
|
||||||
|
For this reason, the Elm SDK maintains **two independent timelines** that are tied
|
||||||
|
together when necessary to form a coherent timeline.
|
||||||
|
|
||||||
|
## Elm design
|
||||||
|
|
||||||
|
For those unfamiliar, the Elm Architecture breaks into three parts:
|
||||||
|
|
||||||
|
- **Model** - the state of the application
|
||||||
|
- **View** - a way to turn your state into meaningful information
|
||||||
|
- **Update** - a way to update your state based on the Matrix API
|
||||||
|
|
||||||
|
Since these concepts are compartmentalized, it is impossible to make an API call
|
||||||
|
while executing the **view** function; the Elm SDK must at all times find a way
|
||||||
|
to represent its state.
|
||||||
|
|
||||||
|
## Timeline
|
||||||
|
|
||||||
|
Concerning the Matrix timeline, it is meant to create a representation
|
||||||
|
(**Model**) of the timeline, find a way to represent (**View**) it, and find a
|
||||||
|
simple way to adjust it with every incoming Matrix API result. (**Update**)
|
||||||
|
|
||||||
|
First, we define what a timeline batch is.
|
||||||
|
|
||||||
|
### Timeline batch
|
||||||
|
|
||||||
|
A timeline batch is something that most Matrix API endpoints return. It is a
|
||||||
|
little piece of the timeline and contains the following four pieces of
|
||||||
|
information:
|
||||||
|
|
||||||
|
1. A list of events that are part of the timeline.
|
||||||
|
2. A Filter for which all provided events meet the criteria.
|
||||||
|
3. An end batch token that functions as an identifier.
|
||||||
|
4. _(Optional.)_ A start token. If not provided, it indicates the start of the
|
||||||
|
timeline.
|
||||||
|
|
||||||
|
Here's an example of such a timeline batch:
|
||||||
|
|
||||||
|
```
|
||||||
|
|-->[■]->[■]->[●]->[■]->[■]->[●]-->|
|
||||||
|
| |
|
||||||
|
|<--- filter: only ■ and ● --->|
|
||||||
|
| |
|
||||||
|
start: end:
|
||||||
|
<token_1> <token_2>
|
||||||
|
```
|
||||||
|
|
||||||
|
When the Matrix API later returns a batch token that starts with `<token_2>`,
|
||||||
|
we know that we can connect it to the batch above and make a longer list of
|
||||||
|
events!
|
||||||
|
|
||||||
|
At first, this seems quite simple to connect, but there are some difficulties
|
||||||
|
that come up along the way.
|
||||||
|
|
||||||
|
### Challenge 1: different filters, different locations
|
||||||
|
|
||||||
|
When two timeline batches have different filters, we do not know their
|
||||||
|
respective location. For example, the following two timeline batches COULD
|
||||||
|
overlap, but it is also possible they don't:
|
||||||
|
|
||||||
|
```
|
||||||
|
|-->[■]->[■]->[●]->[■]->[■]->[●]-->|
|
||||||
|
| |
|
||||||
|
|<--- filter: only ■ and ● --->|
|
||||||
|
| |
|
||||||
|
start: end:
|
||||||
|
<token_1> <token_2>
|
||||||
|
|
||||||
|
|
||||||
|
|-->[★]->[★]->[★]->[★]-->|
|
||||||
|
| |
|
||||||
|
|<-- filter: only ★ -->|
|
||||||
|
| |
|
||||||
|
start: end:
|
||||||
|
<token_3> <token_4>
|
||||||
|
```
|
||||||
|
|
||||||
|
Realistically, there is currently no way of knowing without making more API
|
||||||
|
calls. However, just making more API calls isn't a solution in Elm because of
|
||||||
|
its architecture.
|
||||||
|
|
||||||
|
> **SOLUTION:** As described in the **View** function, we may assume that
|
||||||
|
overlapping timeline batches have overlapping events. If they overlap yet have
|
||||||
|
no overlapping events, then their filters must be disjoint. If the filters are
|
||||||
|
disjoint, we do not care whether they're overlapping.
|
||||||
|
|
Loading…
Reference in New Issue