Refactor public types

pull/1/head
Bram van den Heuvel 2023-03-03 16:07:37 +01:00
parent caab0ae0bb
commit 9dec58b3d4
10 changed files with 317 additions and 284 deletions

73
src/Internal/Context.elm Normal file
View File

@ -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

View File

@ -9,6 +9,7 @@ This file combines the internal functions with the API endpoints to create a ful
import Dict import Dict
import Internal.Api.All as Api import Internal.Api.All as Api
import Internal.Context as Context exposing (Context)
import Internal.Event as Event import Internal.Event as Event
import Internal.Room as Room import Internal.Room as Room
import Internal.Tools.Exceptions as X 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 If you pass the `Credentials` into any function, then the library will look for
the right keys and tokens to get the right information. the right keys and tokens to get the right information.
-} -}
type alias Credentials = type Credentials
Internal.Credentials = Credentials
{ cred : Internal.ICredentials
, context : Context
}
{-| Get a Credentials type based on an unknown access token. {-| 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. when the access token expires, is revoked or something else happens.
-} -}
fromAccessToken : { homeserver : String, accessToken : String } -> Credentials fromAccessToken : { baseUrl : String, accessToken : String } -> Credentials
fromAccessToken = fromAccessToken { baseUrl, accessToken } =
Internal.fromAccessToken Context.fromBaseUrl baseUrl
|> Context.addToken accessToken
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Credentials
{-| Get a Credentials type using a username and password. {-| Get a Credentials type using a username and password.
-} -}
fromLoginCredentials : { username : String, password : String, homeserver : String } -> Credentials fromLoginCredentials : { username : String, password : String, baseUrl : String } -> Credentials
fromLoginCredentials = fromLoginCredentials { username, password, baseUrl } =
Internal.fromLoginCredentials Context.fromBaseUrl baseUrl
|> Context.addUsernameAndPassword
{ username = username
, password = password
}
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Credentials
{-| Get a room based on its id. {-| Get a room based on its id.
-} -}
getRoomById : String -> Credentials -> Maybe Room.Room getRoomById : String -> Credentials -> Maybe Room.Room
getRoomById roomId credentials = getRoomById roomId (Credentials { cred, context }) =
Internal.getRoomById roomId credentials Internal.getRoomById roomId cred
|> Maybe.map |> Maybe.map (Room.withContext context)
(Room.init
{ accessToken = Internal.getAccessTokenType credentials
, baseUrl = Internal.getBaseUrl credentials
, versions = Internal.getVersions credentials
}
)
{-| Insert an internal room type into the credentials. {-| Insert an internal room type into the credentials.
-} -}
insertInternalRoom : IRoom.Room -> Credentials -> Credentials insertInternalRoom : IRoom.IRoom -> Credentials -> Credentials
insertInternalRoom = insertInternalRoom iroom (Credentials data) =
Internal.insertRoom Credentials { data | cred = Internal.insertRoom iroom data.cred }
{-| Internal a full room type into the credentials. {-| Internal a full room type into the credentials.
-} -}
insertRoom : Room.Room -> Credentials -> Credentials insertRoom : Room.Room -> Credentials -> Credentials
insertRoom = insertRoom =
Room.internalValue >> insertInternalRoom Room.withoutContext >> insertInternalRoom
{-| Update the Credentials type with new values {-| Update the Credentials type with new values
-} -}
updateWith : Api.CredUpdate -> Credentials -> Credentials updateWith : Api.CredUpdate -> Credentials -> Credentials
updateWith credUpdate credentials = updateWith credUpdate ((Credentials ({ cred, context } as data)) as credentials) =
case credUpdate of case credUpdate of
Api.MultipleUpdates updates -> Api.MultipleUpdates updates ->
List.foldl updateWith credentials updates List.foldl updateWith credentials updates
@ -109,6 +120,7 @@ updateWith credUpdate credentials =
-- TODO -- TODO
Api.SyncUpdate input output -> Api.SyncUpdate input output ->
let let
jRooms : List IRoom.IRoom
jRooms = jRooms =
output.rooms output.rooms
|> Maybe.map .join |> Maybe.map .join
@ -119,68 +131,73 @@ updateWith credUpdate credentials =
case getRoomById roomId credentials of case getRoomById roomId credentials of
-- Update existing room -- Update existing room
Just room -> Just room ->
room case jroom.timeline of
|> Room.internalValue Just timeline ->
|> IRoom.addEvents room
{ events = |> Room.withoutContext
jroom.timeline |> IRoom.addEvents
|> Maybe.map .events { events =
|> Maybe.withDefault [] List.map
|> List.map (Event.initFromClientEventWithoutRoomId roomId) (Event.initFromClientEventWithoutRoomId roomId)
, nextBatch = output.nextBatch timeline.events
, prevBatch = , limited = timeline.limited
jroom.timeline , nextBatch = output.nextBatch
|> Maybe.andThen .prevBatch , prevBatch =
|> Maybe.withDefault (Maybe.withDefault "" input.since) timeline.prevBatch
, stateDelta = |> Maybe.withDefault
jroom.state (Maybe.withDefault "" input.since)
|> Maybe.map , stateDelta =
(.events jroom.state
>> List.map (Event.initFromClientEventWithoutRoomId roomId) |> Maybe.map
>> StateManager.fromEventList (.events
) >> List.map (Event.initFromClientEventWithoutRoomId roomId)
} >> StateManager.fromEventList
)
}
Nothing ->
Room.withoutContext room
-- Add new room -- Add new room
Nothing -> Nothing ->
Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId } jroom jroom
|> Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId }
) )
in 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 -> Api.UpdateAccessToken token ->
Internal.addAccessToken token credentials Credentials { data | context = Context.addToken token context }
Api.UpdateVersions versions -> Api.UpdateVersions versions ->
Internal.addVersions versions credentials Credentials { data | context = Context.addVersions versions context }
{-| Synchronize credentials {-| Synchronize credentials
-} -}
sync : Credentials -> Task X.Error Api.CredUpdate sync : Credentials -> Task X.Error Api.CredUpdate
sync credentials = sync (Credentials { cred, context }) =
Api.syncCredentials Api.syncCredentials
{ accessToken = Internal.getAccessTokenType credentials { accessToken = Context.accessToken context
, baseUrl = Internal.getBaseUrl credentials , baseUrl = Context.baseUrl context
, filter = Nothing , filter = Nothing
, fullState = Nothing , fullState = Nothing
, setPresence = Nothing , setPresence = Nothing
, since = Internal.getSince credentials , since = Internal.getSince cred
, timeout = Just 30 , timeout = Just 30
, versions = Internal.getVersions credentials , versions = Context.versions context
} }
{-| Get a list of all synchronised rooms. {-| Get a list of all synchronised rooms.
-} -}
rooms : Credentials -> List Room.Room rooms : Credentials -> List Room.Room
rooms credentials = rooms (Credentials { cred, context }) =
credentials cred
|> Internal.getRooms |> Internal.getRooms
|> ({ accessToken = Internal.getAccessTokenType credentials |> List.map (Room.withContext context)
, baseUrl = Internal.getBaseUrl credentials
, versions = Internal.getVersions credentials
}
|> Room.init
|> List.map
)

View File

@ -9,9 +9,8 @@ resend other events or forward them elsewhere.
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.PreApi.Objects.Versions as V
import Internal.Api.Sync.V2.SpecObjects as SyncSO 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.Tools.Timestamp exposing (Timestamp)
import Internal.Values.Event as Internal import Internal.Values.Event as Internal
import Json.Encode as E import Json.Encode as E
@ -21,30 +20,26 @@ import Json.Encode as E
-} -}
type Event type Event
= Event = Event
{ event : Internal.Event { event : Internal.IEvent
, accessToken : AccessToken , context : Context
, baseUrl : String
, versions : Maybe V.Versions
} }
{-| Using the credentials' background information and an internal event type, {-| Using the credentials' background information and an internal event type,
create an interactive event type. create an interactive event type.
-} -}
init : { accessToken : AccessToken, baseUrl : String, versions : Maybe V.Versions } -> Internal.Event -> Event withContext : Context -> Internal.IEvent -> Event
init { accessToken, baseUrl, versions } event = withContext context event =
Event Event
{ event = event { event = event
, accessToken = accessToken , context = context
, baseUrl = baseUrl
, versions = versions
} }
{-| 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.
-} -}
initFromGetEvent : GetEvent.EventOutput -> Internal.Event initFromGetEvent : GetEvent.EventOutput -> Internal.IEvent
initFromGetEvent output = initFromGetEvent output =
Internal.init Internal.init
{ content = output.content { content = output.content
@ -70,7 +65,7 @@ initFromGetEvent output =
{-| 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.
-} -}
initFromClientEventWithoutRoomId : String -> SyncSO.ClientEventWithoutRoomId -> Internal.Event initFromClientEventWithoutRoomId : String -> SyncSO.ClientEventWithoutRoomId -> Internal.IEvent
initFromClientEventWithoutRoomId rId output = initFromClientEventWithoutRoomId rId output =
Internal.init Internal.init
{ content = output.content { content = output.content
@ -95,8 +90,8 @@ initFromClientEventWithoutRoomId rId output =
{-| Get the internal event type that is hidden in the interactive event type. {-| Get the internal event type that is hidden in the interactive event type.
-} -}
internalValue : Event -> Internal.Event withoutContext : Event -> Internal.IEvent
internalValue (Event { event }) = withoutContext (Event { event }) =
event event
@ -106,42 +101,42 @@ internalValue (Event { event }) =
content : Event -> E.Value content : Event -> E.Value
content = content =
internalValue >> Internal.content withoutContext >> Internal.content
eventId : Event -> String eventId : Event -> String
eventId = eventId =
internalValue >> Internal.eventId withoutContext >> Internal.eventId
originServerTs : Event -> Timestamp originServerTs : Event -> Timestamp
originServerTs = originServerTs =
internalValue >> Internal.originServerTs withoutContext >> Internal.originServerTs
roomId : Event -> String roomId : Event -> String
roomId = roomId =
internalValue >> Internal.roomId withoutContext >> Internal.roomId
sender : Event -> String sender : Event -> String
sender = sender =
internalValue >> Internal.sender withoutContext >> Internal.sender
stateKey : Event -> Maybe String stateKey : Event -> Maybe String
stateKey = stateKey =
internalValue >> Internal.stateKey withoutContext >> Internal.stateKey
contentType : Event -> String contentType : Event -> String
contentType = contentType =
internalValue >> Internal.contentType withoutContext >> Internal.contentType
age : Event -> Maybe Int age : Event -> Maybe Int
age = age =
internalValue >> Internal.age withoutContext >> Internal.age
redactedBecause : Event -> Maybe Event redactedBecause : Event -> Maybe Event
@ -156,4 +151,4 @@ redactedBecause (Event data) =
transactionId : Event -> Maybe String transactionId : Event -> Maybe String
transactionId = transactionId =
internalValue >> Internal.transactionId withoutContext >> Internal.transactionId

View File

@ -5,12 +5,11 @@ module Internal.Room exposing (..)
import Dict import Dict
import Internal.Api.All as Api import Internal.Api.All as Api
import Internal.Api.PreApi.Objects.Versions as V
import Internal.Api.Sync.V2.SpecObjects as Sync import Internal.Api.Sync.V2.SpecObjects as Sync
import Internal.Context as Context exposing (Context)
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.LoginValues exposing (AccessToken)
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
@ -29,18 +28,16 @@ to it.
-} -}
type Room type Room
= Room = Room
{ room : Internal.Room { room : Internal.IRoom
, accessToken : AccessToken , context : Context
, baseUrl : String
, versions : Maybe V.Versions
} }
{-| Create a new object from a joined room. {-| 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 = initFromJoinedRoom data jroom =
Internal.Room Internal.IRoom
{ accountData = { accountData =
jroom.accountData jroom.accountData
|> Maybe.map .events |> Maybe.map .events
@ -90,7 +87,7 @@ initFromJoinedRoom data jroom =
{-| Adds an internal event to the `Room`. An internal event is a custom event {-| Adds an internal event to the `Room`. An internal event is a custom event
that has been generated by the client. that has been generated by the client.
-} -}
addInternalEvent : IEvent.Event -> Room -> Room addInternalEvent : IEvent.IEvent -> Room -> Room
addInternalEvent ievent (Room ({ room } as data)) = addInternalEvent ievent (Room ({ room } as data)) =
Room { data | room = Internal.addEvent ievent room } Room { data | room = Internal.addEvent ievent room }
@ -100,61 +97,53 @@ addInternalEvent ievent (Room ({ room } as data)) =
-} -}
addEvent : Event -> Room -> Room addEvent : Event -> Room -> Room
addEvent = addEvent =
Event.internalValue >> addInternalEvent Event.withoutContext >> addInternalEvent
{-| Creates a new `Room` object with the given parameters. {-| Creates a new `Room` object with the given parameters.
-} -}
init : { accessToken : AccessToken, baseUrl : String, versions : Maybe V.Versions } -> Internal.Room -> Room withContext : Context -> Internal.IRoom -> Room
init { accessToken, baseUrl, versions } room = withContext context room =
Room Room
{ accessToken = accessToken { context = context
, baseUrl = baseUrl
, room = room , 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 withoutContext : Room -> Internal.IRoom
internalValue (Room { room }) = withoutContext (Room { room }) =
room room
{-| Get the most recent events. {-| Get the most recent events.
-} -}
mostRecentEvents : Room -> List Event mostRecentEvents : Room -> List Event
mostRecentEvents (Room data) = mostRecentEvents (Room { context, room }) =
data.room room
|> Internal.mostRecentEvents |> Internal.mostRecentEvents
|> List.map |> List.map (Event.withContext context)
(Event.init
{ accessToken = data.accessToken
, baseUrl = data.baseUrl
, versions = data.versions
}
)
{-| Retrieves the ID of the Matrix room associated with the given `Room`. {-| Retrieves the ID of the Matrix room associated with the given `Room`.
-} -}
roomId : Room -> String roomId : Room -> String
roomId = roomId =
internalValue >> Internal.roomId withoutContext >> Internal.roomId
{-| Sends a new event to the Matrix room associated with the given `Room`. {-| 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 -> { 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 Api.sendMessageEvent
{ accessToken = accessToken { accessToken = Context.accessToken context
, baseUrl = baseUrl , baseUrl = Context.baseUrl context
, content = content , content = content
, eventType = eventType , eventType = eventType
, roomId = Internal.roomId room , roomId = Internal.roomId room
, versions = versions , versions = Context.versions context
, extraTransactionNoise = "content-value:<object>" , extraTransactionNoise = "content-value:<object>"
} }
@ -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`. {-| Sends a new text message to the Matrix room associated with the given `Room`.
-} -}
sendMessage : Room -> String -> Task X.Error Api.CredUpdate sendMessage : Room -> String -> Task X.Error Api.CredUpdate
sendMessage (Room { room, accessToken, baseUrl, versions }) text = sendMessage (Room { context, room }) text =
Api.sendMessageEvent Api.sendMessageEvent
{ accessToken = accessToken { accessToken = Context.accessToken context
, baseUrl = baseUrl , baseUrl = Context.baseUrl context
, content = , content =
E.object E.object
[ ( "msgtype", E.string "m.text" ) [ ( "msgtype", E.string "m.text" )
@ -173,6 +162,6 @@ sendMessage (Room { room, accessToken, baseUrl, versions }) text =
] ]
, eventType = "m.room.message" , eventType = "m.room.message"
, roomId = Internal.roomId room , roomId = Internal.roomId room
, versions = versions , versions = Context.versions context
, extraTransactionNoise = "literal-message:" ++ text , extraTransactionNoise = "literal-message:" ++ text
} }

View File

@ -54,3 +54,28 @@ addToken s t =
, password = password , password = password
, token = Just s , 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
}

View File

@ -4,129 +4,61 @@ module Internal.Values.Credentials exposing (..)
It handles all communication with the homeserver. 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.Hashdict as Hashdict exposing (Hashdict)
import Internal.Tools.LoginValues as Login exposing (AccessToken(..)) import Internal.Values.Room as Room exposing (IRoom)
import Internal.Values.Room as Room exposing (Room)
type Credentials type ICredentials
= Credentials = ICredentials
{ access : AccessToken { rooms : Hashdict IRoom
, baseUrl : String
, rooms : Hashdict Room
, since : Maybe String , 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. {-| Add a new `since` token to sync from.
-} -}
addSince : String -> Credentials -> Credentials addSince : String -> ICredentials -> ICredentials
addSince since (Credentials data) = addSince since (ICredentials data) =
Credentials { data | since = Just since } ICredentials { 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 } }
{-| Get a room from the Credentials type by the room's id. {-| Get a room from the Credentials type by the room's id.
-} -}
getRoomById : String -> Credentials -> Maybe Room getRoomById : String -> ICredentials -> Maybe IRoom
getRoomById roomId (Credentials cred) = getRoomById roomId (ICredentials cred) =
Hashdict.get roomId cred.rooms 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. {-| 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. This function can hence also be used as an update function for rooms.
-} -}
insertRoom : Room -> Credentials -> Credentials insertRoom : IRoom -> ICredentials -> ICredentials
insertRoom room (Credentials cred) = insertRoom room (ICredentials cred) =
Credentials ICredentials
{ cred | rooms = Hashdict.insert room cred.rooms } { cred | rooms = Hashdict.insert room cred.rooms }
{-| Get a list of all synchronised rooms.
-}
getRooms : Credentials -> List Room
getRooms (Credentials { rooms }) =
Hashdict.values rooms

View File

@ -4,8 +4,8 @@ import Internal.Tools.Timestamp exposing (Timestamp)
import Json.Encode as E import Json.Encode as E
type Event type IEvent
= Event = IEvent
{ content : E.Value { content : E.Value
, eventId : String , eventId : String
, originServerTs : Timestamp , originServerTs : Timestamp
@ -17,7 +17,7 @@ type Event
Maybe Maybe
{ age : Maybe Int { age : Maybe Int
, prevContent : Maybe E.Value , prevContent : Maybe E.Value
, redactedBecause : Maybe Event , redactedBecause : Maybe IEvent
, transactionId : Maybe String , transactionId : Maybe String
} }
} }
@ -35,68 +35,68 @@ init :
Maybe Maybe
{ age : Maybe Int { age : Maybe Int
, prevContent : Maybe E.Value , prevContent : Maybe E.Value
, redactedBecause : Maybe Event , redactedBecause : Maybe IEvent
, transactionId : Maybe String , transactionId : Maybe String
} }
} }
-> Event -> IEvent
init = init =
Event IEvent
{- GETTER FUNCTIONS -} {- GETTER FUNCTIONS -}
content : Event -> E.Value content : IEvent -> E.Value
content (Event e) = content (IEvent e) =
e.content e.content
eventId : Event -> String eventId : IEvent -> String
eventId (Event e) = eventId (IEvent e) =
e.eventId e.eventId
originServerTs : Event -> Timestamp originServerTs : IEvent -> Timestamp
originServerTs (Event e) = originServerTs (IEvent e) =
e.originServerTs e.originServerTs
roomId : Event -> String roomId : IEvent -> String
roomId (Event e) = roomId (IEvent e) =
e.roomId e.roomId
sender : Event -> String sender : IEvent -> String
sender (Event e) = sender (IEvent e) =
e.sender e.sender
stateKey : Event -> Maybe String stateKey : IEvent -> Maybe String
stateKey (Event e) = stateKey (IEvent e) =
e.stateKey e.stateKey
contentType : Event -> String contentType : IEvent -> String
contentType (Event e) = contentType (IEvent e) =
e.contentType e.contentType
age : Event -> Maybe Int age : IEvent -> Maybe Int
age (Event e) = age (IEvent e) =
e.unsigned e.unsigned
|> Maybe.andThen .age |> Maybe.andThen .age
redactedBecause : Event -> Maybe Event redactedBecause : IEvent -> Maybe IEvent
redactedBecause (Event e) = redactedBecause (IEvent e) =
e.unsigned e.unsigned
|> Maybe.andThen .redactedBecause |> Maybe.andThen .redactedBecause
transactionId : Event -> Maybe String transactionId : IEvent -> Maybe String
transactionId (Event e) = transactionId (IEvent e) =
e.unsigned e.unsigned
|> Maybe.andThen .transactionId |> Maybe.andThen .transactionId

View File

@ -3,17 +3,17 @@ module Internal.Values.Room exposing (..)
import Dict exposing (Dict) import Dict exposing (Dict)
import Internal.Tools.Hashdict as Hashdict exposing (Hashdict) import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
import Internal.Tools.SpecEnums exposing (SessionDescriptionType(..)) 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.StateManager exposing (StateManager)
import Internal.Values.Timeline as Timeline exposing (Timeline) import Internal.Values.Timeline as Timeline exposing (Timeline)
import Json.Encode as E import Json.Encode as E
type Room type IRoom
= Room = IRoom
{ accountData : Dict String E.Value { accountData : Dict String E.Value
, ephemeral : List BlindEvent , ephemeral : List BlindEvent
, events : Hashdict Event , events : Hashdict IEvent
, roomId : String , roomId : String
, timeline : Timeline , timeline : Timeline
} }
@ -21,23 +21,24 @@ type Room
{-| Add the data of a single event to the hashdict of events. {-| Add the data of a single event to the hashdict of events.
-} -}
addEvent : Event -> Room -> Room addEvent : IEvent -> IRoom -> IRoom
addEvent event (Room ({ events } as room)) = addEvent event (IRoom ({ events } as room)) =
Room { room | events = Hashdict.insert event events } IRoom { room | events = Hashdict.insert event events }
{-| Add new events as the most recent events. {-| Add new events as the most recent events.
-} -}
addEvents : addEvents :
{ events : List Event { events : List IEvent
, limited : Bool
, nextBatch : String , nextBatch : String
, prevBatch : String , prevBatch : String
, stateDelta : Maybe StateManager , stateDelta : Maybe StateManager
} }
-> Room -> IRoom
-> Room -> IRoom
addEvents ({ events } as data) (Room room) = addEvents ({ events } as data) (IRoom room) =
Room IRoom
{ room { room
| events = List.foldl Hashdict.insert room.events events | events = List.foldl Hashdict.insert room.events events
, timeline = Timeline.addNewEvents data room.timeline , timeline = Timeline.addNewEvents data room.timeline
@ -46,20 +47,20 @@ addEvents ({ events } as data) (Room room) =
{-| Get an event by its id. {-| Get an event by its id.
-} -}
getEventById : String -> Room -> Maybe Event getEventById : String -> IRoom -> Maybe IEvent
getEventById eventId (Room room) = getEventById eventId (IRoom room) =
Hashdict.get eventId room.events Hashdict.get eventId room.events
{-| Get the room's id. {-| Get the room's id.
-} -}
roomId : Room -> String roomId : IRoom -> String
roomId (Room room) = roomId (IRoom room) =
room.roomId room.roomId
{-| Get the most recent events. {-| Get the most recent events.
-} -}
mostRecentEvents : Room -> List Event mostRecentEvents : IRoom -> List IEvent
mostRecentEvents (Room room) = mostRecentEvents (IRoom room) =
Timeline.mostRecentEvents room.timeline Timeline.mostRecentEvents room.timeline

View File

@ -1,14 +1,14 @@
module Internal.Values.StateManager exposing (..) module Internal.Values.StateManager exposing (..)
import Dict exposing (Dict) import Dict exposing (Dict)
import Internal.Values.Event as Event exposing (Event) import Internal.Values.Event as Event exposing (IEvent)
type alias StateManager = type alias StateManager =
Dict ( String, String ) Event Dict ( String, String ) IEvent
addEvent : Event -> StateManager -> StateManager addEvent : IEvent -> StateManager -> StateManager
addEvent event oldManager = addEvent event oldManager =
case Event.stateKey event of case Event.stateKey event of
Just key -> Just key ->
@ -18,7 +18,7 @@ addEvent event oldManager =
oldManager oldManager
getStateEvent : String -> String -> StateManager -> Maybe Event getStateEvent : String -> String -> StateManager -> Maybe IEvent
getStateEvent eventType stateKey = getStateEvent eventType stateKey =
Dict.get ( eventType, stateKey ) Dict.get ( eventType, stateKey )
@ -28,13 +28,13 @@ updateRoomStateWith =
Dict.union Dict.union
fromEvent : Event -> StateManager fromEvent : IEvent -> StateManager
fromEvent event = fromEvent event =
Dict.empty Dict.empty
|> addEvent event |> addEvent event
fromEventList : List Event -> StateManager fromEventList : List IEvent -> StateManager
fromEventList = fromEventList =
List.foldl addEvent Dict.empty List.foldl addEvent Dict.empty

View File

@ -5,7 +5,7 @@ module Internal.Values.Timeline exposing (..)
import Internal.Config.Leaking as Leaking import Internal.Config.Leaking as Leaking
import Internal.Tools.Fold as Fold 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) import Internal.Values.StateManager as StateManager exposing (StateManager)
@ -13,7 +13,7 @@ type Timeline
= Timeline = Timeline
{ prevBatch : String { prevBatch : String
, nextBatch : String , nextBatch : String
, events : List Event , events : List IEvent
, stateAtStart : StateManager , stateAtStart : StateManager
, previous : BeforeTimeline , previous : BeforeTimeline
} }
@ -28,16 +28,17 @@ type BeforeTimeline
{-| Add a new batch of events to the front of the timeline. {-| Add a new batch of events to the front of the timeline.
-} -}
addNewEvents : addNewEvents :
{ events : List Event { events : List IEvent
, limited : Bool
, nextBatch : String , nextBatch : String
, prevBatch : String , prevBatch : String
, stateDelta : Maybe StateManager , stateDelta : Maybe StateManager
} }
-> Timeline -> Timeline
-> Timeline -> Timeline
addNewEvents { events, nextBatch, prevBatch, stateDelta } (Timeline t) = addNewEvents { events, limited, nextBatch, prevBatch, stateDelta } (Timeline t) =
Timeline Timeline
(if prevBatch == t.nextBatch then (if prevBatch == t.nextBatch || not limited then
{ t { t
| events = t.events ++ events | events = t.events ++ events
, nextBatch = nextBatch , nextBatch = nextBatch
@ -63,7 +64,7 @@ addNewEvents { events, nextBatch, prevBatch, stateDelta } (Timeline t) =
{-| Create a new timeline. {-| Create a new timeline.
-} -}
newFromEvents : newFromEvents :
{ events : List Event { events : List IEvent
, nextBatch : String , nextBatch : String
, prevBatch : Maybe String , prevBatch : Maybe String
, stateDelta : Maybe StateManager , stateDelta : Maybe StateManager
@ -89,7 +90,7 @@ newFromEvents { events, nextBatch, prevBatch, stateDelta } =
{-| Insert events starting from a known batch token. {-| Insert events starting from a known batch token.
-} -}
insertEvents : insertEvents :
{ events : List Event { events : List IEvent
, nextBatch : String , nextBatch : String
, prevBatch : String , prevBatch : String
, stateDelta : Maybe StateManager , stateDelta : Maybe StateManager
@ -157,7 +158,7 @@ localSize =
{-| Get a list of the most recent events recorded. {-| Get a list of the most recent events recorded.
-} -}
mostRecentEvents : Timeline -> List Event mostRecentEvents : Timeline -> List IEvent
mostRecentEvents (Timeline t) = mostRecentEvents (Timeline t) =
t.events 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. {-| 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) = stateAtEvent event (Timeline t) =
if if
t.events t.events