Add event to get older events

pull/1/head
Bram van den Heuvel 2023-03-23 22:45:26 +01:00
parent c32a62c242
commit 098b38170a
7 changed files with 250 additions and 52 deletions

View File

@ -7,6 +7,7 @@ import Hash
import Internal.Api.Chain as Chain import Internal.Api.Chain as Chain
import Internal.Api.Credentials as Cred exposing (Credentials) import Internal.Api.Credentials as Cred exposing (Credentials)
import Internal.Api.GetEvent.Main exposing (EventInput) import Internal.Api.GetEvent.Main exposing (EventInput)
import Internal.Api.GetMessages.Main exposing (GetMessagesInput)
import Internal.Api.Invite.Main exposing (InviteInput) import Internal.Api.Invite.Main exposing (InviteInput)
import Internal.Api.JoinRoomById.Main exposing (JoinRoomByIdInput) import Internal.Api.JoinRoomById.Main exposing (JoinRoomByIdInput)
import Internal.Api.JoinedMembers.Main exposing (JoinedMembersInput) import Internal.Api.JoinedMembers.Main exposing (JoinedMembersInput)
@ -35,6 +36,13 @@ getEvent { eventId, roomId } cred =
|> C.toTask |> C.toTask
getMessages : GetMessagesInput -> Credentials -> FutureTask
getMessages data cred =
C.makeVBA cred
|> Chain.andThen (C.getMessages data)
|> C.toTask
invite : InviteInput -> Credentials -> FutureTask invite : InviteInput -> Credentials -> FutureTask
invite data cred = invite data cred =
C.makeVBA cred C.makeVBA cred

View File

@ -10,6 +10,7 @@ resend other events or forward them elsewhere.
import Internal.Api.Credentials exposing (Credentials) import Internal.Api.Credentials exposing (Credentials)
import Internal.Api.GetEvent.Main as GetEvent import Internal.Api.GetEvent.Main as GetEvent
import Internal.Api.GetEvent.V1.SpecObjects as GetEventSO import Internal.Api.GetEvent.V1.SpecObjects as GetEventSO
import Internal.Api.GetMessages.V4.SpecObjects as GetMessagesSO
import Internal.Api.Sync.V2.SpecObjects as SyncSO import Internal.Api.Sync.V2.SpecObjects as SyncSO
import Internal.Tools.Timestamp exposing (Timestamp) import Internal.Tools.Timestamp exposing (Timestamp)
import Internal.Values.Event as Internal import Internal.Values.Event as Internal
@ -62,6 +63,32 @@ initFromGetEvent output =
} }
{-| Create an internal event type from an API endpoint event object.
This function is placed in this file to respect file hierarchy and avoid circular imports.
-}
initFromGetMessages : GetMessagesSO.ClientEvent -> Internal.IEvent
initFromGetMessages output =
Internal.init
{ content = output.content
, eventId = output.eventId
, originServerTs = output.originServerTs
, roomId = output.roomId
, sender = output.sender
, stateKey = output.stateKey
, contentType = output.contentType
, unsigned =
output.unsigned
|> Maybe.map
(\(GetMessagesSO.UnsignedData data) ->
{ age = data.age
, prevContent = data.prevContent
, redactedBecause = Maybe.map initFromGetMessages data.redactedBecause
, transactionId = data.transactionId
}
)
}
{-| Create an internal event type from an API endpoint event object. {-| Create an internal event type from an API endpoint event object.
This function is placed in this file to respect file hierarchy and avoid circular imports. This function is placed in this file to respect file hierarchy and avoid circular imports.
-} -}

View File

@ -7,10 +7,11 @@ import Dict
import Internal.Api.Credentials exposing (Credentials) import Internal.Api.Credentials exposing (Credentials)
import Internal.Api.Sync.V2.SpecObjects as Sync import Internal.Api.Sync.V2.SpecObjects as Sync
import Internal.Api.Task as Api import Internal.Api.Task as Api
import Internal.Api.VaultUpdate exposing (VaultUpdate) import Internal.Api.VaultUpdate exposing (VaultUpdate(..))
import Internal.Event as Event exposing (Event) import Internal.Event as Event exposing (Event)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Internal.Tools.Hashdict as Hashdict import Internal.Tools.Hashdict as Hashdict
import Internal.Tools.SpecEnums as Enums
import Internal.Values.Event as IEvent import Internal.Values.Event as IEvent
import Internal.Values.Room as Internal import Internal.Values.Room as Internal
import Internal.Values.StateManager as StateManager import Internal.Values.StateManager as StateManager
@ -118,6 +119,26 @@ withoutCredentials (Room { room }) =
room room
{-| Get older events from the Matrix API.
-}
getOlderEvents : { limit : Maybe Int } -> Room -> Task X.Error VaultUpdate
getOlderEvents { limit } (Room { context, room }) =
case Internal.latestGap room of
Nothing ->
Task.succeed (MultipleUpdates [])
Just { from, to } ->
Api.getMessages
{ direction = Enums.ReverseChronological
, filter = Nothing
, from = Just to
, limit = limit
, roomId = Internal.roomId room
, to = from
}
context
{-| Get the most recent events. {-| Get the most recent events.
-} -}
mostRecentEvents : Room -> List Event mostRecentEvents : Room -> List Event

View File

@ -59,11 +59,28 @@ getStateEvent data (IRoom room) =
|> StateManager.getStateEvent data |> StateManager.getStateEvent data
{-| Get the room's id. {-| Insert a chunk of events into a room.
-} -}
roomId : IRoom -> String insertEvents :
roomId (IRoom room) = { events : List IEvent
room.roomId , nextBatch : String
, prevBatch : Maybe String
, stateDelta : Maybe StateManager
}
-> IRoom
-> IRoom
insertEvents data (IRoom ({ timeline } as room)) =
IRoom
{ room | timeline = Timeline.insertEvents data timeline }
|> List.foldl addEvent
|> (|>) data.events
{-| Get the latest gap.
-}
latestGap : IRoom -> Maybe { from : Maybe String, to : String }
latestGap (IRoom room) =
Timeline.latestGap room.timeline
{-| Get the most recent events. {-| Get the most recent events.
@ -71,3 +88,10 @@ roomId (IRoom room) =
mostRecentEvents : IRoom -> List IEvent mostRecentEvents : IRoom -> List IEvent
mostRecentEvents (IRoom room) = mostRecentEvents (IRoom room) =
Timeline.mostRecentEvents room.timeline Timeline.mostRecentEvents room.timeline
{-| Get the room's id.
-}
roomId : IRoom -> String
roomId (IRoom room) =
room.roomId

View File

@ -92,63 +92,119 @@ newFromEvents { events, nextBatch, prevBatch, stateDelta } =
insertEvents : insertEvents :
{ events : List IEvent { events : List IEvent
, nextBatch : String , nextBatch : String
, prevBatch : String , prevBatch : Maybe String
, stateDelta : Maybe StateManager , stateDelta : Maybe StateManager
} }
-> Timeline -> Timeline
-> Timeline -> Timeline
insertEvents ({ events, nextBatch, prevBatch, stateDelta } as data) (Timeline t) = insertEvents ({ events, nextBatch, prevBatch, stateDelta } as data) (Timeline t) =
Timeline Timeline
(if t.nextBatch == prevBatch then (case prevBatch of
{ t -- No prevbatch suggests the start of the timeline.
| events = t.events ++ events -- This means that we must recurse until we've hit the bottom,
, nextBatch = nextBatch -- and then mark the bottom of the timeline.
} Nothing ->
case t.previous of
else if nextBatch == t.prevBatch then Gap prevT ->
case t.previous of
Gap (Timeline prevT) ->
if prevT.nextBatch == prevBatch then
{ events = prevT.events ++ events ++ t.events
, nextBatch = t.nextBatch
, prevBatch = prevT.prevBatch
, stateAtStart = prevT.stateAtStart
, previous = prevT.previous
}
else
{ t { t
| events = events ++ t.events | previous =
, prevBatch = prevBatch prevT
, stateAtStart = |> insertEvents data
stateDelta |> Gap
|> Maybe.withDefault StateManager.empty
} }
_ -> _ ->
{ t if nextBatch == t.prevBatch then
| events = events ++ t.events { t | previous = StartOfTimeline, events = events ++ t.events, stateAtStart = StateManager.empty }
, prevBatch = prevBatch
, stateAtStart =
stateDelta
|> Maybe.withDefault StateManager.empty
}
else else
case t.previous of { t | previous = Gap <| newFromEvents data }
Gap prevT ->
{ t
| previous =
prevT
|> insertEvents data
|> Gap
}
_ -> -- If there is a prevbatch, it is not the start of the timeline
t -- 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. {-| Get the longest uninterrupted length of most recent events.
-} -}
localSize : Timeline -> Int localSize : Timeline -> Int

View File

@ -16,6 +16,7 @@ import Internal.Event as Event
import Internal.Invite as Invite import Internal.Invite as Invite
import Internal.Room as Room import Internal.Room as Room
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Internal.Tools.SpecEnums as Enums
import Internal.Values.Room as IRoom import Internal.Values.Room as IRoom
import Internal.Values.RoomInvite exposing (IRoomInvite) import Internal.Values.RoomInvite exposing (IRoomInvite)
import Internal.Values.StateManager as StateManager import Internal.Values.StateManager as StateManager
@ -125,8 +126,62 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
vault vault
-- TODO -- TODO
GetMessages _ _ -> GetMessages input output ->
vault let
prevBatch : Maybe String
prevBatch =
case input.direction of
Enums.Chronological ->
Just output.start
Enums.ReverseChronological ->
case output.end of
Just end ->
Just end
Nothing ->
input.to
nextBatch : Maybe String
nextBatch =
case input.direction of
Enums.Chronological ->
case output.end of
Just end ->
Just end
Nothing ->
input.to
Enums.ReverseChronological ->
Just output.start
in
case ( getRoomById input.roomId vault, nextBatch ) of
( Just room, Just nb ) ->
room
|> Room.withoutCredentials
|> IRoom.insertEvents
{ events =
output.chunk
|> List.map Event.initFromGetMessages
|> (\x ->
case input.direction of
Enums.Chronological ->
x
Enums.ReverseChronological ->
List.reverse x
)
, prevBatch = prevBatch
, nextBatch = nb
, stateDelta = Just <| StateManager.fromEventList (List.map Event.initFromGetMessages output.state)
}
|> Internal.insertRoom
|> (|>) cred
|> (\v -> Vault { cred = v, context = context })
_ ->
vault
-- TODO -- TODO
InviteSent _ _ -> InviteSent _ _ ->

View File

@ -1,5 +1,5 @@
module Matrix.Room exposing module Matrix.Room exposing
( Room, roomId, mostRecentEvents ( Room, roomId, mostRecentEvents, findOlderEvents
, sendMessage, sendMessages, sendOneEvent, sendMultipleEvents , sendMessage, sendMessages, sendOneEvent, sendMultipleEvents
) )
@ -10,7 +10,7 @@ module Matrix.Room exposing
A room represents a channel of communication within a Matrix home server. A room represents a channel of communication within a Matrix home server.
@docs Room, roomId, mostRecentEvents @docs Room, roomId, mostRecentEvents, findOlderEvents
# Sending events # Sending events
@ -35,6 +35,13 @@ type alias Room =
Internal.Room Internal.Room
{-| If you want more events as part of the most recent events, you can run this task to get more.
-}
findOlderEvents : { limit : Maybe Int, room : Room } -> Task X.Error VaultUpdate
findOlderEvents { limit, room } =
Internal.getOlderEvents { limit = limit } room
{-| Get the most recent events from this room. {-| Get the most recent events from this room.
-} -}
mostRecentEvents : Room -> List Event.Event mostRecentEvents : Room -> List Event.Event