elm-matrix-sdk-alpha/src/Internal/Vault.elm

215 lines
7.5 KiB
Elm

module Internal.Vault exposing (..)
{-| The Vault type is the keychain that stores all tokens, values,
numbers and other types that need to be remembered.
This file combines the internal functions with the API endpoints to create a fully functional Vault keychain.
-}
import Dict
import Internal.Api.Credentials as Credentials exposing (Credentials)
import Internal.Api.Task as Api
import Internal.Api.VaultUpdate exposing (VaultUpdate(..))
import Internal.Event as Event
import Internal.Room as Room
import Internal.Tools.Exceptions as X
import Internal.Values.Event as IEvent
import Internal.Values.Room as IRoom
import Internal.Values.StateManager as StateManager
import Internal.Values.Vault as Internal
import Task exposing (Task)
{-| You can consider the `Vault` type as a large ring of keys,
and Elm will figure out which key to use.
If you pass the `Vault` into any function, then the library will look for
the right keys and tokens to get the right information.
-}
type Vault
= Vault
{ cred : Internal.IVault
, context : Credentials
}
{-| Get a Vault type based on an unknown access token.
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 : { baseUrl : String, accessToken : String } -> Vault
fromAccessToken { baseUrl, accessToken } =
Credentials.fromBaseUrl baseUrl
|> Credentials.addToken accessToken
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Vault
{-| Get a Vault type using a username and password.
-}
fromLoginVault : { username : String, password : String, baseUrl : String } -> Vault
fromLoginVault { username, password, baseUrl } =
Credentials.fromBaseUrl baseUrl
|> Credentials.addUsernameAndPassword
{ username = username
, password = password
}
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Vault
{-| Get a room based on its id.
-}
getRoomById : String -> Vault -> Maybe Room.Room
getRoomById roomId (Vault { cred, context }) =
Internal.getRoomById roomId cred
|> Maybe.map (Room.withCredentials context)
{-| Insert an internal room type into the credentials.
-}
insertInternalRoom : IRoom.IRoom -> Vault -> Vault
insertInternalRoom iroom (Vault data) =
Vault { data | cred = Internal.insertRoom iroom data.cred }
{-| Internal a full room type into the credentials.
-}
insertRoom : Room.Room -> Vault -> Vault
insertRoom =
Room.withoutCredentials >> insertInternalRoom
{-| Update the Vault type with new values
-}
updateWith : VaultUpdate -> Vault -> Vault
updateWith vaultUpdate ((Vault ({ cred, context } as data)) as credentials) =
case vaultUpdate of
MultipleUpdates updates ->
List.foldl updateWith credentials updates
GetEvent input output ->
case getRoomById input.roomId credentials of
Just room ->
output
|> Event.initFromGetEvent
|> Room.addInternalEvent
|> (|>) room
|> insertRoom
|> (|>) credentials
Nothing ->
credentials
-- TODO
InviteSent _ _ ->
credentials
JoinedMembersToRoom _ _ ->
credentials
-- TODO
MessageEventSent _ _ ->
credentials
-- TODO
RedactedEvent _ _ ->
credentials
-- TODO
StateEventSent _ _ ->
credentials
-- TODO
SyncUpdate input output ->
let
jRooms : List IRoom.IRoom
jRooms =
output.rooms
|> Maybe.map .join
|> Maybe.withDefault Dict.empty
|> Dict.toList
|> List.map
(\( roomId, jroom ) ->
case getRoomById roomId credentials of
-- Update existing room
Just room ->
case jroom.timeline of
Just timeline ->
room
|> Room.withoutCredentials
|> 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.withoutCredentials room
-- Add new room
Nothing ->
jroom
|> Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId }
)
in
cred
|> Internal.addSince output.nextBatch
|> List.foldl Internal.insertRoom
|> (|>) jRooms
|> (\x -> { cred = x, context = context })
|> Vault
UpdateAccessToken token ->
Vault { data | context = Credentials.addToken token context }
UpdateVersions versions ->
Vault { data | context = Credentials.addVersions versions context }
-- TODO: Save all info
LoggedInWithUsernameAndPassword _ output ->
Vault { data | context = Credentials.addToken output.accessToken context }
{-| Synchronize credentials
-}
sync : Vault -> Task X.Error VaultUpdate
sync (Vault { cred, context }) =
Api.sync
{ filter = Nothing
, fullState = Nothing
, setPresence = Nothing
, since = Internal.getSince cred
, timeout = Just 30
}
context
{-| Get a list of all synchronised rooms.
-}
rooms : Vault -> List Room.Room
rooms (Vault { cred, context }) =
cred
|> Internal.getRooms
|> List.map (Room.withCredentials context)