Transform input into simple batches
This design allows for simple two-way connections and simplifies the input design. It lacks on state resolution for state events. Given that the events are unknown and exclusively event ids are stored, this might not be relevant to implement at this levelrefactor
parent
8e647a870e
commit
327140393f
|
@ -10,43 +10,124 @@ import Internal.Tools.Iddict as Iddict exposing (Iddict)
|
|||
import Internal.Tools.Filters.Main as Filter exposing (Filter)
|
||||
import Internal.Tools.Iddict as Iddict
|
||||
|
||||
{-| A batch is a piece of the timeline that can be used to update the timeline.
|
||||
-}
|
||||
type Batch
|
||||
= BatchToken TokenValue (List TokenValue)
|
||||
| BatchSlice Batch Filter EventId (List EventId) TokenValue (List TokenValue)
|
||||
|
||||
{-| An event id is a raw value provided by the Matrix API. It points to an event
|
||||
that is being stored elsewhere in the Matrix vault.
|
||||
-}
|
||||
type alias EventId = String
|
||||
|
||||
{-| A TokenValue is a raw value provided by the Matrix API. It is an opaque
|
||||
value which indicates a point in the timeline and provides no other information.
|
||||
-}
|
||||
type alias TokenValue = String
|
||||
|
||||
{-| Central data type in the room.
|
||||
-}
|
||||
type alias Timeline =
|
||||
{ mostRecentToken : TokenId
|
||||
, slices : Iddict Slice
|
||||
, tokenToId : Dict String TokenId
|
||||
, tokenToId : Dict TokenValue TokenId
|
||||
, tokens : Iddict Token
|
||||
}
|
||||
|
||||
{-| Pointer to a specific token.
|
||||
-}
|
||||
type TokenId = TokenId Int
|
||||
|
||||
{-| Pointer to a specific slice on the timeline.
|
||||
-}
|
||||
type SliceId = SliceId Int
|
||||
|
||||
{-| Information of a specific slice on the timeline.
|
||||
-}
|
||||
type Slice
|
||||
= Slice
|
||||
{ events : List EventId
|
||||
, filter : Filter
|
||||
{ filter : Filter
|
||||
, head : EventId
|
||||
, next : List TokenId
|
||||
, previous : List TokenId
|
||||
, tail : List EventId
|
||||
}
|
||||
|
||||
{-| Information on a token, which is a point on the timeline. It might have
|
||||
multiple TokenValue types point to it.
|
||||
-}
|
||||
type Token
|
||||
= Token
|
||||
{ next : List SliceId
|
||||
, previous : List SliceId
|
||||
, head : String
|
||||
, tail : List String
|
||||
, head : TokenValue
|
||||
, tail : List TokenValue
|
||||
}
|
||||
|
||||
type alias EventId = String
|
||||
{-| Add a new batch to the timeline. Tokens that already existed, are ignored
|
||||
but connected to the slices.
|
||||
|
||||
The function returns token ids to where the batch starts and ends, as well as
|
||||
the renewed timeline.
|
||||
-}
|
||||
addBatch : Batch -> Timeline -> { start : TokenId, end : TokenId, timeline : Timeline }
|
||||
addBatch batch timeline =
|
||||
case batch of
|
||||
BatchToken head tail ->
|
||||
case addToken (Token { next = [], previous = [], head = head, tail = tail }) timeline of
|
||||
( tokenId, newTimeline ) ->
|
||||
{ start = tokenId, end = tokenId, timeline = newTimeline }
|
||||
|
||||
BatchSlice b filter sHead sTail tHead tTail ->
|
||||
case addBatch b timeline of
|
||||
newBatch ->
|
||||
let
|
||||
slice : Slice
|
||||
slice =
|
||||
Slice
|
||||
{ filter = filter
|
||||
, head = sHead
|
||||
, next = []
|
||||
, previous = []
|
||||
, tail = sTail
|
||||
}
|
||||
|
||||
token : Token
|
||||
token =
|
||||
Token
|
||||
{ next = []
|
||||
, previous = []
|
||||
, head = tHead
|
||||
, tail = tTail
|
||||
}
|
||||
in
|
||||
case newBatch.timeline |> insertSlice slice |> Tuple.mapSecond (addToken token) of
|
||||
( sliceId, ( tokenId, newTimeline ) ) ->
|
||||
{ start = newBatch.start
|
||||
, end = tokenId
|
||||
, timeline =
|
||||
newTimeline
|
||||
|> connectToSlice newBatch.end sliceId
|
||||
|> connectToToken sliceId tokenId
|
||||
}
|
||||
|
||||
{-| Add a new token to the timeline. If it already exists, this function does
|
||||
nothing and instead returns the existing token id.
|
||||
-}
|
||||
addToken : Token -> Timeline -> ( TokenId, Timeline )
|
||||
addToken ((Token { head }) as token) timeline =
|
||||
case Dict.get head timeline.tokenToId of
|
||||
addToken ((Token { head, tail }) as token) timeline =
|
||||
case getTokenIdFromToken token timeline of
|
||||
Just tokenId ->
|
||||
( tokenId, timeline )
|
||||
( tokenId
|
||||
, mapToken tokenId
|
||||
(\(Token tk) ->
|
||||
case mergeUnique ( head, tail ) ( tk.head, tk.tail ) of
|
||||
( h, t ) ->
|
||||
Token { tk | head = h, tail = t }
|
||||
)
|
||||
timeline
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
insertToken token timeline
|
||||
|
@ -71,6 +152,58 @@ addTokenAlias old new timeline =
|
|||
Nothing ->
|
||||
timeline
|
||||
|
||||
{-| Connect a slice to a token to its right. The connection is established in
|
||||
two directions.
|
||||
-}
|
||||
connectToToken : SliceId -> TokenId -> Timeline -> Timeline
|
||||
connectToToken ((SliceId sliceId) as s) ((TokenId tokenId) as t) timeline =
|
||||
{ timeline
|
||||
| slices =
|
||||
Iddict.map sliceId
|
||||
(\(Slice slice) ->
|
||||
if isConnectedToToken t slice.next then
|
||||
Slice slice
|
||||
else
|
||||
Slice { slice | next = t :: slice.next }
|
||||
)
|
||||
timeline.slices
|
||||
, tokens =
|
||||
Iddict.map tokenId
|
||||
(\(Token token) ->
|
||||
if isConnectedToSlice s token.previous then
|
||||
Token token
|
||||
else
|
||||
Token { token | previous = s :: token.previous }
|
||||
)
|
||||
timeline.tokens
|
||||
}
|
||||
|
||||
{-| Connect a token to a slice to its right. The connection is established in
|
||||
two directions.
|
||||
-}
|
||||
connectToSlice : TokenId -> SliceId -> Timeline -> Timeline
|
||||
connectToSlice ((TokenId tokenId) as t) ((SliceId sliceId) as s) timeline =
|
||||
{ timeline
|
||||
| slices =
|
||||
Iddict.map sliceId
|
||||
(\(Slice slice) ->
|
||||
if isConnectedToToken t slice.previous then
|
||||
Slice slice
|
||||
else
|
||||
Slice { slice | previous = t :: slice.previous }
|
||||
)
|
||||
timeline.slices
|
||||
, tokens =
|
||||
Iddict.map tokenId
|
||||
(\(Token token) ->
|
||||
if isConnectedToSlice s token.next then
|
||||
Token token
|
||||
else
|
||||
Token { token | next = s :: token.next }
|
||||
)
|
||||
timeline.tokens
|
||||
}
|
||||
|
||||
{-| Get an empty timeline.
|
||||
-}
|
||||
empty : Timeline
|
||||
|
@ -87,19 +220,45 @@ getSlice : SliceId -> Timeline -> Maybe Slice
|
|||
getSlice (SliceId key) { slices } =
|
||||
Iddict.get key slices
|
||||
|
||||
{-| Get a token value from the timeline.
|
||||
{-| Get a token based on its id.
|
||||
-}
|
||||
getToken : TokenId -> Timeline -> Maybe Token
|
||||
getToken (TokenId key) { tokens } =
|
||||
Iddict.get key tokens
|
||||
getTokenFromTokenId : TokenId -> Timeline -> Maybe Token
|
||||
getTokenFromTokenId (TokenId tokenId) timeline =
|
||||
Iddict.get tokenId timeline.tokens
|
||||
|
||||
{-| Get the token id of an existing token value.
|
||||
{-| Get a token based on its token value.
|
||||
-}
|
||||
getTokenId : String -> Timeline -> Maybe TokenId
|
||||
getToken v timeline =
|
||||
Dict.get v timeline.tokenToId
|
||||
getTokenFromTokenValue : TokenValue -> Timeline -> Maybe Token
|
||||
getTokenFromTokenValue value timeline =
|
||||
timeline
|
||||
|> getTokenIdFromTokenValue value
|
||||
|> Maybe.andThen (\tid -> getTokenFromTokenId tid timeline)
|
||||
|
||||
{-| Insert a new slice into the timeline.
|
||||
{-| Get the token id based on a token value. The function returns Nothing if it
|
||||
isn't on the timeline.
|
||||
-}
|
||||
getTokenIdFromTokenValue : TokenValue -> Timeline -> Maybe TokenId
|
||||
getTokenIdFromTokenValue value timeline =
|
||||
Dict.get value timeline.tokenToId
|
||||
|
||||
{-| Get the token's id. The function returns Nothing if the token isn't on the
|
||||
timeline.
|
||||
-}
|
||||
getTokenIdFromToken : Token -> Timeline -> Maybe TokenId
|
||||
getTokenIdFromToken (Token { head, tail }) timeline =
|
||||
List.foldl
|
||||
(\value ptr ->
|
||||
case ptr of
|
||||
Nothing ->
|
||||
getTokenIdFromTokenValue value timeline
|
||||
|
||||
Just _ ->
|
||||
ptr
|
||||
)
|
||||
Nothing (head :: tail)
|
||||
|
||||
{-| Insert a new slice into the timeline. This is a raw operation that should
|
||||
never be exposed!
|
||||
-}
|
||||
insertSlice : Slice -> Timeline -> ( SliceId, Timeline )
|
||||
insertSlice slice timeline =
|
||||
|
@ -107,7 +266,8 @@ insertSlice slice timeline =
|
|||
|> Iddict.insert slice
|
||||
|> Tuple.mapBoth SliceId (\x -> { timeline | slices = x })
|
||||
|
||||
{-| Insert a new token into the timeline.
|
||||
{-| Insert a new token into the timeline. This is a raw operation that should
|
||||
never be exposed!
|
||||
-}
|
||||
insertToken : Token -> Timeline -> ( TokenId, Timeline )
|
||||
insertToken ((Token { head }) as token) timeline =
|
||||
|
@ -120,6 +280,18 @@ insertToken ((Token { head }) as token) timeline =
|
|||
}
|
||||
)
|
||||
|
||||
{-| Whether a list contains a given slice id.
|
||||
-}
|
||||
isConnectedToSlice : SliceId -> List SliceId -> Bool
|
||||
isConnectedToSlice (SliceId a) =
|
||||
List.any (\(SliceId b) -> a == b)
|
||||
|
||||
{-| Whether a list contains a given token id.
|
||||
-}
|
||||
isConnectedToToken : TokenId -> List TokenId -> Bool
|
||||
isConnectedToToken (TokenId a) =
|
||||
List.any (\(TokenId b) -> a == b)
|
||||
|
||||
{-| Update an existing slice based on its id.
|
||||
-}
|
||||
mapSlice : SliceId -> (Slice -> Slice) -> Timeline -> Timeline
|
||||
|
@ -132,358 +304,30 @@ mapToken : TokenId -> (Token -> Token) -> Timeline -> Timeline
|
|||
mapToken (TokenId tokenId) f timeline =
|
||||
{ timeline | tokens = Iddict.map tokenId f timeline.tokens }
|
||||
|
||||
{-| Merge two lists such that each element only appears once.
|
||||
-}
|
||||
mergeUnique : (a, List a) -> (a, List a) -> (a, List a)
|
||||
mergeUnique (head, tail) (otherHead, otherTail) =
|
||||
otherTail
|
||||
|> List.filter (\e -> e /= otherHead)
|
||||
|> (::) otherHead
|
||||
|> List.filter (\e -> e /= head)
|
||||
|> List.filter (\e -> not <| List.member e tail )
|
||||
|> Tuple.pair head
|
||||
|
||||
-- {-| The Timeline is a comprehensive object describing a timeline in a room.
|
||||
{-| Turn a single slice into a batch.
|
||||
-}
|
||||
sliceToBatch : { start : String, filter : Filter, events : List EventId, end : String } -> Batch
|
||||
sliceToBatch { start, filter, events, end } =
|
||||
case events of
|
||||
[] ->
|
||||
BatchToken end [ start ]
|
||||
|
||||
-- Any Timeline type contains the following pieces of information:
|
||||
head :: tail ->
|
||||
BatchSlice (BatchToken start []) filter head tail end []
|
||||
|
||||
-- - `events` Comprehensive dictionary containing all locally stored timeline events
|
||||
-- - `batches` Comprehensive dictionary containing all batches. Batches are pieces
|
||||
-- of the timeline that have been sent by the homeserver.
|
||||
-- - `token` Dictionary that maps for each batch token which batches it borders
|
||||
-- - `mostRecentSync` Id of the most "recent" batch in the timeline
|
||||
-- -}
|
||||
-- type Timeline
|
||||
-- = Timeline
|
||||
-- { events : Hashdict IEvent
|
||||
-- , batches : Iddict TimelineBatch
|
||||
-- , token : DefaultDict String (List Int)
|
||||
-- , mostRecentSync : Maybe Int
|
||||
-- }
|
||||
|
||||
-- {-| A BatchToken is a token that has been handed out by the server to mark the end of a -}
|
||||
-- type alias BatchToken = String
|
||||
|
||||
-- type alias TimelineBatch =
|
||||
-- { prevBatch : List Batch
|
||||
-- , nextBatch : List Batch
|
||||
-- , filter : Filter
|
||||
-- , events : List String
|
||||
-- , stateDelta : StateManager
|
||||
-- }
|
||||
|
||||
-- type Batch
|
||||
-- = Token BatchToken
|
||||
-- | Batch Int
|
||||
|
||||
-- addNewSync :
|
||||
-- { events : List IEvent
|
||||
-- , filter : Filter
|
||||
-- , limited : Bool
|
||||
-- , nextBatch : String
|
||||
-- , prevBatch : String
|
||||
-- , stateDelta : Maybe StateManager
|
||||
-- } -> Timeline -> Timeline
|
||||
-- addNewSync data (Timeline timeline) =
|
||||
-- let
|
||||
-- batchToInsert : TimelineBatch
|
||||
-- batchToInsert =
|
||||
-- { prevBatch =
|
||||
-- [ Just <| Token data.prevBatch
|
||||
-- , Maybe.map Batch timeline.mostRecentSync
|
||||
-- ]
|
||||
-- |> List.filterMap identity
|
||||
-- , nextBatch =
|
||||
-- [ Token data.nextBatch ]
|
||||
-- , filter = data.filter
|
||||
-- , events = List.map Event.eventId data.events
|
||||
-- , stateDelta = Maybe.withDefault StateManager.empty data.stateDelta
|
||||
-- }
|
||||
-- in
|
||||
-- case Iddict.insert batchToInsert timeline.batches of
|
||||
-- ( batchId, batches ) ->
|
||||
-- Timeline
|
||||
-- { events = List.foldl Hashdict.insert timeline.events data.events
|
||||
-- , batches = batches
|
||||
-- , mostRecentSync = Just batchId
|
||||
-- , token =
|
||||
-- timeline.token
|
||||
-- |> DefaultDict.update data.prevBatch
|
||||
-- (\value ->
|
||||
-- case value of
|
||||
-- Just v ->
|
||||
-- Just (batchId :: v)
|
||||
-- Nothing ->
|
||||
-- Just [ batchId ]
|
||||
-- )
|
||||
-- |> DefaultDict.update data.nextBatch
|
||||
-- (\value ->
|
||||
-- case value of
|
||||
-- Just v ->
|
||||
-- Just (batchId :: v)
|
||||
-- Nothing ->
|
||||
-- Just [ batchId ]
|
||||
-- )
|
||||
-- }
|
||||
|
||||
-- -- type Timeline
|
||||
-- -- = Timeline
|
||||
-- -- { prevBatch : String
|
||||
-- -- , nextBatch : String
|
||||
-- -- , events : List IEvent
|
||||
-- -- , stateAtStart : StateManager
|
||||
-- -- , previous : BeforeTimeline
|
||||
-- -- }
|
||||
|
||||
|
||||
-- type BeforeTimeline
|
||||
-- = Endless String
|
||||
-- | Gap Timeline
|
||||
-- | StartOfTimeline
|
||||
|
||||
|
||||
-- {-| Add a new batch of events to the front of the timeline.
|
||||
-- -}
|
||||
-- addNewEvents :
|
||||
-- { events : List IEvent
|
||||
-- , limited : Bool
|
||||
-- , nextBatch : String
|
||||
-- , prevBatch : String
|
||||
-- , stateDelta : Maybe StateManager
|
||||
-- }
|
||||
-- -> Timeline
|
||||
-- -> Timeline
|
||||
-- addNewEvents { events, limited, nextBatch, prevBatch, stateDelta } (Timeline t) =
|
||||
-- Timeline
|
||||
-- (if prevBatch == t.nextBatch || not limited then
|
||||
-- { t
|
||||
-- | events = t.events ++ events
|
||||
-- , nextBatch = nextBatch
|
||||
-- }
|
||||
|
||||
-- else
|
||||
-- { prevBatch = prevBatch
|
||||
-- , nextBatch = nextBatch
|
||||
-- , events = events
|
||||
-- , stateAtStart =
|
||||
-- t
|
||||
-- |> Timeline
|
||||
-- |> mostRecentState
|
||||
-- |> StateManager.updateRoomStateWith
|
||||
-- (stateDelta
|
||||
-- |> Maybe.withDefault StateManager.empty
|
||||
-- )
|
||||
-- , previous = Gap (Timeline t)
|
||||
-- }
|
||||
-- )
|
||||
|
||||
|
||||
-- {-| Create a new timeline.
|
||||
-- -}
|
||||
-- newFromEvents :
|
||||
-- { events : List IEvent
|
||||
-- , nextBatch : String
|
||||
-- , prevBatch : Maybe String
|
||||
-- , stateDelta : Maybe StateManager
|
||||
-- }
|
||||
-- -> Timeline
|
||||
-- newFromEvents { events, nextBatch, prevBatch, stateDelta } =
|
||||
-- Timeline
|
||||
-- { events = events
|
||||
-- , nextBatch = nextBatch
|
||||
-- , prevBatch =
|
||||
-- prevBatch
|
||||
-- |> Maybe.withDefault Leaking.prevBatch
|
||||
-- , previous =
|
||||
-- prevBatch
|
||||
-- |> Maybe.map Endless
|
||||
-- |> Maybe.withDefault StartOfTimeline
|
||||
-- , stateAtStart =
|
||||
-- stateDelta
|
||||
-- |> Maybe.withDefault StateManager.empty
|
||||
-- }
|
||||
|
||||
|
||||
-- {-| Insert events starting from a known batch token.
|
||||
-- -}
|
||||
-- insertEvents :
|
||||
-- { events : List IEvent
|
||||
-- , nextBatch : String
|
||||
-- , prevBatch : Maybe String
|
||||
-- , stateDelta : Maybe StateManager
|
||||
-- }
|
||||
-- -> Timeline
|
||||
-- -> Timeline
|
||||
-- insertEvents ({ events, nextBatch, prevBatch, stateDelta } as data) (Timeline t) =
|
||||
-- Timeline
|
||||
-- (case prevBatch of
|
||||
-- -- No prevbatch suggests the start of the timeline.
|
||||
-- -- This means that we must recurse until we've hit the bottom,
|
||||
-- -- and then mark the bottom of the timeline.
|
||||
-- Nothing ->
|
||||
-- case t.previous of
|
||||
-- Gap prevT ->
|
||||
-- { t
|
||||
-- | previous =
|
||||
-- prevT
|
||||
-- |> insertEvents data
|
||||
-- |> Gap
|
||||
-- }
|
||||
|
||||
-- _ ->
|
||||
-- if nextBatch == t.prevBatch then
|
||||
-- { t | previous = StartOfTimeline, events = events ++ t.events, stateAtStart = StateManager.empty }
|
||||
|
||||
-- else
|
||||
-- { t | previous = Gap <| newFromEvents data }
|
||||
|
||||
-- -- If there is a prevbatch, it is not the start of the timeline
|
||||
-- -- and could be located anywhere.
|
||||
-- -- Starting at the front, look for a way to match it with the existing timeline.
|
||||
-- Just p ->
|
||||
-- -- Piece connects to the front of the timeline.
|
||||
-- if t.nextBatch == p then
|
||||
-- { t
|
||||
-- | events = t.events ++ events
|
||||
-- , nextBatch = nextBatch
|
||||
-- }
|
||||
-- -- Piece connects to the back of the timeline.
|
||||
|
||||
-- else if nextBatch == t.prevBatch then
|
||||
-- case t.previous of
|
||||
-- Gap (Timeline prevT) ->
|
||||
-- -- Piece also connects to the timeline in the back,
|
||||
-- -- allowing the two timelines to merge.
|
||||
-- if prevT.nextBatch == p then
|
||||
-- { events = prevT.events ++ events ++ t.events
|
||||
-- , nextBatch = t.nextBatch
|
||||
-- , prevBatch = prevT.prevBatch
|
||||
-- , stateAtStart = prevT.stateAtStart
|
||||
-- , previous = prevT.previous
|
||||
-- }
|
||||
|
||||
-- else
|
||||
-- { t
|
||||
-- | events = events ++ t.events
|
||||
-- , prevBatch = p
|
||||
-- , stateAtStart =
|
||||
-- stateDelta
|
||||
-- |> Maybe.withDefault StateManager.empty
|
||||
-- }
|
||||
|
||||
-- Endless _ ->
|
||||
-- { t
|
||||
-- | events = events ++ t.events
|
||||
-- , prevBatch = p
|
||||
-- , stateAtStart =
|
||||
-- stateDelta
|
||||
-- |> Maybe.withDefault StateManager.empty
|
||||
-- , previous = Endless p
|
||||
-- }
|
||||
|
||||
-- _ ->
|
||||
-- { t
|
||||
-- | events = events ++ t.events
|
||||
-- , prevBatch = p
|
||||
-- , stateAtStart =
|
||||
-- stateDelta
|
||||
-- |> Maybe.withDefault StateManager.empty
|
||||
-- }
|
||||
-- -- Piece doesn't connect to this piece of the timeline.
|
||||
-- -- Consequently, look for previous parts of the timeline to see if it connects.
|
||||
|
||||
-- else
|
||||
-- case t.previous of
|
||||
-- Gap prevT ->
|
||||
-- { t
|
||||
-- | previous =
|
||||
-- prevT
|
||||
-- |> insertEvents data
|
||||
-- |> Gap
|
||||
-- }
|
||||
|
||||
-- _ ->
|
||||
-- t
|
||||
-- )
|
||||
|
||||
|
||||
-- {-| Get the width of the latest gap. This data is usually accessed when trying to get more messages.
|
||||
-- -}
|
||||
-- latestGap : Timeline -> Maybe { from : Maybe String, to : String }
|
||||
-- latestGap (Timeline t) =
|
||||
-- case t.previous of
|
||||
-- StartOfTimeline ->
|
||||
-- Nothing
|
||||
|
||||
-- Endless prevBatch ->
|
||||
-- Just { from = Nothing, to = prevBatch }
|
||||
|
||||
-- Gap (Timeline pt) ->
|
||||
-- Just { from = Just pt.nextBatch, to = t.prevBatch }
|
||||
|
||||
|
||||
-- {-| Get the longest uninterrupted length of most recent events.
|
||||
-- -}
|
||||
-- localSize : Timeline -> Int
|
||||
-- localSize =
|
||||
-- mostRecentEvents >> List.length
|
||||
|
||||
|
||||
-- {-| Get a list of the most recent events recorded.
|
||||
-- -}
|
||||
-- mostRecentEvents : Timeline -> List IEvent
|
||||
-- mostRecentEvents (Timeline t) =
|
||||
-- t.events
|
||||
|
||||
|
||||
-- {-| Get the needed `since` parameter to get the latest events.
|
||||
-- -}
|
||||
-- nextSyncToken : Timeline -> String
|
||||
-- nextSyncToken (Timeline t) =
|
||||
-- t.nextBatch
|
||||
|
||||
|
||||
-- {-| Get the state of the room after the most recent event.
|
||||
-- -}
|
||||
-- mostRecentState : Timeline -> StateManager
|
||||
-- mostRecentState (Timeline t) =
|
||||
-- t.stateAtStart
|
||||
-- |> StateManager.updateRoomStateWith
|
||||
-- (StateManager.fromEventList t.events)
|
||||
|
||||
|
||||
-- {-| Get the timeline's room state at any given event. The function returns `Nothing` if the event is not found in the timeline.
|
||||
-- -}
|
||||
-- stateAtEvent : IEvent -> Timeline -> Maybe StateManager
|
||||
-- stateAtEvent event (Timeline t) =
|
||||
-- if
|
||||
-- t.events
|
||||
-- |> List.map Event.eventId
|
||||
-- |> List.member (Event.eventId event)
|
||||
-- then
|
||||
-- Fold.untilCompleted
|
||||
-- List.foldl
|
||||
-- (\e ->
|
||||
-- StateManager.addEvent e
|
||||
-- >> (if Event.eventId e == Event.eventId event then
|
||||
-- Fold.AnswerWith
|
||||
|
||||
-- else
|
||||
-- Fold.ContinueWith
|
||||
-- )
|
||||
-- )
|
||||
-- t.stateAtStart
|
||||
-- t.events
|
||||
-- |> Just
|
||||
|
||||
-- else
|
||||
-- case t.previous of
|
||||
-- Gap prevT ->
|
||||
-- stateAtEvent event prevT
|
||||
|
||||
-- _ ->
|
||||
-- Nothing
|
||||
|
||||
|
||||
-- {-| Count how many events the current timeline is storing.
|
||||
-- -}
|
||||
-- size : Timeline -> Int
|
||||
-- size (Timeline t) =
|
||||
-- (case t.previous of
|
||||
-- Gap prev ->
|
||||
-- size prev
|
||||
|
||||
-- _ ->
|
||||
-- 0
|
||||
-- )
|
||||
-- + List.length t.events
|
||||
{-| Turn a single token into a batch.
|
||||
-}
|
||||
tokenToBatch : String -> Batch
|
||||
tokenToBatch value =
|
||||
BatchToken value []
|
||||
|
|
Loading…
Reference in New Issue