Rename Elm types

Credentials -> Vault

Context (upper level) -> Credentials

Context (lower level) remains called Context
pull/1/head
Bram van den Heuvel 2023-03-13 13:50:41 +01:00
parent d3637cf45f
commit e62b6a09c4
8 changed files with 354 additions and 343 deletions

View File

@ -1,4 +1,5 @@
module Internal.Api.Chain exposing (..)
{-| This module aims to simplify chaining several API tasks together.
Chaining tasks together is usually done through the `Task` submodule of `elm/core`,
@ -18,23 +19,29 @@ The model is like a snake: _____
/-|------------ | ------- | ------------- | -------- | |\/\/
< | accessToken | baseUrl | transactionId | API call | |------< Final API call
\-|------------ | ------- | ------------- | -------- | |/\/\
------/
(You're not allowed to judge my ASCII art skills unless you submit a PR with a
\-----/
(You're not allowed to judge my ASCII art skills unless you submit a PR with a
superior ASCII snake model.)
Every task will add another value to an extensible record, which can be used
by later tasks in the chain. Additionally, every subtask can leave a `CredUpdate`
type as a message to the Credentials to update certain information.
-}
import Internal.Tools.Exceptions as X
import Internal.Api.Context as Context exposing (Context)
import Internal.Tools.Exceptions as X
import Task exposing (Task)
type alias TaskChain u a b =
(Context a -> Task X.Error (TaskChainPiece u a b))
type alias IdemChain u a = TaskChain u a a
type alias TaskChain u a b =
Context a -> Task X.Error (TaskChainPiece u a b)
type alias IdemChain u a =
TaskChain u a a
type TaskChainPiece u a b
= TaskChainPiece
@ -42,44 +49,47 @@ type TaskChainPiece u a b
, messages : List u
}
{-| Chain two tasks together. The second task will only run if the first one succeeds.
-}
andThen : TaskChain u b c -> TaskChain u a b -> TaskChain u a c
andThen f2 f1 =
(\context ->
\context ->
f1 context
|> Task.andThen
(\(TaskChainPiece old) ->
context
|> old.contextChange
|> f2
|> Task.map
(\(TaskChainPiece new) ->
TaskChainPiece
{ contextChange = old.contextChange >> new.contextChange
, messages = List.append old.messages new.messages
}
)
)
)
|> Task.andThen
(\(TaskChainPiece old) ->
context
|> old.contextChange
|> f2
|> Task.map
(\(TaskChainPiece new) ->
TaskChainPiece
{ contextChange = old.contextChange >> new.contextChange
, messages = List.append old.messages new.messages
}
)
)
{-| Optionally run a task that may provide additional information.
{-| Optionally run a task that may provide additional information.
If the provided chain fails, it will be ignored. This way, the chain can be tasked
without needlessly breaking the whole chain if anything breaks in here.
You cannot use this function to execute a task chain that adds or removes context.
-}
maybe : IdemChain u a -> IdemChain u a
maybe f =
{ contextChange = identity
, messages = []
}
|> TaskChainPiece
|> Task.succeed
|> always
|> Task.onError
|> (>>) f
{ contextChange = identity
, messages = []
}
|> TaskChainPiece
|> Task.succeed
|> always
|> Task.onError
|> (>>) f
{-| If the TaskChain fails, run this task otherwise.
-}
@ -87,30 +97,33 @@ otherwise : TaskChain u a b -> TaskChain u a b -> TaskChain u a b
otherwise f2 f1 context =
Task.onError (always <| f2 context) (f1 context)
{-| Once all the pieces of the chain have been assembled, you can turn it into a task.
The compiler will fail if the chain is missing a vital piece of information.
-}
toTask : TaskChain u {} b -> Task X.Error (List u)
toTask f1 =
Context.init
|> f1
|> Task.map
(\(TaskChainPiece data) ->
data.messages
)
|> f1
|> Task.map
(\(TaskChainPiece data) ->
data.messages
)
{-| If the TaskChain fails, this function will get it to retry.
When set to 1 or lower, the task will only try once.
-}
tryNTimes : Int -> TaskChain u a b -> TaskChain u a b
tryNTimes n f context =
if n <= 1 then
f context
else
(\_ -> tryNTimes (n - 1) f context)
|> Task.onError
|> (|>) (f context)
|> Task.onError
|> (|>) (f context)

View File

@ -1,7 +1,5 @@
module Internal.Api.CredUpdate exposing (..)
import Hash
import Html exposing (input)
import Internal.Api.Chain as Chain exposing (IdemChain, TaskChain)
import Internal.Api.Context as Context exposing (VB, VBA, VBAT)
import Internal.Api.GetEvent.Main as GetEvent

View File

@ -1,73 +0,0 @@
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.Versions.V1.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

@ -1,216 +1,73 @@
module Internal.Credentials exposing (..)
{-| The Credentials type is the keychain that stores all tokens, values,
numbers and other types that need to be remembered.
{-| The `Credentials` type serves as an extra layer between the internal Room/Event types
and the types that the user may deal with directly.
This file combines the internal functions with the API endpoints to create a fully functional Credentials keychain.
Since pointers cannot point to values that the `Vault` type has,
the `Vault` type passes information down in the form of a `Credentials` type.
-}
import Dict
import Internal.Api.Task as Api
import Internal.Api.CredUpdate exposing (CredUpdate(..))
import Internal.Context as Context exposing (Context)
import Internal.Event as Event
import Internal.Room as Room
import Internal.Tools.Exceptions as X
import Internal.Values.Credentials as Internal
import Internal.Values.Event as IEvent
import Internal.Values.Room as IRoom
import Internal.Values.StateManager as StateManager
import Task exposing (Task)
import Internal.Api.Versions.V1.Versions as V
import Internal.Tools.LoginValues as Login exposing (AccessToken(..))
{-| You can consider the `Credentials` type as a large ring of keys,
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 Credentials
= Credentials
{ cred : Internal.ICredentials
, context : Context
{ access : AccessToken
, homeserver : String
, vs : Maybe V.Versions
}
{-| Get a Credentials 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.
{-| Retrieves the access token from a given `Credentials` value.
-}
fromAccessToken : { baseUrl : String, accessToken : String } -> Credentials
fromAccessToken { baseUrl, accessToken } =
Context.fromBaseUrl baseUrl
|> Context.addToken accessToken
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Credentials
accessToken : Credentials -> AccessToken
accessToken (Credentials { access }) =
access
{-| Get a Credentials type using a username and password.
{-| Add a new access token to the `Credentials` type.
-}
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
addToken : String -> Credentials -> Credentials
addToken token (Credentials ({ access } as data)) =
Credentials { data | access = Login.addToken token access }
{-| Get a room based on its id.
{-| Add a username and password to the `Credentials` type.
-}
getRoomById : String -> Credentials -> Maybe Room.Room
getRoomById roomId (Credentials { cred, context }) =
Internal.getRoomById roomId cred
|> Maybe.map (Room.withContext context)
addUsernameAndPassword : { username : String, password : String } -> Credentials -> Credentials
addUsernameAndPassword uap (Credentials ({ access } as data)) =
Credentials { data | access = Login.addUsernameAndPassword uap access }
{-| Insert an internal room type into the credentials.
{-| Add known spec versions to the `Credentials` type.
-}
insertInternalRoom : IRoom.IRoom -> Credentials -> Credentials
insertInternalRoom iroom (Credentials data) =
Credentials { data | cred = Internal.insertRoom iroom data.cred }
addVersions : V.Versions -> Credentials -> Credentials
addVersions vs (Credentials data) =
Credentials { data | vs = Just vs }
{-| Internal a full room type into the credentials.
{-| Retrieves the base url from a given `Credentials` value.
-}
insertRoom : Room.Room -> Credentials -> Credentials
insertRoom =
Room.withoutContext >> insertInternalRoom
baseUrl : Credentials -> String
baseUrl (Credentials { homeserver }) =
homeserver
{-| Update the Credentials type with new values
{-| Creates a `Credentials` value from a base URL.
-}
updateWith : CredUpdate -> Credentials -> Credentials
updateWith credUpdate ((Credentials ({ cred, context } as data)) as credentials) =
case credUpdate 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.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 ->
jroom
|> Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId }
)
in
cred
|> Internal.addSince output.nextBatch
|> List.foldl Internal.insertRoom
|> (|>) jRooms
|> (\x -> { cred = x, context = context })
|> Credentials
UpdateAccessToken token ->
Credentials { data | context = Context.addToken token context }
UpdateVersions versions ->
Credentials { data | context = Context.addVersions versions context }
-- TODO: Save all info
LoggedInWithUsernameAndPassword _ output ->
Credentials { data | context = Context.addToken output.accessToken context }
{-| Synchronize credentials
-}
sync : Credentials -> Task X.Error CredUpdate
sync (Credentials { cred, context }) =
Api.sync
{ accessToken = Context.accessToken context
, baseUrl = Context.baseUrl context
, filter = Nothing
, fullState = Nothing
, setPresence = Nothing
, since = Internal.getSince cred
, timeout = Just 30
, versions = Context.versions context
fromBaseUrl : String -> Credentials
fromBaseUrl url =
Credentials
{ access = NoAccess
, homeserver = url
, vs = Nothing
}
{-| Get a list of all synchronised rooms.
{-| Retrieves the spec versions from a given `Credentials` value.
-}
rooms : Credentials -> List Room.Room
rooms (Credentials { cred, context }) =
cred
|> Internal.getRooms
|> List.map (Room.withContext context)
versions : Credentials -> Maybe V.Versions
versions (Credentials { vs }) =
vs

View File

@ -10,7 +10,7 @@ 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.Sync.V2.SpecObjects as SyncSO
import Internal.Context exposing (Context)
import Internal.Credentials exposing (Credentials)
import Internal.Tools.Timestamp exposing (Timestamp)
import Internal.Values.Event as Internal
import Json.Encode as E
@ -21,15 +21,15 @@ import Json.Encode as E
type Event
= Event
{ event : Internal.IEvent
, context : Context
, context : Credentials
}
{-| Using the credentials' background information and an internal event type,
create an interactive event type.
-}
withContext : Context -> Internal.IEvent -> Event
withContext context event =
withCredentials : Credentials -> Internal.IEvent -> Event
withCredentials context event =
Event
{ event = event
, context = context
@ -90,8 +90,8 @@ initFromClientEventWithoutRoomId rId output =
{-| Get the internal event type that is hidden in the interactive event type.
-}
withoutContext : Event -> Internal.IEvent
withoutContext (Event { event }) =
withoutCredentials : Event -> Internal.IEvent
withoutCredentials (Event { event }) =
event
@ -101,42 +101,42 @@ withoutContext (Event { event }) =
content : Event -> E.Value
content =
withoutContext >> Internal.content
withoutCredentials >> Internal.content
eventId : Event -> String
eventId =
withoutContext >> Internal.eventId
withoutCredentials >> Internal.eventId
originServerTs : Event -> Timestamp
originServerTs =
withoutContext >> Internal.originServerTs
withoutCredentials >> Internal.originServerTs
roomId : Event -> String
roomId =
withoutContext >> Internal.roomId
withoutCredentials >> Internal.roomId
sender : Event -> String
sender =
withoutContext >> Internal.sender
withoutCredentials >> Internal.sender
stateKey : Event -> Maybe String
stateKey =
withoutContext >> Internal.stateKey
withoutCredentials >> Internal.stateKey
contentType : Event -> String
contentType =
withoutContext >> Internal.contentType
withoutCredentials >> Internal.contentType
age : Event -> Maybe Int
age =
withoutContext >> Internal.age
withoutCredentials >> Internal.age
redactedBecause : Event -> Maybe Event
@ -151,4 +151,4 @@ redactedBecause (Event data) =
transactionId : Event -> Maybe String
transactionId =
withoutContext >> Internal.transactionId
withoutCredentials >> Internal.transactionId

View File

@ -7,7 +7,7 @@ import Dict
import Internal.Api.CredUpdate exposing (CredUpdate)
import Internal.Api.Sync.V2.SpecObjects as Sync
import Internal.Api.Task as Api
import Internal.Context as Context exposing (Context)
import Internal.Credentials as Credentials exposing (Credentials)
import Internal.Event as Event exposing (Event)
import Internal.Tools.Exceptions as X
import Internal.Tools.Hashdict as Hashdict
@ -30,7 +30,7 @@ to it.
type Room
= Room
{ room : Internal.IRoom
, context : Context
, context : Credentials
}
@ -98,13 +98,13 @@ addInternalEvent ievent (Room ({ room } as data)) =
-}
addEvent : Event -> Room -> Room
addEvent =
Event.withoutContext >> addInternalEvent
Event.withoutCredentials >> addInternalEvent
{-| Creates a new `Room` object with the given parameters.
-}
withContext : Context -> Internal.IRoom -> Room
withContext context room =
withCredentials : Credentials -> Internal.IRoom -> Room
withCredentials context room =
Room
{ context = context
, room = room
@ -113,8 +113,8 @@ withContext context room =
{-| Retrieves the `Internal.IRoom` type contained within the given `Room`.
-}
withoutContext : Room -> Internal.IRoom
withoutContext (Room { room }) =
withoutCredentials : Room -> Internal.IRoom
withoutCredentials (Room { room }) =
room
@ -124,14 +124,14 @@ mostRecentEvents : Room -> List Event
mostRecentEvents (Room { context, room }) =
room
|> Internal.mostRecentEvents
|> List.map (Event.withContext context)
|> List.map (Event.withCredentials context)
{-| Retrieves the ID of the Matrix room associated with the given `Room`.
-}
roomId : Room -> String
roomId =
withoutContext >> Internal.roomId
withoutCredentials >> Internal.roomId
{-| Sends a new event to the Matrix room associated with the given `Room`.
@ -139,12 +139,12 @@ roomId =
sendEvent : Room -> { eventType : String, content : E.Value } -> Task X.Error CredUpdate
sendEvent (Room { context, room }) { eventType, content } =
Api.sendMessageEvent
{ accessToken = Context.accessToken context
, baseUrl = Context.baseUrl context
{ accessToken = Credentials.accessToken context
, baseUrl = Credentials.baseUrl context
, content = content
, eventType = eventType
, roomId = Internal.roomId room
, versions = Context.versions context
, versions = Credentials.versions context
, extraTransactionNoise = "content-value:<object>"
}
@ -154,8 +154,8 @@ sendEvent (Room { context, room }) { eventType, content } =
sendMessage : Room -> String -> Task X.Error CredUpdate
sendMessage (Room { context, room }) text =
Api.sendMessageEvent
{ accessToken = Context.accessToken context
, baseUrl = Context.baseUrl context
{ accessToken = Credentials.accessToken context
, baseUrl = Credentials.baseUrl context
, content =
E.object
[ ( "msgtype", E.string "m.text" )
@ -163,6 +163,6 @@ sendMessage (Room { context, room }) text =
]
, eventType = "m.room.message"
, roomId = Internal.roomId room
, versions = Context.versions context
, versions = Credentials.versions context
, extraTransactionNoise = "literal-message:" ++ text
}

View File

@ -1,4 +1,4 @@
module Internal.Values.Credentials exposing (..)
module Internal.Values.Vault exposing (..)
{-| The Credentials type is the keychain of the Matrix SDK.
It handles all communication with the homeserver.
@ -8,8 +8,8 @@ import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
import Internal.Values.Room as Room exposing (IRoom)
type ICredentials
= ICredentials
type IVault
= IVault
{ rooms : Hashdict IRoom
, since : Maybe String
}
@ -17,37 +17,37 @@ type ICredentials
{-| Add a new `since` token to sync from.
-}
addSince : String -> ICredentials -> ICredentials
addSince since (ICredentials data) =
ICredentials { data | since = Just since }
addSince : String -> IVault -> IVault
addSince since (IVault data) =
IVault { data | since = Just since }
{-| Get a room from the Credentials type by the room's id.
-}
getRoomById : String -> ICredentials -> Maybe IRoom
getRoomById roomId (ICredentials cred) =
getRoomById : String -> IVault -> Maybe IRoom
getRoomById roomId (IVault cred) =
Hashdict.get roomId cred.rooms
{-| Get a list of all synchronised rooms.
-}
getRooms : ICredentials -> List IRoom
getRooms (ICredentials { rooms }) =
getRooms : IVault -> List IRoom
getRooms (IVault { rooms }) =
Hashdict.values rooms
{-| Get the latest `since` token.
-}
getSince : ICredentials -> Maybe String
getSince (ICredentials { since }) =
getSince : IVault -> Maybe String
getSince (IVault { since }) =
since
{-| Create new empty Credentials.
-}
init : ICredentials
init : IVault
init =
ICredentials
IVault
{ rooms = Hashdict.empty Room.roomId
, since = Nothing
}
@ -58,7 +58,7 @@ init =
This function can hence also be used as an update function for rooms.
-}
insertRoom : IRoom -> ICredentials -> ICredentials
insertRoom room (ICredentials cred) =
ICredentials
insertRoom : IRoom -> IVault -> IVault
insertRoom room (IVault cred) =
IVault
{ cred | rooms = Hashdict.insert room cred.rooms }

216
src/Internal/Vault.elm Normal file
View File

@ -0,0 +1,216 @@
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.CredUpdate exposing (CredUpdate(..))
import Internal.Api.Task 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
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 : Context
}
{-| 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 } =
Context.fromBaseUrl baseUrl
|> Context.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 } =
Context.fromBaseUrl baseUrl
|> Context.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.withContext 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.withoutContext >> insertInternalRoom
{-| Update the Vault type with new values
-}
updateWith : CredUpdate -> Vault -> Vault
updateWith credUpdate ((Vault ({ cred, context } as data)) as credentials) =
case credUpdate 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.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 ->
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 = Context.addToken token context }
UpdateVersions versions ->
Vault { data | context = Context.addVersions versions context }
-- TODO: Save all info
LoggedInWithUsernameAndPassword _ output ->
Vault { data | context = Context.addToken output.accessToken context }
{-| Synchronize credentials
-}
sync : Vault -> Task X.Error CredUpdate
sync (Vault { cred, context }) =
Api.sync
{ accessToken = Context.accessToken context
, baseUrl = Context.baseUrl context
, filter = Nothing
, fullState = Nothing
, setPresence = Nothing
, since = Internal.getSince cred
, timeout = Just 30
, versions = Context.versions context
}
{-| Get a list of all synchronised rooms.
-}
rooms : Vault -> List Room.Room
rooms (Vault { cred, context }) =
cred
|> Internal.getRooms
|> List.map (Room.withContext context)