api-rpc-pegnet (empty) → 0.1.0.0
raw patch · 8 files changed
+371/−0 lines, 8 filesdep +aesondep +aeson-casingdep +basesetup-changed
Dependencies added: aeson, aeson-casing, base, bytestring, http-client, http-client-tls, http-conduit, json-alt, network, remote-json, remote-json-client, remote-monad, text, time, transformers
Files
- LICENSE +30/−0
- README.md +58/−0
- Setup.hs +2/−0
- api-rpc-pegnet.cabal +55/−0
- src/PegNet/RPC/Api.hs +78/−0
- src/PegNet/RPC/Types.hs +1/−0
- src/PegNet/RPC/Types/SyncStatus.hs +47/−0
- src/PegNet/RPC/Types/Transaction.hs +100/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Sergey Bushnyak (c) 2019++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Sergey Bushnyak nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,58 @@+# Haskell JSON-RPC client for PegNet++[](https://travis-ci.com/kompendium-llc/api-rpc-factom)+[](https://github.com/kompendium-llc/api-rpc-factom/blob/master/LICENSE)++A JSON-RPC Haskell client for the PegNet [API](https://github.com/pegnet/pegnetd/wiki/API). Each response has special ADT(algebraic data type) that automatically converted from JSON response.++# Installation++You can install package from [Hackage](https://hackage.haskell.org/package/api-rpc-factom) and build with Cabal, but we recommend to use [Stack](https://haskellstack.org) tool. Add to you dependencies in stack.yaml and cabal file dependency `- api-rpc-factom`.++To run and test fromrepository++1. Build with stack+```bash+$ stack build+```++2. Load REPL with stack for evaluation+```+$ stack repl+```++3. execute required methods++## Usage++for basic daemon functionality++1. import with++```haskell+import PegNet.RPC.Api+```+or load in REPL.++2. build communication session with+```+weakSession (traceSendAPI "" $ clientSendAPI endpoint)+```++3. run required methods inside `RPC` monad++#### Retreiving a sync status++```haskell+-- build communication session+let s = weakSession (traceSendAPI "" $ clientSendAPI endpoint)++-- run Remote Monad+h <- send s $ do+ -- run specific events by executing exposed+ h <- reqGetSyncStatus+ return h+-- show converted ADT+print h+-- or use for special business logic+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ api-rpc-pegnet.cabal view
@@ -0,0 +1,55 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: f998af876ee380cd0f3e17213282441322f7618fb4ea71159e87d583bb7e2f57++name: api-rpc-pegnet+version: 0.1.0.0+synopsis: simple json-rpc client for PegNet+description: simple json-rpc client for PegNet integration+category: Web+homepage: https://github.com/sigrlami/api-rpc-pegnet#readme+bug-reports: https://github.com/sigrlami/api-rpc-pegnet/issues+author: Sergey Bushnyak+maintainer: sergey.bushnyak@sigrlami.eu+copyright: Copyright: (c) 2019 Sergey Bushnyak+license: MIT+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md++source-repository head+ type: git+ location: https://github.com/sigrlami/api-rpc-pegnet++library+ exposed-modules:+ PegNet.RPC.Api+ other-modules:+ PegNet.RPC.Types+ PegNet.RPC.Types.SyncStatus+ PegNet.RPC.Types.Transaction+ Paths_api_rpc_pegnet+ hs-source-dirs:+ src+ build-depends:+ aeson+ , aeson-casing+ , base >=4.7 && <5+ , bytestring+ , http-client+ , http-client-tls+ , http-conduit+ , json-alt+ , network+ , remote-json+ , remote-json-client+ , remote-monad+ , text+ , time+ , transformers+ default-language: Haskell2010
+ src/PegNet/RPC/Api.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Api where++import Control.Concurrent+import Control.Exception (bracket)+import Control.Monad.IO.Class+import Control.Remote.Monad.JSON+import Control.Remote.Monad.JSON.Client+import Control.Remote.Monad.JSON.Router+import Control.Remote.Monad.JSON.Trace+import Data.Aeson+import Data.Aeson.Types+import Data.Text+import Network.Socket (HostName, ServiceName,+ SocketType (Stream),+ addrAddress, addrFamily,+ addrProtocol, addrSocketType,+ close, connect, defaultHints,+ getAddrInfo, socket)++import PegNet.RPC.Types.SyncStatus+import PegNet.RPC.Types.Transaction++--------------------------------------------------------------------------------++endpoint = "http://localhost:8070/v1"+endpointRemote = "http://dev.pegnet.org/v1"++-- | "get-sync-status"+-- Return the current heights synced by pegnetd and the factomd it is communicating with+reqGetSyncStatus :: RPC SyncStatus+reqGetSyncStatus =+ method "get-sync-status" None -- $ List [toJSON height]++-- | "get-transaction"+-- Returns if a given entry hash is a pegnet transaction, and if so returns the transaction.+reqGetTransaction :: Text -> Text -> RPC Transaction+reqGetTransaction chainId entryHash =+ method "get-transaction" $ List [String chainId, String entryHash]++reqPegNetIssuance :: RPC ()+reqPegNetIssuance =+ method "get-pegnet-issuance" None++reqPegNetBalances :: RPC ()+reqPegNetBalances =+ method "get-pegnet-balances" None++reqPegNetRates :: RPC ()+reqPegNetRates =+ method "get-pegnet-rates" None++reqGetTransactionStatus :: Text -> RPC ()+reqGetTransactionStatus id =+ method "get-transaction-status" None++reqGeTransactions :: RPC [Transaction]+reqGeTransactions =+ method "get-transactions" None++--------------------------------------------------------------------------------++main = do+ let s = weakSession (traceSendAPI "" $ clientSendAPI endpoint)+ h <- send s $ do+ h <- reqGetSyncStatus+ return h+ print h
+ src/PegNet/RPC/Types.hs view
@@ -0,0 +1,1 @@+module PegNet.RPC.Types where
+ src/PegNet/RPC/Types/SyncStatus.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.SyncStatus where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++-- | Workaround for https://github.com/bos/aeson/issues/287.+o .:?? val = fmap join (o .:? val)++data SyncStatus = SyncStatus {+ topLevelFactomheight :: Double,+ topLevelSyncheight :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)++instance FromJSON SyncStatus where+ parseJSON (Object v) =+ SyncStatus+ <$> v .: "factomheight"+ <*> v .: "syncheight"+ parseJSON _ = mzero++instance ToJSON SyncStatus where+ toJSON (SyncStatus {..}) =+ object [ "factomheight" .= topLevelFactomheight+ , "syncheight" .= topLevelSyncheight]+ toEncoding (SyncStatus {..}) =+ pairs ( "factomheight" .= topLevelFactomheight+ <> "syncheight" .= topLevelSyncheight)
+ src/PegNet/RPC/Types/Transaction.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.Transaction where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++-- | Workaround for https://github.com/bos/aeson/issues/287.+o .:?? val = fmap join (o .:? val)+++data Input = Input {+ inputAmount :: Double,+ inputAddress :: Text,+ inputType :: Text+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Input where+ parseJSON (Object v) = Input <$> v .: "amount" <*> v .: "address" <*> v .: "type"+ parseJSON _ = mzero+++instance ToJSON Input where+ toJSON (Input {..}) = object ["amount" .= inputAmount, "address" .= inputAddress, "type" .= inputType]+ toEncoding (Input {..}) = pairs ("amount" .= inputAmount<>"address" .= inputAddress<>"type" .= inputType)+++data TransactionsElt = TransactionsElt {+ transactionsEltInput :: Input,+ transactionsEltMetadata :: (Maybe Value),+ transactionsEltConversion :: Text+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON TransactionsElt where+ parseJSON (Object v) = TransactionsElt <$> v .: "input" <*> v .:?? "metadata" <*> v .: "conversion"+ parseJSON _ = mzero+++instance ToJSON TransactionsElt where+ toJSON (TransactionsElt {..}) = object ["input" .= transactionsEltInput, "metadata" .= transactionsEltMetadata, "conversion" .= transactionsEltConversion]+ toEncoding (TransactionsElt {..}) = pairs ("input" .= transactionsEltInput<>"metadata" .= transactionsEltMetadata<>"conversion" .= transactionsEltConversion)+++data Data = Data {+ dataTransactions :: [TransactionsElt],+ dataVersion :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Data where+ parseJSON (Object v) = Data <$> v .: "transactions" <*> v .: "version"+ parseJSON _ = mzero+++instance ToJSON Data where+ toJSON (Data {..}) = object ["transactions" .= dataTransactions, "version" .= dataVersion]+ toEncoding (Data {..}) = pairs ("transactions" .= dataTransactions<>"version" .= dataVersion)+++data Transaction = Transaction {+ topLevelData :: Data,+ topLevelEntryhash :: Text,+ topLevelTimestamp :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Transaction where+ parseJSON (Object v) = Transaction <$> v .: "data" <*> v .: "entryhash" <*> v .: "timestamp"+ parseJSON _ = mzero+++instance ToJSON Transaction where+ toJSON (Transaction {..}) =+ object [ "data" .= topLevelData+ , "entryhash" .= topLevelEntryhash+ , "timestamp" .= topLevelTimestamp]+ toEncoding (Transaction {..}) =+ pairs ( "data" .= topLevelData+ <> "entryhash" .= topLevelEntryhash+ <>"timestamp" .= topLevelTimestamp)