diff --git a/src/Internal/Context.elm b/src/Internal/Context.elm new file mode 100644 index 0000000..6c33d2b --- /dev/null +++ b/src/Internal/Context.elm @@ -0,0 +1,73 @@ +module Internal.Context exposing (..) + +{-| The `Context` type serves as an extra layer between the internal Room/Event types +and the types that the user may deal with directly. + +Since pointers cannot point to values that the `Credentials` type has, +the `Credentials` type passes information down in the form of a `Context` type. + +-} + +import Internal.Api.PreApi.Objects.Versions as V +import Internal.Tools.LoginValues as Login exposing (AccessToken(..)) + + +type Context + = Context + { access : AccessToken + , homeserver : String + , vs : Maybe V.Versions + } + + +{-| Retrieves the access token from a given `Context` value. +-} +accessToken : Context -> AccessToken +accessToken (Context { access }) = + access + + +{-| Add a new access token to the `Context` type. +-} +addToken : String -> Context -> Context +addToken token (Context ({ access } as data)) = + Context { data | access = Login.addToken token access } + + +{-| Add a username and password to the `Context` type. +-} +addUsernameAndPassword : { username : String, password : String } -> Context -> Context +addUsernameAndPassword uap (Context ({ access } as data)) = + Context { data | access = Login.addUsernameAndPassword uap access } + + +{-| Add known spec versions to the `Context` type. +-} +addVersions : V.Versions -> Context -> Context +addVersions vs (Context data) = + Context { data | vs = Just vs } + + +{-| Retrieves the base url from a given `Context` value. +-} +baseUrl : Context -> String +baseUrl (Context { homeserver }) = + homeserver + + +{-| Creates a `Context` value from a base URL. +-} +fromBaseUrl : String -> Context +fromBaseUrl url = + Context + { access = NoAccess + , homeserver = url + , vs = Nothing + } + + +{-| Retrieves the spec versions from a given `Context` value. +-} +versions : Context -> Maybe V.Versions +versions (Context { vs }) = + vs diff --git a/src/Internal/Credentials.elm b/src/Internal/Credentials.elm index bcdab2b..cb676f4 100644 --- a/src/Internal/Credentials.elm +++ b/src/Internal/Credentials.elm @@ -9,6 +9,7 @@ This file combines the internal functions with the API endpoints to create a ful import Dict import Internal.Api.All as Api +import Internal.Context as Context exposing (Context) import Internal.Event as Event import Internal.Room as Room import Internal.Tools.Exceptions as X @@ -24,8 +25,11 @@ and Elm will figure out which key to use. If you pass the `Credentials` into any function, then the library will look for the right keys and tokens to get the right information. -} -type alias Credentials = - Internal.Credentials +type Credentials + = Credentials + { cred : Internal.ICredentials + , context : Context + } {-| Get a Credentials type based on an unknown access token. @@ -34,50 +38,57 @@ This is an easier way to connect to a Matrix homeserver, but your access may end when the access token expires, is revoked or something else happens. -} -fromAccessToken : { homeserver : String, accessToken : String } -> Credentials -fromAccessToken = - Internal.fromAccessToken +fromAccessToken : { baseUrl : String, accessToken : String } -> Credentials +fromAccessToken { baseUrl, accessToken } = + Context.fromBaseUrl baseUrl + |> Context.addToken accessToken + |> (\context -> + { cred = Internal.init, context = context } + ) + |> Credentials {-| Get a Credentials type using a username and password. -} -fromLoginCredentials : { username : String, password : String, homeserver : String } -> Credentials -fromLoginCredentials = - Internal.fromLoginCredentials +fromLoginCredentials : { username : String, password : String, baseUrl : String } -> Credentials +fromLoginCredentials { username, password, baseUrl } = + Context.fromBaseUrl baseUrl + |> Context.addUsernameAndPassword + { username = username + , password = password + } + |> (\context -> + { cred = Internal.init, context = context } + ) + |> Credentials {-| Get a room based on its id. -} getRoomById : String -> Credentials -> Maybe Room.Room -getRoomById roomId credentials = - Internal.getRoomById roomId credentials - |> Maybe.map - (Room.init - { accessToken = Internal.getAccessTokenType credentials - , baseUrl = Internal.getBaseUrl credentials - , versions = Internal.getVersions credentials - } - ) +getRoomById roomId (Credentials { cred, context }) = + Internal.getRoomById roomId cred + |> Maybe.map (Room.withContext context) {-| Insert an internal room type into the credentials. -} -insertInternalRoom : IRoom.Room -> Credentials -> Credentials -insertInternalRoom = - Internal.insertRoom +insertInternalRoom : IRoom.IRoom -> Credentials -> Credentials +insertInternalRoom iroom (Credentials data) = + Credentials { data | cred = Internal.insertRoom iroom data.cred } {-| Internal a full room type into the credentials. -} insertRoom : Room.Room -> Credentials -> Credentials insertRoom = - Room.internalValue >> insertInternalRoom + Room.withoutContext >> insertInternalRoom {-| Update the Credentials type with new values -} updateWith : Api.CredUpdate -> Credentials -> Credentials -updateWith credUpdate credentials = +updateWith credUpdate ((Credentials ({ cred, context } as data)) as credentials) = case credUpdate of Api.MultipleUpdates updates -> List.foldl updateWith credentials updates @@ -109,6 +120,7 @@ updateWith credUpdate credentials = -- TODO Api.SyncUpdate input output -> let + jRooms : List IRoom.IRoom jRooms = output.rooms |> Maybe.map .join @@ -119,68 +131,73 @@ updateWith credUpdate credentials = case getRoomById roomId credentials of -- Update existing room Just room -> - room - |> Room.internalValue - |> IRoom.addEvents - { events = - jroom.timeline - |> Maybe.map .events - |> Maybe.withDefault [] - |> List.map (Event.initFromClientEventWithoutRoomId roomId) - , nextBatch = output.nextBatch - , prevBatch = - jroom.timeline - |> Maybe.andThen .prevBatch - |> Maybe.withDefault (Maybe.withDefault "" input.since) - , stateDelta = - jroom.state - |> Maybe.map - (.events - >> List.map (Event.initFromClientEventWithoutRoomId roomId) - >> StateManager.fromEventList - ) - } + case jroom.timeline of + Just timeline -> + room + |> Room.withoutContext + |> IRoom.addEvents + { events = + List.map + (Event.initFromClientEventWithoutRoomId roomId) + timeline.events + , limited = timeline.limited + , nextBatch = output.nextBatch + , prevBatch = + timeline.prevBatch + |> Maybe.withDefault + (Maybe.withDefault "" input.since) + , stateDelta = + jroom.state + |> Maybe.map + (.events + >> List.map (Event.initFromClientEventWithoutRoomId roomId) + >> StateManager.fromEventList + ) + } + + Nothing -> + Room.withoutContext room -- Add new room Nothing -> - Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId } jroom + jroom + |> Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId } ) in - List.foldl Internal.insertRoom (Internal.addSince output.nextBatch credentials) jRooms + cred + |> Internal.addSince output.nextBatch + |> List.foldl Internal.insertRoom + |> (|>) jRooms + |> (\x -> { cred = x, context = context }) + |> Credentials Api.UpdateAccessToken token -> - Internal.addAccessToken token credentials + Credentials { data | context = Context.addToken token context } Api.UpdateVersions versions -> - Internal.addVersions versions credentials + Credentials { data | context = Context.addVersions versions context } {-| Synchronize credentials -} sync : Credentials -> Task X.Error Api.CredUpdate -sync credentials = +sync (Credentials { cred, context }) = Api.syncCredentials - { accessToken = Internal.getAccessTokenType credentials - , baseUrl = Internal.getBaseUrl credentials + { accessToken = Context.accessToken context + , baseUrl = Context.baseUrl context , filter = Nothing , fullState = Nothing , setPresence = Nothing - , since = Internal.getSince credentials + , since = Internal.getSince cred , timeout = Just 30 - , versions = Internal.getVersions credentials + , versions = Context.versions context } {-| Get a list of all synchronised rooms. -} rooms : Credentials -> List Room.Room -rooms credentials = - credentials +rooms (Credentials { cred, context }) = + cred |> Internal.getRooms - |> ({ accessToken = Internal.getAccessTokenType credentials - , baseUrl = Internal.getBaseUrl credentials - , versions = Internal.getVersions credentials - } - |> Room.init - |> List.map - ) + |> List.map (Room.withContext context) diff --git a/src/Internal/Event.elm b/src/Internal/Event.elm index fe831cc..778274f 100644 --- a/src/Internal/Event.elm +++ b/src/Internal/Event.elm @@ -9,9 +9,8 @@ resend other events or forward them elsewhere. import Internal.Api.GetEvent.Main as GetEvent import Internal.Api.GetEvent.V1.SpecObjects as GetEventSO -import Internal.Api.PreApi.Objects.Versions as V import Internal.Api.Sync.V2.SpecObjects as SyncSO -import Internal.Tools.LoginValues exposing (AccessToken) +import Internal.Context exposing (Context) import Internal.Tools.Timestamp exposing (Timestamp) import Internal.Values.Event as Internal import Json.Encode as E @@ -21,30 +20,26 @@ import Json.Encode as E -} type Event = Event - { event : Internal.Event - , accessToken : AccessToken - , baseUrl : String - , versions : Maybe V.Versions + { event : Internal.IEvent + , context : Context } {-| Using the credentials' background information and an internal event type, create an interactive event type. -} -init : { accessToken : AccessToken, baseUrl : String, versions : Maybe V.Versions } -> Internal.Event -> Event -init { accessToken, baseUrl, versions } event = +withContext : Context -> Internal.IEvent -> Event +withContext context event = Event { event = event - , accessToken = accessToken - , baseUrl = baseUrl - , versions = versions + , context = context } {-| 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. -} -initFromGetEvent : GetEvent.EventOutput -> Internal.Event +initFromGetEvent : GetEvent.EventOutput -> Internal.IEvent initFromGetEvent output = Internal.init { content = output.content @@ -70,7 +65,7 @@ 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. -} -initFromClientEventWithoutRoomId : String -> SyncSO.ClientEventWithoutRoomId -> Internal.Event +initFromClientEventWithoutRoomId : String -> SyncSO.ClientEventWithoutRoomId -> Internal.IEvent initFromClientEventWithoutRoomId rId output = Internal.init { content = output.content @@ -95,8 +90,8 @@ initFromClientEventWithoutRoomId rId output = {-| Get the internal event type that is hidden in the interactive event type. -} -internalValue : Event -> Internal.Event -internalValue (Event { event }) = +withoutContext : Event -> Internal.IEvent +withoutContext (Event { event }) = event @@ -106,42 +101,42 @@ internalValue (Event { event }) = content : Event -> E.Value content = - internalValue >> Internal.content + withoutContext >> Internal.content eventId : Event -> String eventId = - internalValue >> Internal.eventId + withoutContext >> Internal.eventId originServerTs : Event -> Timestamp originServerTs = - internalValue >> Internal.originServerTs + withoutContext >> Internal.originServerTs roomId : Event -> String roomId = - internalValue >> Internal.roomId + withoutContext >> Internal.roomId sender : Event -> String sender = - internalValue >> Internal.sender + withoutContext >> Internal.sender stateKey : Event -> Maybe String stateKey = - internalValue >> Internal.stateKey + withoutContext >> Internal.stateKey contentType : Event -> String contentType = - internalValue >> Internal.contentType + withoutContext >> Internal.contentType age : Event -> Maybe Int age = - internalValue >> Internal.age + withoutContext >> Internal.age redactedBecause : Event -> Maybe Event @@ -156,4 +151,4 @@ redactedBecause (Event data) = transactionId : Event -> Maybe String transactionId = - internalValue >> Internal.transactionId + withoutContext >> Internal.transactionId diff --git a/src/Internal/Room.elm b/src/Internal/Room.elm index e835116..69bba43 100644 --- a/src/Internal/Room.elm +++ b/src/Internal/Room.elm @@ -5,12 +5,11 @@ module Internal.Room exposing (..) import Dict import Internal.Api.All as Api -import Internal.Api.PreApi.Objects.Versions as V import Internal.Api.Sync.V2.SpecObjects as Sync +import Internal.Context as Context exposing (Context) import Internal.Event as Event exposing (Event) import Internal.Tools.Exceptions as X import Internal.Tools.Hashdict as Hashdict -import Internal.Tools.LoginValues exposing (AccessToken) import Internal.Values.Event as IEvent import Internal.Values.Room as Internal import Internal.Values.StateManager as StateManager @@ -29,18 +28,16 @@ to it. -} type Room = Room - { room : Internal.Room - , accessToken : AccessToken - , baseUrl : String - , versions : Maybe V.Versions + { room : Internal.IRoom + , context : Context } {-| Create a new object from a joined room. -} -initFromJoinedRoom : { roomId : String, nextBatch : String } -> Sync.JoinedRoom -> Internal.Room +initFromJoinedRoom : { roomId : String, nextBatch : String } -> Sync.JoinedRoom -> Internal.IRoom initFromJoinedRoom data jroom = - Internal.Room + Internal.IRoom { accountData = jroom.accountData |> Maybe.map .events @@ -90,7 +87,7 @@ initFromJoinedRoom data jroom = {-| Adds an internal event to the `Room`. An internal event is a custom event that has been generated by the client. -} -addInternalEvent : IEvent.Event -> Room -> Room +addInternalEvent : IEvent.IEvent -> Room -> Room addInternalEvent ievent (Room ({ room } as data)) = Room { data | room = Internal.addEvent ievent room } @@ -100,61 +97,53 @@ addInternalEvent ievent (Room ({ room } as data)) = -} addEvent : Event -> Room -> Room addEvent = - Event.internalValue >> addInternalEvent + Event.withoutContext >> addInternalEvent {-| Creates a new `Room` object with the given parameters. -} -init : { accessToken : AccessToken, baseUrl : String, versions : Maybe V.Versions } -> Internal.Room -> Room -init { accessToken, baseUrl, versions } room = +withContext : Context -> Internal.IRoom -> Room +withContext context room = Room - { accessToken = accessToken - , baseUrl = baseUrl + { context = context , room = room - , versions = versions } -{-| Retrieves the `Internal.Room` type contained within the given `Room`. +{-| Retrieves the `Internal.IRoom` type contained within the given `Room`. -} -internalValue : Room -> Internal.Room -internalValue (Room { room }) = +withoutContext : Room -> Internal.IRoom +withoutContext (Room { room }) = room {-| Get the most recent events. -} mostRecentEvents : Room -> List Event -mostRecentEvents (Room data) = - data.room +mostRecentEvents (Room { context, room }) = + room |> Internal.mostRecentEvents - |> List.map - (Event.init - { accessToken = data.accessToken - , baseUrl = data.baseUrl - , versions = data.versions - } - ) + |> List.map (Event.withContext context) {-| Retrieves the ID of the Matrix room associated with the given `Room`. -} roomId : Room -> String roomId = - internalValue >> Internal.roomId + withoutContext >> Internal.roomId {-| Sends a new event to the Matrix room associated with the given `Room`. -} sendEvent : Room -> { eventType : String, content : E.Value } -> Task X.Error Api.CredUpdate -sendEvent (Room { room, accessToken, baseUrl, versions }) { eventType, content } = +sendEvent (Room { context, room }) { eventType, content } = Api.sendMessageEvent - { accessToken = accessToken - , baseUrl = baseUrl + { accessToken = Context.accessToken context + , baseUrl = Context.baseUrl context , content = content , eventType = eventType , roomId = Internal.roomId room - , versions = versions + , versions = Context.versions context , extraTransactionNoise = "content-value:" } @@ -162,10 +151,10 @@ sendEvent (Room { room, accessToken, baseUrl, versions }) { eventType, content } {-| Sends a new text message to the Matrix room associated with the given `Room`. -} sendMessage : Room -> String -> Task X.Error Api.CredUpdate -sendMessage (Room { room, accessToken, baseUrl, versions }) text = +sendMessage (Room { context, room }) text = Api.sendMessageEvent - { accessToken = accessToken - , baseUrl = baseUrl + { accessToken = Context.accessToken context + , baseUrl = Context.baseUrl context , content = E.object [ ( "msgtype", E.string "m.text" ) @@ -173,6 +162,6 @@ sendMessage (Room { room, accessToken, baseUrl, versions }) text = ] , eventType = "m.room.message" , roomId = Internal.roomId room - , versions = versions + , versions = Context.versions context , extraTransactionNoise = "literal-message:" ++ text } diff --git a/src/Internal/Tools/LoginValues.elm b/src/Internal/Tools/LoginValues.elm index 165aab2..8a3e5a9 100644 --- a/src/Internal/Tools/LoginValues.elm +++ b/src/Internal/Tools/LoginValues.elm @@ -54,3 +54,28 @@ addToken s t = , password = password , token = Just s } + + +addUsernameAndPassword : { username : String, password : String } -> AccessToken -> AccessToken +addUsernameAndPassword { username, password } t = + case t of + NoAccess -> + UsernameAndPassword + { username = username + , password = password + , token = Nothing + } + + AccessToken a -> + UsernameAndPassword + { username = username + , password = password + , token = Just a + } + + UsernameAndPassword { token } -> + UsernameAndPassword + { username = username + , password = password + , token = token + } diff --git a/src/Internal/Values/Credentials.elm b/src/Internal/Values/Credentials.elm index bb74cc9..21d3edd 100644 --- a/src/Internal/Values/Credentials.elm +++ b/src/Internal/Values/Credentials.elm @@ -4,129 +4,61 @@ module Internal.Values.Credentials exposing (..) It handles all communication with the homeserver. -} -import Internal.Api.PreApi.Objects.Versions as V import Internal.Tools.Hashdict as Hashdict exposing (Hashdict) -import Internal.Tools.LoginValues as Login exposing (AccessToken(..)) -import Internal.Values.Room as Room exposing (Room) +import Internal.Values.Room as Room exposing (IRoom) -type Credentials - = Credentials - { access : AccessToken - , baseUrl : String - , rooms : Hashdict Room +type ICredentials + = ICredentials + { rooms : Hashdict IRoom , since : Maybe String - , versions : Maybe V.Versions } -{-| Add a new access token based on prior information. --} -addAccessToken : String -> Credentials -> Credentials -addAccessToken token (Credentials ({ access } as data)) = - Credentials { data | access = Login.addToken token access } - - -{-| Add the list of versions that is supported by the homeserver. --} -addVersions : V.Versions -> Credentials -> Credentials -addVersions versions (Credentials data) = - Credentials { data | versions = Just versions } - - {-| Add a new `since` token to sync from. -} -addSince : String -> Credentials -> Credentials -addSince since (Credentials data) = - Credentials { data | since = Just since } - - -{-| Get the stringed access token the Credentials type is using, if any. --} -getAccessToken : Credentials -> Maybe String -getAccessToken = - getAccessTokenType >> Login.getToken - - -{-| Get the access token type that stores the Credentials's ways of getting access. --} -getAccessTokenType : Credentials -> AccessToken -getAccessTokenType (Credentials { access }) = - access - - -{-| Get the baseUrl that the credentials accesses. --} -getBaseUrl : Credentials -> String -getBaseUrl (Credentials { baseUrl }) = - baseUrl - - -{-| Get the versions that the homeserver supports. --} -getVersions : Credentials -> Maybe V.Versions -getVersions (Credentials { versions }) = - versions - - -{-| Internal value to be used as a "default" for credentials settings. --} -defaultCredentials : String -> Credentials -defaultCredentials homeserver = - Credentials - { access = NoAccess - , baseUrl = homeserver - , rooms = Hashdict.empty Room.roomId - , since = Nothing - , versions = Nothing - } - - -{-| Get the latest `since` token. --} -getSince : Credentials -> Maybe String -getSince (Credentials { since }) = - since - - -{-| Create a Credentials type using an unknown access token. --} -fromAccessToken : { accessToken : String, homeserver : String } -> Credentials -fromAccessToken { accessToken, homeserver } = - case defaultCredentials homeserver of - Credentials c -> - Credentials { c | access = AccessToken accessToken } - - -{-| Create a Credentials type using a username and password. --} -fromLoginCredentials : { username : String, password : String, homeserver : String } -> Credentials -fromLoginCredentials { username, password, homeserver } = - case defaultCredentials homeserver of - Credentials c -> - Credentials { c | access = UsernameAndPassword { username = username, password = password, token = Nothing } } +addSince : String -> ICredentials -> ICredentials +addSince since (ICredentials data) = + ICredentials { data | since = Just since } {-| Get a room from the Credentials type by the room's id. -} -getRoomById : String -> Credentials -> Maybe Room -getRoomById roomId (Credentials cred) = +getRoomById : String -> ICredentials -> Maybe IRoom +getRoomById roomId (ICredentials cred) = Hashdict.get roomId cred.rooms +{-| Get a list of all synchronised rooms. +-} +getRooms : ICredentials -> List IRoom +getRooms (ICredentials { rooms }) = + Hashdict.values rooms + + +{-| Get the latest `since` token. +-} +getSince : ICredentials -> Maybe String +getSince (ICredentials { since }) = + since + + +{-| Create new empty Credentials. +-} +init : ICredentials +init = + ICredentials + { rooms = Hashdict.empty Room.roomId + , since = Nothing + } + + {-| Add a new room to the Credentials type. If a room with this id already exists, it is overwritten. This function can hence also be used as an update function for rooms. -} -insertRoom : Room -> Credentials -> Credentials -insertRoom room (Credentials cred) = - Credentials +insertRoom : IRoom -> ICredentials -> ICredentials +insertRoom room (ICredentials cred) = + ICredentials { cred | rooms = Hashdict.insert room cred.rooms } - - -{-| Get a list of all synchronised rooms. --} -getRooms : Credentials -> List Room -getRooms (Credentials { rooms }) = - Hashdict.values rooms diff --git a/src/Internal/Values/Event.elm b/src/Internal/Values/Event.elm index b373a61..2ac8640 100644 --- a/src/Internal/Values/Event.elm +++ b/src/Internal/Values/Event.elm @@ -4,8 +4,8 @@ import Internal.Tools.Timestamp exposing (Timestamp) import Json.Encode as E -type Event - = Event +type IEvent + = IEvent { content : E.Value , eventId : String , originServerTs : Timestamp @@ -17,7 +17,7 @@ type Event Maybe { age : Maybe Int , prevContent : Maybe E.Value - , redactedBecause : Maybe Event + , redactedBecause : Maybe IEvent , transactionId : Maybe String } } @@ -35,68 +35,68 @@ init : Maybe { age : Maybe Int , prevContent : Maybe E.Value - , redactedBecause : Maybe Event + , redactedBecause : Maybe IEvent , transactionId : Maybe String } } - -> Event + -> IEvent init = - Event + IEvent {- GETTER FUNCTIONS -} -content : Event -> E.Value -content (Event e) = +content : IEvent -> E.Value +content (IEvent e) = e.content -eventId : Event -> String -eventId (Event e) = +eventId : IEvent -> String +eventId (IEvent e) = e.eventId -originServerTs : Event -> Timestamp -originServerTs (Event e) = +originServerTs : IEvent -> Timestamp +originServerTs (IEvent e) = e.originServerTs -roomId : Event -> String -roomId (Event e) = +roomId : IEvent -> String +roomId (IEvent e) = e.roomId -sender : Event -> String -sender (Event e) = +sender : IEvent -> String +sender (IEvent e) = e.sender -stateKey : Event -> Maybe String -stateKey (Event e) = +stateKey : IEvent -> Maybe String +stateKey (IEvent e) = e.stateKey -contentType : Event -> String -contentType (Event e) = +contentType : IEvent -> String +contentType (IEvent e) = e.contentType -age : Event -> Maybe Int -age (Event e) = +age : IEvent -> Maybe Int +age (IEvent e) = e.unsigned |> Maybe.andThen .age -redactedBecause : Event -> Maybe Event -redactedBecause (Event e) = +redactedBecause : IEvent -> Maybe IEvent +redactedBecause (IEvent e) = e.unsigned |> Maybe.andThen .redactedBecause -transactionId : Event -> Maybe String -transactionId (Event e) = +transactionId : IEvent -> Maybe String +transactionId (IEvent e) = e.unsigned |> Maybe.andThen .transactionId diff --git a/src/Internal/Values/Room.elm b/src/Internal/Values/Room.elm index 5e8ec6e..b95aab4 100644 --- a/src/Internal/Values/Room.elm +++ b/src/Internal/Values/Room.elm @@ -3,17 +3,17 @@ module Internal.Values.Room exposing (..) import Dict exposing (Dict) import Internal.Tools.Hashdict as Hashdict exposing (Hashdict) import Internal.Tools.SpecEnums exposing (SessionDescriptionType(..)) -import Internal.Values.Event as Event exposing (BlindEvent, Event) +import Internal.Values.Event exposing (BlindEvent, IEvent) import Internal.Values.StateManager exposing (StateManager) import Internal.Values.Timeline as Timeline exposing (Timeline) import Json.Encode as E -type Room - = Room +type IRoom + = IRoom { accountData : Dict String E.Value , ephemeral : List BlindEvent - , events : Hashdict Event + , events : Hashdict IEvent , roomId : String , timeline : Timeline } @@ -21,23 +21,24 @@ type Room {-| Add the data of a single event to the hashdict of events. -} -addEvent : Event -> Room -> Room -addEvent event (Room ({ events } as room)) = - Room { room | events = Hashdict.insert event events } +addEvent : IEvent -> IRoom -> IRoom +addEvent event (IRoom ({ events } as room)) = + IRoom { room | events = Hashdict.insert event events } {-| Add new events as the most recent events. -} addEvents : - { events : List Event + { events : List IEvent + , limited : Bool , nextBatch : String , prevBatch : String , stateDelta : Maybe StateManager } - -> Room - -> Room -addEvents ({ events } as data) (Room room) = - Room + -> IRoom + -> IRoom +addEvents ({ events } as data) (IRoom room) = + IRoom { room | events = List.foldl Hashdict.insert room.events events , timeline = Timeline.addNewEvents data room.timeline @@ -46,20 +47,20 @@ addEvents ({ events } as data) (Room room) = {-| Get an event by its id. -} -getEventById : String -> Room -> Maybe Event -getEventById eventId (Room room) = +getEventById : String -> IRoom -> Maybe IEvent +getEventById eventId (IRoom room) = Hashdict.get eventId room.events {-| Get the room's id. -} -roomId : Room -> String -roomId (Room room) = +roomId : IRoom -> String +roomId (IRoom room) = room.roomId {-| Get the most recent events. -} -mostRecentEvents : Room -> List Event -mostRecentEvents (Room room) = +mostRecentEvents : IRoom -> List IEvent +mostRecentEvents (IRoom room) = Timeline.mostRecentEvents room.timeline diff --git a/src/Internal/Values/StateManager.elm b/src/Internal/Values/StateManager.elm index 913caaa..d496613 100644 --- a/src/Internal/Values/StateManager.elm +++ b/src/Internal/Values/StateManager.elm @@ -1,14 +1,14 @@ module Internal.Values.StateManager exposing (..) import Dict exposing (Dict) -import Internal.Values.Event as Event exposing (Event) +import Internal.Values.Event as Event exposing (IEvent) type alias StateManager = - Dict ( String, String ) Event + Dict ( String, String ) IEvent -addEvent : Event -> StateManager -> StateManager +addEvent : IEvent -> StateManager -> StateManager addEvent event oldManager = case Event.stateKey event of Just key -> @@ -18,7 +18,7 @@ addEvent event oldManager = oldManager -getStateEvent : String -> String -> StateManager -> Maybe Event +getStateEvent : String -> String -> StateManager -> Maybe IEvent getStateEvent eventType stateKey = Dict.get ( eventType, stateKey ) @@ -28,13 +28,13 @@ updateRoomStateWith = Dict.union -fromEvent : Event -> StateManager +fromEvent : IEvent -> StateManager fromEvent event = Dict.empty |> addEvent event -fromEventList : List Event -> StateManager +fromEventList : List IEvent -> StateManager fromEventList = List.foldl addEvent Dict.empty diff --git a/src/Internal/Values/Timeline.elm b/src/Internal/Values/Timeline.elm index 05a5b68..ad044ca 100644 --- a/src/Internal/Values/Timeline.elm +++ b/src/Internal/Values/Timeline.elm @@ -5,7 +5,7 @@ module Internal.Values.Timeline exposing (..) import Internal.Config.Leaking as Leaking import Internal.Tools.Fold as Fold -import Internal.Values.Event as Event exposing (Event) +import Internal.Values.Event as Event exposing (IEvent) import Internal.Values.StateManager as StateManager exposing (StateManager) @@ -13,7 +13,7 @@ type Timeline = Timeline { prevBatch : String , nextBatch : String - , events : List Event + , events : List IEvent , stateAtStart : StateManager , previous : BeforeTimeline } @@ -28,16 +28,17 @@ type BeforeTimeline {-| Add a new batch of events to the front of the timeline. -} addNewEvents : - { events : List Event + { events : List IEvent + , limited : Bool , nextBatch : String , prevBatch : String , stateDelta : Maybe StateManager } -> Timeline -> Timeline -addNewEvents { events, nextBatch, prevBatch, stateDelta } (Timeline t) = +addNewEvents { events, limited, nextBatch, prevBatch, stateDelta } (Timeline t) = Timeline - (if prevBatch == t.nextBatch then + (if prevBatch == t.nextBatch || not limited then { t | events = t.events ++ events , nextBatch = nextBatch @@ -63,7 +64,7 @@ addNewEvents { events, nextBatch, prevBatch, stateDelta } (Timeline t) = {-| Create a new timeline. -} newFromEvents : - { events : List Event + { events : List IEvent , nextBatch : String , prevBatch : Maybe String , stateDelta : Maybe StateManager @@ -89,7 +90,7 @@ newFromEvents { events, nextBatch, prevBatch, stateDelta } = {-| Insert events starting from a known batch token. -} insertEvents : - { events : List Event + { events : List IEvent , nextBatch : String , prevBatch : String , stateDelta : Maybe StateManager @@ -157,7 +158,7 @@ localSize = {-| Get a list of the most recent events recorded. -} -mostRecentEvents : Timeline -> List Event +mostRecentEvents : Timeline -> List IEvent mostRecentEvents (Timeline t) = t.events @@ -180,7 +181,7 @@ mostRecentState (Timeline t) = {-| Get the timeline's room state at any given event. The function returns `Nothing` if the event is not found in the timeline. -} -stateAtEvent : Event -> Timeline -> Maybe StateManager +stateAtEvent : IEvent -> Timeline -> Maybe StateManager stateAtEvent event (Timeline t) = if t.events