diff --git a/language-support/hs/bindings/BUILD.bazel b/language-support/hs/bindings/BUILD.bazel index df27bda5d280..59d4c82e67bf 100644 --- a/language-support/hs/bindings/BUILD.bazel +++ b/language-support/hs/bindings/BUILD.bazel @@ -17,6 +17,7 @@ da_haskell_library( "retry", "text", "time", + "transformers", "vector", ], visibility = ["//visibility:public"], diff --git a/language-support/hs/bindings/examples/chat/src/Contracts.hs b/language-support/hs/bindings/examples/chat/src/Contracts.hs index 44a5bae3565a..f28bfbc72381 100644 --- a/language-support/hs/bindings/examples/chat/src/Contracts.hs +++ b/language-support/hs/bindings/examples/chat/src/Contracts.hs @@ -12,7 +12,7 @@ import DA.Ledger ( Command(..), Event(..), Transaction(..) ) -import DA.Ledger.Valuable (toRecord,fromRecord) +import DA.Ledger.IsLedgerValue (toRecord,fromRecord) import Domain (Introduce,Message,Broadcast) import Logging (Logger) diff --git a/language-support/hs/bindings/examples/chat/src/Domain.hs b/language-support/hs/bindings/examples/chat/src/Domain.hs index 19caf1664ad0..58d0cf2da2ea 100644 --- a/language-support/hs/bindings/examples/chat/src/Domain.hs +++ b/language-support/hs/bindings/examples/chat/src/Domain.hs @@ -12,13 +12,13 @@ module Domain(Party(..), ) where import DA.Ledger.Types as L (Party(..),Value(VList)) -import DA.Ledger.Valuable (Valuable(..)) +import DA.Ledger.IsLedgerValue (IsLedgerValue(..)) import Data.Text.Lazy (Text) data Introduce = Introduce { from :: Party, people :: [Party] } deriving Show -instance Valuable Introduce where +instance IsLedgerValue Introduce where toValue Introduce{from,people} = L.VList [toValue from, toValue people] fromValue = \case L.VList [v1,v2] -> do @@ -30,7 +30,7 @@ instance Valuable Introduce where data Message = Message { from :: Party, to :: Party, body :: Text } deriving Show -instance Valuable Message where +instance IsLedgerValue Message where toValue Message{from,to,body} = L.VList [toValue from, toValue to, toValue body] fromValue = \case L.VList [v1,v2,v3] -> do @@ -43,7 +43,7 @@ instance Valuable Message where data Broadcast = Broadcast { from :: Party, to :: [Party], body :: Text } deriving Show -instance Valuable Broadcast where +instance IsLedgerValue Broadcast where toValue Broadcast{from,to,body} = L.VList [toValue from, toValue to, toValue body] fromValue = \case L.VList [v1,v2,v3] -> do diff --git a/language-support/hs/bindings/examples/nim-console/src/Domain.hs b/language-support/hs/bindings/examples/nim-console/src/Domain.hs index 3aa3cb95cd75..403be6ea645c 100644 --- a/language-support/hs/bindings/examples/nim-console/src/Domain.hs +++ b/language-support/hs/bindings/examples/nim-console/src/Domain.hs @@ -15,7 +15,7 @@ module Domain(Player(..), partyOfPlayer, import Data.List.Extra(zipWithFrom) import DA.Ledger.Types -import DA.Ledger.Valuable(Valuable(..)) +import DA.Ledger.IsLedgerValue(IsLedgerValue(..)) import qualified Data.Text.Lazy as Text data Player = Player { unPlayer :: String } deriving (Eq,Ord) @@ -24,14 +24,14 @@ instance Show Player where show (Player s) = s partyOfPlayer :: Player -> Party partyOfPlayer = Party . Text.pack . unPlayer -instance Valuable Player where +instance IsLedgerValue Player where toValue = toValue . Party . Text.pack . unPlayer fromValue = fmap (Player . Text.unpack . unParty) . fromValue data Offer = Offer { from :: Player, to :: [Player] } deriving (Show) -instance Valuable Offer where +instance IsLedgerValue Offer where toValue Offer{from,to} = VList [toValue from, toValue to] fromValue = \case VList [v1,v2] -> do @@ -42,7 +42,7 @@ instance Valuable Offer where data Game = Game { p1 :: Player, p2 :: Player, piles :: [Int] } deriving (Show) -instance Valuable Game where +instance IsLedgerValue Game where toValue Game{} = undefined -- we never send games to the ledger fromValue = \case VList[VRecord Record{fields=[ @@ -62,7 +62,7 @@ data Move = Move { pileNum :: Int, howMany :: Int } instance Show Move where show Move{pileNum,howMany} = show pileNum <> ":" <> show howMany -instance Valuable Move where +instance IsLedgerValue Move where toValue Move{pileNum,howMany} = VRecord(Record{rid=Nothing, fields=[ diff --git a/language-support/hs/bindings/examples/nim-console/src/NimCommand.hs b/language-support/hs/bindings/examples/nim-console/src/NimCommand.hs index 303feff9253d..b328271e9c34 100644 --- a/language-support/hs/bindings/examples/nim-console/src/NimCommand.hs +++ b/language-support/hs/bindings/examples/nim-console/src/NimCommand.hs @@ -7,7 +7,7 @@ module NimCommand(NimCommand(..), makeLedgerCommands,) where import DA.Ledger as Ledger -import DA.Ledger.Valuable +import DA.Ledger.IsLedgerValue import Domain type Oid = ContractId diff --git a/language-support/hs/bindings/examples/nim-console/src/NimTrans.hs b/language-support/hs/bindings/examples/nim-console/src/NimTrans.hs index f61c26f8f2b3..a8a887c396c6 100644 --- a/language-support/hs/bindings/examples/nim-console/src/NimTrans.hs +++ b/language-support/hs/bindings/examples/nim-console/src/NimTrans.hs @@ -7,7 +7,7 @@ module NimTrans(NimTrans(..), extractTransaction,) where import DA.Ledger as Ledger -import DA.Ledger.Valuable +import DA.Ledger.IsLedgerValue import Domain import Logging diff --git a/language-support/hs/bindings/src/DA/Ledger/Valuable.hs b/language-support/hs/bindings/src/DA/Ledger/IsLedgerValue.hs similarity index 77% rename from language-support/hs/bindings/src/DA/Ledger/Valuable.hs rename to language-support/hs/bindings/src/DA/Ledger/IsLedgerValue.hs index 2e6ef9da68d3..2ea04d54320c 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Valuable.hs +++ b/language-support/hs/bindings/src/DA/Ledger/IsLedgerValue.hs @@ -3,14 +3,14 @@ {-# LANGUAGE OverloadedStrings #-} -module DA.Ledger.Valuable( -- TODO: Better name! - Valuable(..), -- types which can be converted to/from a Ledger API Value +module DA.Ledger.IsLedgerValue ( + IsLedgerValue(..), -- types which can be converted to/from a Ledger API Value ) where import Data.Text.Lazy (Text) import DA.Ledger.Types -class Valuable a where +class IsLedgerValue a where toValue :: a -> Value fromValue :: Value -> Maybe a @@ -28,18 +28,18 @@ class Valuable a where . map fieldValue --(\RecordField{value} -> value) . fields -instance Valuable Int where +instance IsLedgerValue Int where toValue = VInt fromValue = \case VInt x -> Just x; _ -> Nothing -instance Valuable Party where +instance IsLedgerValue Party where toValue = VParty fromValue = \case VParty x -> Just x; _ -> Nothing -instance Valuable a => Valuable [a] where +instance IsLedgerValue a => IsLedgerValue [a] where toValue = VList . map toValue fromValue = \case VList vs -> mapM fromValue vs; _ -> Nothing -instance Valuable Text where +instance IsLedgerValue Text where toValue = VString fromValue = \case VString x -> Just x; _ -> Nothing diff --git a/language-support/hs/bindings/src/DA/Ledger/LedgerService.hs b/language-support/hs/bindings/src/DA/Ledger/LedgerService.hs index 9017f50aebf7..b03d53bd952b 100644 --- a/language-support/hs/bindings/src/DA/Ledger/LedgerService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/LedgerService.hs @@ -3,42 +3,23 @@ -- Abstraction for LedgerService, which can be composed monadically. module DA.Ledger.LedgerService ( - LedgerService, runLedgerService, makeLedgerService, TimeoutSeconds(..), + LedgerService, runLedgerService, makeLedgerService, TimeoutSeconds, ) where -import Prelude hiding (fail) -import Control.Monad (ap,liftM) -import Control.Monad.Fail (MonadFail,fail) -import Control.Monad.IO.Class (MonadIO,liftIO) +import Control.Monad.Fail (MonadFail) +import Control.Monad.IO.Class (MonadIO) +import Control.Monad.Trans.Reader (ReaderT(..),runReaderT) import DA.Ledger.Retry (ledgerRetry) -import Network.GRPC.HighLevel.Generated +import Network.GRPC.HighLevel.Generated(ClientConfig) +import Network.GRPC.HighLevel.Client(TimeoutSeconds) -newtype TimeoutSeconds = TimeoutSeconds { unTimeoutSeconds :: Int } deriving Num +type Context = (TimeoutSeconds,ClientConfig) -newtype LedgerService a = - LedgerService { runLedgerService :: TimeoutSeconds -> ClientConfig -> IO a } - --deriving (Monad) +newtype LedgerService a = LedgerService (ReaderT Context IO a) + deriving (Functor,Applicative,Monad,MonadFail,MonadIO) --- TODO: How do we avoid the boiler plate here? - -instance Functor LedgerService where fmap = liftM -instance Applicative LedgerService where pure = return; (<*>) = ap - -instance Monad LedgerService where - return a = LedgerService $ \_ _ -> return a - (>>=) = bind - -instance MonadIO LedgerService where - liftIO io = LedgerService $ \_ _ -> io - -instance MonadFail LedgerService where - fail s = LedgerService $ \_ _ -> fail s +runLedgerService :: LedgerService a -> TimeoutSeconds -> ClientConfig -> IO a +runLedgerService (LedgerService r) ts cc = runReaderT r (ts,cc) makeLedgerService :: (TimeoutSeconds -> ClientConfig -> IO a) -> LedgerService a -makeLedgerService f = LedgerService $ \t cc -> do ledgerRetry (f t cc) - -bind :: LedgerService a -> (a -> LedgerService b) -> LedgerService b -bind m f = - LedgerService $ \to cc -> do - a <- runLedgerService m to cc - runLedgerService (f a) to cc +makeLedgerService f = LedgerService $ ReaderT $ \(ts,cc) -> ledgerRetry $ f ts cc diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/CommandCompletionService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/CommandCompletionService.hs index 0c169afc6308..28afb4314288 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/CommandCompletionService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/CommandCompletionService.hs @@ -24,7 +24,7 @@ type Request = (LedgerId,ApplicationId,[Party],Maybe LedgerOffset) --completionStream :: Request -> LedgerService (Stream Response) -- GOAL completionStream :: Request -> LedgerService (Stream Completion) completionStream (lid,aid,partys,offset) = - makeLedgerService $ \(TimeoutSeconds timeout) config -> do + makeLedgerService $ \timeout config -> do stream <- newStream let request = mkCompletionStreamRequest lid aid partys offset _ <- forkIO $ diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/CommandSubmissionService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/CommandSubmissionService.hs index 71dede4b91e3..45e490983ef4 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/CommandSubmissionService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/CommandSubmissionService.hs @@ -15,7 +15,7 @@ import Network.GRPC.HighLevel.Generated submit :: Commands -> LedgerService (Either String ()) submit commands = - makeLedgerService $ \(TimeoutSeconds timeout) config -> + makeLedgerService $ \timeout config -> withGRPCClient config $ \client -> do service <- commandSubmissionServiceClient client let CommandSubmissionService rpc = service diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/LedgerIdentityService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/LedgerIdentityService.hs index cf42b8ee5778..2b72e54af760 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/LedgerIdentityService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/LedgerIdentityService.hs @@ -11,7 +11,7 @@ import Network.GRPC.HighLevel.Generated getLedgerIdentity :: LedgerService LedgerId getLedgerIdentity = - makeLedgerService $ \(TimeoutSeconds timeout) config -> do + makeLedgerService $ \timeout config -> do let request = GetLedgerIdentityRequest noTrace withGRPCClient config $ \client -> do service <- ledgerIdentityServiceClient client diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/PackageService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/PackageService.hs index 32efa7085110..a24798ade002 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/PackageService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/PackageService.hs @@ -22,7 +22,7 @@ import qualified Proto3.Suite(fromByteString) listPackages :: LedgerId -> LedgerService [PackageId] listPackages lid = - makeLedgerService $ \(TimeoutSeconds timeout) config -> + makeLedgerService $ \timeout config -> withGRPCClient config $ \client -> do service <- packageServiceClient client let PackageService {packageServiceListPackages=rpc} = service @@ -33,7 +33,7 @@ listPackages lid = getPackage :: LedgerId -> PackageId -> LedgerService (Maybe LF.Package) getPackage lid pid = - makeLedgerService $ \(TimeoutSeconds timeout) config -> + makeLedgerService $ \timeout config -> withGRPCClient config $ \client -> do service <- packageServiceClient client let PackageService {packageServiceGetPackage=rpc} = service @@ -52,7 +52,7 @@ getPackage lid pid = getPackageStatus :: LedgerId -> PackageId -> LedgerService PackageStatus getPackageStatus lid pid = - makeLedgerService $ \(TimeoutSeconds timeout) config -> + makeLedgerService $ \timeout config -> withGRPCClient config $ \client -> do service <- packageServiceClient client let PackageService {packageServiceGetPackageStatus=rpc} = service diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/ResetService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/ResetService.hs index 49763e110535..d1bbe8fafb8e 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/ResetService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/ResetService.hs @@ -12,7 +12,7 @@ import Network.GRPC.HighLevel.Generated reset :: LedgerId -> LedgerService () reset lid = - makeLedgerService $ \(TimeoutSeconds timeout) config -> do + makeLedgerService $ \timeout config -> do withGRPCClient config $ \client -> do service <- resetServiceClient client let ResetService {resetServiceReset=rpc} = service diff --git a/language-support/hs/bindings/src/DA/Ledger/Services/TransactionService.hs b/language-support/hs/bindings/src/DA/Ledger/Services/TransactionService.hs index d931007ee1f2..22dd37090ec4 100644 --- a/language-support/hs/bindings/src/DA/Ledger/Services/TransactionService.hs +++ b/language-support/hs/bindings/src/DA/Ledger/Services/TransactionService.hs @@ -22,7 +22,7 @@ import qualified Com.Digitalasset.Ledger.Api.V1.TransactionService as LL ledgerEnd :: LedgerId -> LedgerService LedgerOffset ledgerEnd lid = - makeLedgerService $ \(TimeoutSeconds timeout) config -> do + makeLedgerService $ \timeout config -> do withGRPCClient config $ \client -> do service <- LL.transactionServiceClient client let LL.TransactionService{transactionServiceGetLedgerEnd=rpc} = service @@ -53,7 +53,7 @@ lowerRequest = \case getTransactions :: GetTransactionsRequest -> LedgerService (Stream Transaction) getTransactions tup = - makeLedgerService $ \(TimeoutSeconds timeout) config -> do + makeLedgerService $ \timeout config -> do stream <- newStream let request = lowerRequest tup _ <- forkIO $ diff --git a/language-support/hs/bindings/test/DA/Ledger/Tests.hs b/language-support/hs/bindings/test/DA/Ledger/Tests.hs index 2be0d6cb1e71..ea3de4359be5 100644 --- a/language-support/hs/bindings/test/DA/Ledger/Tests.hs +++ b/language-support/hs/bindings/test/DA/Ledger/Tests.hs @@ -237,7 +237,8 @@ looksLikeSandBoxLedgerId (LedgerId text) = -- runWithSandbox runWithSandbox :: Sandbox -> LedgerService a -> IO a -runWithSandbox Sandbox{port} ls = runLedgerService ls 30 (configOfPort port) +runWithSandbox Sandbox{port} ls = runLedgerService ls timeout (configOfPort port) + where timeout = 30 :: TimeoutSeconds resetSandbox :: Sandbox-> IO () resetSandbox sandbox = runWithSandbox sandbox $ do