From 68d93180c170c9400168536039e97c9b1cb96f1a Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Wed, 1 Mar 2023 11:21:22 +0100 Subject: [PATCH] Add PreApi for getting unavailable values --- src/Internal/Api/All.elm | 170 +++++++++-- src/Internal/Api/CredUpdate.elm | 104 ------- src/Internal/Api/GetEvent/Main.elm | 3 +- src/Internal/Api/JoinedMembers/Main.elm | 3 +- src/Internal/Api/PreApi/Main.elm | 65 +++++ src/Internal/Api/PreApi/Objects/Versions.elm | 43 +++ src/Internal/Api/PreApi/Objects/Versions.yaml | 12 + src/Internal/Api/SendMessageEvent/Main.elm | 3 +- src/Internal/Api/SendStateKey/Main.elm | 3 +- src/Internal/Api/Sync/Api.elm | 4 +- src/Internal/Api/Sync/Main.elm | 3 +- src/Internal/Tools/LoginValues.elm | 56 ++++ src/Internal/Tools/Timestamp.elm | 13 +- src/Internal/Tools/ValueGetter.elm | 271 ++++++++++++++++++ 14 files changed, 607 insertions(+), 146 deletions(-) delete mode 100644 src/Internal/Api/CredUpdate.elm create mode 100644 src/Internal/Api/PreApi/Main.elm create mode 100644 src/Internal/Api/PreApi/Objects/Versions.elm create mode 100644 src/Internal/Api/PreApi/Objects/Versions.yaml create mode 100644 src/Internal/Tools/LoginValues.elm create mode 100644 src/Internal/Tools/ValueGetter.elm diff --git a/src/Internal/Api/All.elm b/src/Internal/Api/All.elm index b0394d9..97845a0 100644 --- a/src/Internal/Api/All.elm +++ b/src/Internal/Api/All.elm @@ -1,12 +1,18 @@ module Internal.Api.All exposing (..) +import Hash import Internal.Api.GetEvent.Main as GetEvent import Internal.Api.JoinedMembers.Main as JoinedMembers +import Internal.Api.PreApi.Main as PreApi +import Internal.Api.PreApi.Objects.Versions as V import Internal.Api.SendMessageEvent.Main as SendMessageEvent import Internal.Api.SendStateKey.Main as SendStateKey import Internal.Api.Sync.Main as Sync -import Internal.Api.Versions.Main as Versions import Internal.Tools.Exceptions as X +import Internal.Tools.LoginValues exposing (AccessToken) +import Internal.Tools.SpecEnums as Enums +import Internal.Tools.ValueGetter as VG +import Json.Encode as E import Task exposing (Task) @@ -14,43 +20,161 @@ type alias Future a = Task X.Error a +type alias GetEventInput = + { accessToken : AccessToken + , baseUrl : String + , eventId : String + , roomId : String + , versions : Maybe V.Versions + } + + {-| Get a specific event from the Matrix API. -} -getEvent : List String -> Maybe (GetEvent.EventInput -> Future GetEvent.EventOutput) -getEvent = - GetEvent.getEvent +getEvent : GetEventInput -> Future GetEvent.EventOutput +getEvent data = + VG.withInfo2 + (\accessToken versions -> + GetEvent.getEvent + versions.versions + { accessToken = accessToken + , baseUrl = data.baseUrl + , eventId = data.eventId + , roomId = data.roomId + } + ) + (PreApi.accessToken data.baseUrl data.accessToken) + (PreApi.versions data.baseUrl data.versions) + + +type alias JoinedMembersInput = + { accessToken : AccessToken + , baseUrl : String + , roomId : String + , versions : Maybe V.Versions + } {-| Get a list of members who are part of a Matrix room. -} -joinedMembers : List String -> Maybe (JoinedMembers.JoinedMembersInput -> Future JoinedMembers.JoinedMembersOutput) -joinedMembers = - JoinedMembers.joinedMembers +joinedMembers : JoinedMembersInput -> Future JoinedMembers.JoinedMembersOutput +joinedMembers data = + VG.withInfo2 + (\accessToken versions -> + JoinedMembers.joinedMembers + versions.versions + { accessToken = accessToken + , baseUrl = data.baseUrl + , roomId = data.roomId + } + ) + (PreApi.accessToken data.baseUrl data.accessToken) + (PreApi.versions data.baseUrl data.versions) + + +type alias SendMessageEventInput = + { accessToken : AccessToken + , baseUrl : String + , content : E.Value + , eventType : String + , roomId : String + , versions : Maybe V.Versions + , extraTransactionNoise : String + } {-| Send a message event into a Matrix room. -} -sendMessageEvent : List String -> Maybe (SendMessageEvent.SendMessageEventInput -> Future SendMessageEvent.SendMessageEventOutput) -sendMessageEvent = - SendMessageEvent.sendMessageEvent +sendMessageEvent : SendMessageEventInput -> Future SendMessageEvent.SendMessageEventOutput +sendMessageEvent data = + VG.withInfo3 + (\accessToken versions transactionId -> + SendMessageEvent.sendMessageEvent + versions.versions + { accessToken = accessToken + , baseUrl = data.baseUrl + , content = data.content + , eventType = data.eventType + , roomId = data.roomId + , transactionId = transactionId + } + ) + (PreApi.accessToken data.baseUrl data.accessToken) + (PreApi.versions data.baseUrl data.versions) + (PreApi.transactionId + (\timestamp -> + [ Hash.fromInt timestamp + , Hash.fromString data.baseUrl + , Hash.fromString data.eventType + , Hash.fromString data.roomId + , Hash.fromString data.extraTransactionNoise + ] + |> List.foldl Hash.dependent (Hash.fromInt 0) + |> Hash.toString + |> (++) "elm" + ) + ) + + +type alias SendStateKeyInput = + { accessToken : AccessToken + , baseUrl : String + , content : E.Value + , eventType : String + , roomId : String + , stateKey : String + , versions : Maybe V.Versions + } {-| Send a state event into a Matrix room. -} -sendStateEvent : List String -> Maybe (SendStateKey.SendStateKeyInput -> Future SendStateKey.SendStateKeyOutput) -sendStateEvent = - SendStateKey.sendStateKey +sendStateEvent : SendStateKeyInput -> Future SendStateKey.SendStateKeyOutput +sendStateEvent data = + VG.withInfo2 + (\accessToken versions -> + SendStateKey.sendStateKey + versions.versions + { accessToken = accessToken + , baseUrl = data.baseUrl + , content = data.content + , eventType = data.eventType + , roomId = data.roomId + , stateKey = data.stateKey + } + ) + (PreApi.accessToken data.baseUrl data.accessToken) + (PreApi.versions data.baseUrl data.versions) + + +type alias SyncInput = + { accessToken : AccessToken + , baseUrl : String + , filter : Maybe String + , fullState : Maybe Bool + , setPresence : Maybe Enums.UserPresence + , since : Maybe String + , timeout : Maybe Int + , versions : Maybe V.Versions + } {-| Get the latest sync from the Matrix API. -} -syncCredentials : List String -> Maybe (Sync.SyncInput -> Future Sync.SyncOutput) -syncCredentials = - Sync.sync - - -{-| Get all supported versions on the Matrix homeserver. --} -versions : Versions.VersionsInput -> Versions.VersionsOutput -versions = - Versions.getVersions +syncCredentials : SyncInput -> Future Sync.SyncOutput +syncCredentials data = + VG.withInfo2 + (\accessToken versions -> + Sync.sync + versions.versions + { accessToken = accessToken + , baseUrl = data.baseUrl + , filter = data.filter + , fullState = data.fullState + , setPresence = data.setPresence + , since = data.since + , timeout = data.timeout + } + ) + (PreApi.accessToken data.baseUrl data.accessToken) + (PreApi.versions data.baseUrl data.versions) diff --git a/src/Internal/Api/CredUpdate.elm b/src/Internal/Api/CredUpdate.elm deleted file mode 100644 index cac742c..0000000 --- a/src/Internal/Api/CredUpdate.elm +++ /dev/null @@ -1,104 +0,0 @@ -module Internal.Api.CredUpdate exposing (getEvent, joinedMembers, sendMessage, sendState, sync) -{-| Sometimes, the `Credentials` type needs to refresh its tokens, log in again, -change some state or adjust its values to be able to keep talking to the server. - -That's what the `CredUpdate` type is for. It is a list of changes that the -`Credentials` type needs to make. --} - -import Internal.Api.GetEvent.Main as GetEvent -import Internal.Api.Helpers as H -import Internal.Api.JoinedMembers.Main as JoinedMembers -import Internal.Api.SendMessageEvent.Main as SendMessageEvent -import Internal.Api.SendStateKey.Main as SendStateKey -import Internal.Api.Sync.Main as Sync -import Internal.Api.Versions.Main as Versions -import Internal.Tools.Exceptions as X -import Task exposing (Task) - -type CredUpdate - = MultipleChanges (List CredUpdate) - | EventDetails GetEvent.EventOutput - | RoomMemberList JoinedMembers.JoinedMembersOutput - | MessageEventSent SendMessageEvent.SendMessageEventOutput - | StateEventSent SendStateKey.SendStateKeyOutput - | SyncReceived Sync.SyncOutput - | VersionReceived Versions.VersionsOutput - -type alias Updater = Task X.Error CredUpdate - -getEvent : Maybe (List String) -> GetEvent.EventInput -> Updater -getEvent versions = - maybeWithVersions - { maybeVersions = versions - , f = GetEvent.getEvent - , toUpdate = EventDetails - } - >> H.retryTask 2 - -joinedMembers : Maybe (List String) -> JoinedMembers.JoinedMembersInput -> Updater -joinedMembers versions = - maybeWithVersions - { maybeVersions = versions - , f = JoinedMembers.joinedMembers - , toUpdate = RoomMemberList - } - -sendMessage : Maybe (List String) -> SendMessageEvent.SendMessageEventInput -> Updater -sendMessage versions = - maybeWithVersions - { maybeVersions = versions - , f = SendMessageEvent.sendMessageEvent - , toUpdate = MessageEventSent - } - >> H.retryTask 5 - -sendState : Maybe (List String) -> SendStateKey.SendStateKeyInput -> Updater -sendState versions = - maybeWithVersions - { maybeVersions = versions - , f = SendStateKey.sendStateKey - , toUpdate = StateEventSent - } - >> H.retryTask 5 - -sync : Maybe (List String) -> Sync.SyncInput -> Updater -sync versions = - maybeWithVersions - { maybeVersions = versions - , f = Sync.sync - , toUpdate = SyncReceived - } - >> H.retryTask 1 - - -maybeWithVersions : - { maybeVersions : Maybe (List String) - , f : (List String -> Maybe ({ in | baseUrl : String } -> Task X.Error out)) - , toUpdate : (out -> CredUpdate) - } -> - { in | baseUrl : String } -> Updater -maybeWithVersions {maybeVersions, f, toUpdate} params = - case maybeVersions of - Just versions -> - case f versions of - Just task -> - task params - |> Task.map toUpdate - Nothing -> - Task.fail X.UnsupportedSpecVersion - - Nothing -> - Versions.getVersions params.baseUrl - |> Task.andThen - (\versions -> - maybeWithVersions (Just versions.supportedVersions) f toUpdate params - |> Task.map - (\update -> - MultipleChanges - [ update - , VersionReceived versions - ] - ) - ) - diff --git a/src/Internal/Api/GetEvent/Main.elm b/src/Internal/Api/GetEvent/Main.elm index 3284b8b..d90b960 100644 --- a/src/Internal/Api/GetEvent/Main.elm +++ b/src/Internal/Api/GetEvent/Main.elm @@ -6,7 +6,7 @@ import Internal.Tools.VersionControl as VC import Task exposing (Task) -getEvent : List String -> Maybe (EventInput -> Task X.Error EventOutput) +getEvent : List String -> EventInput -> Task X.Error EventOutput getEvent versions = VC.withBottomLayer { current = Api.getEventInputV1 @@ -20,6 +20,7 @@ getEvent versions = |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" |> VC.mostRecentFromVersionList versions + |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) type alias EventOutput = diff --git a/src/Internal/Api/JoinedMembers/Main.elm b/src/Internal/Api/JoinedMembers/Main.elm index 2dc5aa0..2225f23 100644 --- a/src/Internal/Api/JoinedMembers/Main.elm +++ b/src/Internal/Api/JoinedMembers/Main.elm @@ -6,7 +6,7 @@ import Internal.Tools.VersionControl as VC import Task exposing (Task) -joinedMembers : List String -> Maybe (JoinedMembersInput -> Task X.Error JoinedMembersOutput) +joinedMembers : List String -> JoinedMembersInput -> Task X.Error JoinedMembersOutput joinedMembers versions = VC.withBottomLayer { current = Api.joinedMembersV1 @@ -31,6 +31,7 @@ joinedMembers versions = |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" |> VC.mostRecentFromVersionList versions + |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) type alias JoinedMembersInput = diff --git a/src/Internal/Api/PreApi/Main.elm b/src/Internal/Api/PreApi/Main.elm new file mode 100644 index 0000000..0835077 --- /dev/null +++ b/src/Internal/Api/PreApi/Main.elm @@ -0,0 +1,65 @@ +module Internal.Api.PreApi.Main exposing (..) + +{-| Certain values are required knowledge for (almost) every endpoint. +Some values aren't known right away, however. + +This module takes care of values like access tokens, transaction ids and spec version lists +that the credentials type needs to know about before it can make a request. + +-} + +import Internal.Api.PreApi.Objects.Versions as V +import Internal.Api.Request as R +import Internal.Tools.Exceptions as X +import Internal.Tools.LoginValues exposing (AccessToken(..)) +import Internal.Tools.ValueGetter exposing (ValueGetter) +import Task +import Time + + +accessToken : String -> AccessToken -> ValueGetter String +accessToken baseUrl t = + { value = + case t of + NoAccess -> + Nothing + + AccessToken token -> + Just token + + UsernameAndPassword { token } -> + token + , getValue = + "Automated login yet needs to be implemented." + |> X.NotSupportedYet + |> X.SDKException + |> Task.fail + } + + +transactionId : (Int -> String) -> ValueGetter String +transactionId seeder = + { value = Nothing + , getValue = + Time.now + |> Task.map Time.posixToMillis + |> Task.map seeder + } + + +versions : String -> Maybe V.Versions -> ValueGetter V.Versions +versions baseUrl mVersions = + { value = mVersions + , getValue = + R.rawApiCall + { headers = R.NoHeaders + , method = "GET" + , baseUrl = baseUrl + , path = "/_matrix/client/versions" + , pathParams = [] + , queryParams = [] + , bodyParams = [] + , timeout = Nothing + , decoder = \_ -> V.versionsDecoder + } + } diff --git a/src/Internal/Api/PreApi/Objects/Versions.elm b/src/Internal/Api/PreApi/Objects/Versions.elm new file mode 100644 index 0000000..9608abe --- /dev/null +++ b/src/Internal/Api/PreApi/Objects/Versions.elm @@ -0,0 +1,43 @@ +module Internal.Api.PreApi.Objects.Versions exposing + ( Versions + , encodeVersions + , versionsDecoder + ) + +{-| Automatically generated 'Versions' + +Last generated at Unix time 1677064309 + +-} + +import Dict exposing (Dict) +import Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault) +import Internal.Tools.EncodeExtra exposing (maybeObject) +import Json.Decode as D +import Json.Encode as E + + +{-| Information on what the homeserver supports. +-} +type alias Versions = + { unstableFeatures : Dict String Bool + , versions : List String + } + + +encodeVersions : Versions -> E.Value +encodeVersions data = + maybeObject + [ ( "unstable_features", Just <| E.dict identity E.bool data.unstableFeatures ) + , ( "versions", Just <| E.list E.string data.versions ) + ] + + +versionsDecoder : D.Decoder Versions +versionsDecoder = + D.map2 + (\a b -> + { unstableFeatures = a, versions = b } + ) + (opFieldWithDefault "unstable_features" Dict.empty (D.dict D.bool)) + (D.field "versions" (D.list D.string)) diff --git a/src/Internal/Api/PreApi/Objects/Versions.yaml b/src/Internal/Api/PreApi/Objects/Versions.yaml new file mode 100644 index 0000000..cd223c3 --- /dev/null +++ b/src/Internal/Api/PreApi/Objects/Versions.yaml @@ -0,0 +1,12 @@ +version: V_all +name: Versions +objects: + Versions: + description: Information on what the homeserver supports. + fields: + unstable_features: + type: "{bool}" + default: Dict.empty + versions: + type: "[string]" + required: true diff --git a/src/Internal/Api/SendMessageEvent/Main.elm b/src/Internal/Api/SendMessageEvent/Main.elm index e8f161e..22428d2 100644 --- a/src/Internal/Api/SendMessageEvent/Main.elm +++ b/src/Internal/Api/SendMessageEvent/Main.elm @@ -6,7 +6,7 @@ import Internal.Tools.VersionControl as VC import Task exposing (Task) -sendMessageEvent : List String -> Maybe (SendMessageEventInput -> Task X.Error SendMessageEventOutput) +sendMessageEvent : List String -> SendMessageEventInput -> Task X.Error SendMessageEventOutput sendMessageEvent versions = VC.withBottomLayer { current = Api.sendMessageEventV1 @@ -31,6 +31,7 @@ sendMessageEvent versions = |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" |> VC.mostRecentFromVersionList versions + |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) type alias SendMessageEventInput = diff --git a/src/Internal/Api/SendStateKey/Main.elm b/src/Internal/Api/SendStateKey/Main.elm index f944d87..92adc3c 100644 --- a/src/Internal/Api/SendStateKey/Main.elm +++ b/src/Internal/Api/SendStateKey/Main.elm @@ -6,7 +6,7 @@ import Internal.Tools.VersionControl as VC import Task exposing (Task) -sendStateKey : List String -> Maybe (SendStateKeyInput -> Task X.Error SendStateKeyOutput) +sendStateKey : List String -> SendStateKeyInput -> Task X.Error SendStateKeyOutput sendStateKey versions = VC.withBottomLayer { current = Api.sendStateKeyV1 @@ -31,6 +31,7 @@ sendStateKey versions = |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" |> VC.mostRecentFromVersionList versions + |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) type alias SendStateKeyInput = diff --git a/src/Internal/Api/Sync/Api.elm b/src/Internal/Api/Sync/Api.elm index 6591c5f..5b29faa 100644 --- a/src/Internal/Api/Sync/Api.elm +++ b/src/Internal/Api/Sync/Api.elm @@ -45,7 +45,7 @@ syncV1 data = , bodyParams = [] , timeout = data.timeout - |> Maybe.map ((+) 10000) + |> Maybe.map ((*) 1000) |> Maybe.map toFloat , decoder = \_ -> SO1.syncDecoder } @@ -69,7 +69,7 @@ syncV2 data = , bodyParams = [] , timeout = data.timeout - |> Maybe.map ((+) 10000) + |> Maybe.map ((*) 1000) |> Maybe.map toFloat , decoder = \_ -> SO2.syncDecoder } diff --git a/src/Internal/Api/Sync/Main.elm b/src/Internal/Api/Sync/Main.elm index 56e8cdd..c78718b 100644 --- a/src/Internal/Api/Sync/Main.elm +++ b/src/Internal/Api/Sync/Main.elm @@ -7,7 +7,7 @@ import Internal.Tools.VersionControl as VC import Task exposing (Task) -sync : List String -> Maybe (SyncInput -> Task X.Error SyncOutput) +sync : List String -> SyncInput -> Task X.Error SyncOutput sync versions = VC.withBottomLayer { current = Api.syncV1 @@ -22,6 +22,7 @@ sync versions = } |> VC.sameForVersion "v1.5" |> VC.mostRecentFromVersionList versions + |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) type alias SyncInput = diff --git a/src/Internal/Tools/LoginValues.elm b/src/Internal/Tools/LoginValues.elm new file mode 100644 index 0000000..165aab2 --- /dev/null +++ b/src/Internal/Tools/LoginValues.elm @@ -0,0 +1,56 @@ +module Internal.Tools.LoginValues exposing (..) + + +type AccessToken + = NoAccess + | AccessToken String + | UsernameAndPassword { username : String, password : String, token : Maybe String } + + +defaultAccessToken : AccessToken +defaultAccessToken = + NoAccess + + +fromAccessToken : String -> AccessToken +fromAccessToken = + AccessToken + + +fromUsernameAndPassword : String -> String -> AccessToken +fromUsernameAndPassword username password = + UsernameAndPassword + { username = username + , password = password + , token = Nothing + } + + +getToken : AccessToken -> Maybe String +getToken t = + case t of + NoAccess -> + Nothing + + AccessToken token -> + Just token + + UsernameAndPassword { token } -> + token + + +addToken : String -> AccessToken -> AccessToken +addToken s t = + case t of + NoAccess -> + AccessToken s + + AccessToken _ -> + AccessToken s + + UsernameAndPassword { username, password } -> + UsernameAndPassword + { username = username + , password = password + , token = Just s + } diff --git a/src/Internal/Tools/Timestamp.elm b/src/Internal/Tools/Timestamp.elm index fd38d2a..983fcff 100644 --- a/src/Internal/Tools/Timestamp.elm +++ b/src/Internal/Tools/Timestamp.elm @@ -1,8 +1,7 @@ -module Internal.Tools.Timestamp exposing (Timestamp, encodeTimestamp, generateTransactionId, timestampDecoder) +module Internal.Tools.Timestamp exposing (Timestamp, encodeTimestamp, timestampDecoder) import Json.Decode as D import Json.Encode as E -import Task exposing (Task) import Time @@ -22,13 +21,3 @@ encodeTimestamp = timestampDecoder : D.Decoder Timestamp timestampDecoder = D.map Time.millisToPosix D.int - - -{-| Generate a transaction id from the current Unix timestamp --} -generateTransactionId : Task x String -generateTransactionId = - Time.now - |> Task.map Time.posixToMillis - |> Task.map String.fromInt - |> Task.map ((++) "elm") diff --git a/src/Internal/Tools/ValueGetter.elm b/src/Internal/Tools/ValueGetter.elm new file mode 100644 index 0000000..e73a689 --- /dev/null +++ b/src/Internal/Tools/ValueGetter.elm @@ -0,0 +1,271 @@ +module Internal.Tools.ValueGetter exposing (..) + +{-| This module creates task pipelines that help gather information +in the Matrix API. + +For example, it might happen that you need to make multiple API calls: + + - Authenticate + - Log in + - Get a list of channels + - Send a message in every room + +For each of these API requests, you might need certain information like +which spec version the homeserver supports. + +This module takes care of this. That way, functions can be written simply by +saying "I need THESE values" and you will then be able to assign them to each +HTTP call that needs that value. + +-} + +import Task exposing (Task) + + +{-| A ValueGetter type takes care of values that MIGHT be available. +If a value is not available, then the task can be used to get a new value. +-} +type alias ValueGetter a = + { value : Maybe a, getValue : Task x a } + + +{-| Convert a `ValueGetter` type to a task. If a previous value has already been given, +then use that value. Otherwise, use the `getValue` task to get a new value. +-} +toTask : ValueGetter a -> Task x a +toTask { value, getValue } = + Maybe.map Task.succeed value + |> Maybe.withDefault getValue + + +withInfo : (a -> Task x result) -> ValueGetter a -> Task x result +withInfo task info1 = + Task.andThen + (\a -> + task a + ) + (toTask info1) + + +withInfo2 : + (a -> b -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> Task x result +withInfo2 task info1 info2 = + Task.andThen + (\a -> + Task.andThen + (\b -> + task a b + ) + (toTask info2) + ) + (toTask info1) + + +withInfo3 : + (a -> b -> c -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> Task x result +withInfo3 task info1 info2 info3 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + task a b c + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1) + + +withInfo4 : + (a -> b -> c -> d -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> ValueGetter d + -> Task x result +withInfo4 task info1 info2 info3 info4 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + Task.andThen + (\d -> + task a b c d + ) + (toTask info4) + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1) + + +withInfo5 : + (a -> b -> c -> d -> e -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> ValueGetter d + -> ValueGetter e + -> Task x result +withInfo5 task info1 info2 info3 info4 info5 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + Task.andThen + (\d -> + Task.andThen + (\e -> + task a b c d e + ) + (toTask info5) + ) + (toTask info4) + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1) + + +withInfo6 : + (a -> b -> c -> d -> e -> f -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> ValueGetter d + -> ValueGetter e + -> ValueGetter f + -> Task x result +withInfo6 task info1 info2 info3 info4 info5 info6 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + Task.andThen + (\d -> + Task.andThen + (\e -> + Task.andThen + (\f -> + task a b c d e f + ) + (toTask info6) + ) + (toTask info5) + ) + (toTask info4) + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1) + + +withInfo7 : + (a -> b -> c -> d -> e -> f -> g -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> ValueGetter d + -> ValueGetter e + -> ValueGetter f + -> ValueGetter g + -> Task x result +withInfo7 task info1 info2 info3 info4 info5 info6 info7 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + Task.andThen + (\d -> + Task.andThen + (\e -> + Task.andThen + (\f -> + Task.andThen + (\g -> + task a b c d e f g + ) + (toTask info7) + ) + (toTask info6) + ) + (toTask info5) + ) + (toTask info4) + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1) + + +withInfo8 : + (a -> b -> c -> d -> e -> f -> g -> h -> Task x result) + -> ValueGetter a + -> ValueGetter b + -> ValueGetter c + -> ValueGetter d + -> ValueGetter e + -> ValueGetter f + -> ValueGetter g + -> ValueGetter h + -> Task x result +withInfo8 task info1 info2 info3 info4 info5 info6 info7 info8 = + Task.andThen + (\a -> + Task.andThen + (\b -> + Task.andThen + (\c -> + Task.andThen + (\d -> + Task.andThen + (\e -> + Task.andThen + (\f -> + Task.andThen + (\g -> + Task.andThen + (\h -> + task a b c d e f g h + ) + (toTask info8) + ) + (toTask info7) + ) + (toTask info6) + ) + (toTask info5) + ) + (toTask info4) + ) + (toTask info3) + ) + (toTask info2) + ) + (toTask info1)