11{-# LANGUAGE OverloadedStrings #-}
2+ {-# OPTIONS_GHC -fno-warn-orphans #-}
23
34module Stub where
45
56
67import Data.Bifunctor
78import Data.ByteString as BS
89import Data.Text
10+ import Data.Text.Lazy as TL
911import Data.Text.Encoding
12+ import Data.IORef ( readIORef
13+ , newIORef
14+ , modifyIORef
15+ , writeIORef
16+ )
1017import Data.Vector as Vector
1118 ( Vector
1219 , length
@@ -25,7 +32,7 @@ import Network.GRPC.HighLevel
2532import Google.Protobuf.Timestamp as Pb
2633import Peer.Proposal as Pb
2734import Proto3.Suite
28- import Proto3.Wire.Decode
35+ import Proto3.Wire.Decode
2936
3037import Interfaces
3138import Messages
@@ -116,7 +123,7 @@ instance ChaincodeStubInterface DefaultChaincodeStub where
116123
117124 -- TODO: Implement better error handling/checks etc
118125 -- getStateByRange :: ccs -> Text -> Text -> IO (Either Error StateQueryIterator)
119- getStateByRange ccs startKey endKey =
126+ getStateByRange ccs startKey endKey =
120127 let payload = getStateByRangePayload startKey endKey
121128 message = buildChaincodeMessage GET_STATE_BY_RANGE payload (txId ccs) (channelId ccs)
122129 -- We have listenForResponse a :: IO (Either Error ByteString)
@@ -126,34 +133,37 @@ instance ChaincodeStubInterface DefaultChaincodeStub where
126133 bsToSqi :: ByteString -> ExceptT Error IO StateQueryIterator
127134 bsToSqi bs = let eeaQueryResponse = parse (decodeMessage (FieldNumber 1 )) bs :: Either ParseError Pb. QueryResponse in
128135 case eeaQueryResponse of
129- Left _ -> ExceptT $ pure $ Left ParseError
130- Right queryResponse -> ExceptT $ do
131- -- queryResponse and currentLoc are IORefs as they need to be mutated
132- -- as a part of the next() function
133- queryResponseIORef <- newIORef queryResponse
134- currentLocIORef <- newIORef 0
135- pure $ Right StateQueryIterator {
136- sqiChannelId = getChannelId ccs
137- , sqiTxId = getTxId ccs
138- , sqiResponse = queryResponseIORef
139- , sqiCurrentLoc = currentLocIORef
140- }
141- in do
142- e <- (sendStream ccs) message
143- case e of
144- Left err -> error (" Error while streaming: " ++ show err)
145- Right _ -> pure ()
146- runExceptT $ ExceptT (listenForResponse (recvStream ccs)) >>= bsToSqi
136+ -- TODO: refactor out pattern matching, e.g. using >>= or <*>
137+ Left _ -> ExceptT $ pure $ Left ParseError
138+ Right queryResponse -> ExceptT $ do
139+ -- queryResponse and currentLoc are IORefs as they need to be mutated
140+ -- as a part of the next() function
141+ queryResponseIORef <- newIORef queryResponse
142+ currentLocIORef <- newIORef 0
143+ pure $ Right StateQueryIterator
144+ { sqiChaincodeStub = ccs
145+ , sqiChannelId = getChannelId ccs
146+ , sqiTxId = getTxId ccs
147+ , sqiResponse = queryResponseIORef
148+ , sqiCurrentLoc = currentLocIORef
149+ }
150+ in do
151+ e <- (sendStream ccs) message
152+ case e of
153+ Left err -> error (" Error while streaming: " ++ show err)
154+ Right _ -> pure ()
155+ runExceptT $ ExceptT (listenForResponse (recvStream ccs)) >>= bsToSqi
147156
148- -- TODO : implement all these interface functions
157+ -- TODO : implement all these interface functions
149158instance StateQueryIteratorInterface StateQueryIterator where
150- -- hasNext :: sqi -> Bool
159+ -- hasNext :: sqi -> Bool
151160 hasNext sqi = True
152161 -- close :: sqi -> IO (Maybe Error)
153162 close _ = pure Nothing
154163 -- next :: sqi -> IO (Either Error Pb.KV)
155164 next _ = pure $ Left $ Error " not implemented"
156165
166+
157167nextResult :: StateQueryIterator -> IO (Either Error Pb. QueryResultBytes )
158168nextResult sqi = do
159169 currentLoc <- readIORef $ sqiCurrentLoc sqi
@@ -171,12 +181,37 @@ nextResult sqi = do
171181 queryResult
172182 else pure $ Left $ Error " Invalid iterator state"
173183
174- -- TODO : this function is only called when the local result list has been
184+
185+ -- This function is only called when the local result list has been
175186-- iterated through and there are more results to get from the peer
176- -- It makes a call to get the next QueryResponse back from the peer
177- -- and mutates the response with the new QueryResponse and set currentLoc back to 0
187+ -- It makes a call to get the next QueryResponse back from the peer
188+ -- and mutates the sqi with the new QueryResponse and sets currentLoc back to 0
178189fetchNextQueryResult :: StateQueryIterator -> IO (Either Error StateQueryIterator )
179- fetchNextQueryResult sqi = pure $ Left $ Error " not yet implemented"
190+ fetchNextQueryResult sqi = do
191+ queryResponse <- readIORef $ sqiResponse sqi
192+ let
193+ payload = queryNextStatePayload $ TL. toStrict $ Pb. queryResponseId queryResponse
194+ message = buildChaincodeMessage QUERY_STATE_NEXT payload (sqiTxId sqi) (sqiChannelId sqi)
195+ bsToQueryResponse :: ByteString -> ExceptT Error IO StateQueryIterator
196+ bsToQueryResponse bs =
197+ let eeaQueryResponse =
198+ parse (decodeMessage (FieldNumber 1 )) bs :: Either
199+ ParseError
200+ Pb. QueryResponse
201+ in case eeaQueryResponse of
202+ -- TODO: refactor out pattern matching, e.g. using >>= or <*>
203+ Left _ -> ExceptT $ pure $ Left ParseError
204+ Right queryResponse -> ExceptT $ do
205+ -- Need to put the new queryResponse in the sqi queryResponse
206+ writeIORef (sqiCurrentLoc sqi) 0
207+ writeIORef (sqiResponse sqi) queryResponse
208+ pure $ Right sqi
209+ in do
210+ e <- (sendStream $ sqiChaincodeStub sqi) message
211+ case e of
212+ Left err -> error (" Error while streaming: " ++ show err)
213+ Right _ -> pure ()
214+ runExceptT $ ExceptT (listenForResponse (recvStream $ sqiChaincodeStub sqi)) >>= bsToQueryResponse
180215
181216 --
182217 -- -- getStateByRangeWithPagination :: ccs -> String -> String -> Int32 -> String -> Either Error (StateQueryIterator, Pb.QueryResponseMetadata)
@@ -249,4 +284,4 @@ fetchNextQueryResult sqi = pure $ Left $ Error "not yet implemented"
249284 -- getTxTimestamp ccs = Right txTimestamp
250285 --
251286 -- -- setEvent :: ccs -> String -> ByteArray -> Maybe Error
252- -- setEvent ccs = Right notImplemented
287+ -- setEvent ccs = Right notImplemented
0 commit comments