@@ -83,15 +83,20 @@ setupLocalStateQueryExpr
8383setupLocalStateQueryExpr waitDone mPointVar' resultVar' ntcVersion f =
8484 LocalStateQueryClient . pure . Net.Query. SendMsgAcquire mPointVar' $
8585 Net.Query. ClientStAcquiring
86- { Net.Query. recvMsgAcquired = runContT (runReaderT (runLocalStateQueryExpr f) ntcVersion) $ \ result -> do
87- atomically $ putTMVar resultVar' (Right result)
88- void $ atomically waitDone -- Wait for all protocols to complete before exiting.
89- pure $ Net.Query. SendMsgRelease $ pure $ Net.Query. SendMsgDone ()
86+ { Net.Query. recvMsgAcquired =
87+ let allQueries = runReaderT (runLocalStateQueryExpr f) ntcVersion
88+ in runContT allQueries finalContinuation
9089 , Net.Query. recvMsgFailure = \ failure -> do
9190 atomically $ putTMVar resultVar' (Left (toAcquiringFailure failure))
9291 void $ atomically waitDone -- Wait for all protocols to complete before exiting.
9392 pure $ Net.Query. SendMsgDone ()
9493 }
94+ where
95+ -- We wait for all queries to finish before exiting.
96+ finalContinuation result = do
97+ atomically $ putTMVar resultVar' (Right result)
98+ void $ atomically waitDone -- Wait for all protocols to complete before exiting.
99+ pure $ Net.Query. SendMsgRelease $ pure $ Net.Query. SendMsgDone ()
95100
96101-- | Get the node server's Node-to-Client version.
97102getNtcVersion :: LocalStateQueryExpr block point QueryInMode r IO NodeToClientVersion
@@ -105,10 +110,39 @@ queryExpr q = do
105110 ntcVersion <- getNtcVersion
106111 case isQuerySupportedInNtcVersion (toConsensusQuery q) ntcVersion of
107112 Right () ->
108- fmap Right . LocalStateQueryExpr . ReaderT $ \ _ -> ContT $ \ f ->
109- pure $
110- Net.Query. SendMsgQuery q $
111- Net.Query. ClientStQuerying
112- { Net.Query. recvMsgResult = f
113- }
113+ fmap Right . LocalStateQueryExpr . ReaderT $ \ _ -> constructQueryContinuation q
114114 Left err -> pure $ Left err
115+
116+ {- The client sends a query with the following data constructor:
117+
118+ data ClientStAcquired block point query m a where
119+ SendMsgQuery :: query result
120+ -> ClientStQuerying block point query m a result
121+ -> ClientStAcquired block point query m a
122+
123+ The client is then awaiting a result from the server which is represented by:
124+
125+ data ClientStQuerying block point query m a result = ClientStQuerying {
126+ recvMsgResult :: result -> m (ClientStAcquired block point query m a)
127+ }
128+
129+ When constructing the `ClientStQuerying` value we can send another query (`SendMsgQuery`) or
130+ release (`SendMsgRelease`) and this recursion is nicely modelled with the `ContT` monad transformer.
131+
132+ The final continuation in our case is waiting for all the queries to be returned and then returning
133+ `SendMsgRelease`.
134+ -}
135+ constructQueryContinuation
136+ :: Applicative m
137+ => QueryInMode result
138+ -> ContT
139+ (Net.Query. ClientStAcquired block point QueryInMode m a )
140+ m
141+ result
142+ constructQueryContinuation q = do
143+ ContT $ \ final ->
144+ pure $
145+ Net.Query. SendMsgQuery q $
146+ Net.Query. ClientStQuerying
147+ { Net.Query. recvMsgResult = final
148+ }
0 commit comments