Added Documentation Page for Client Api and pubsubCall

This commit is contained in:
amany9000 2019-09-16 17:10:17 +05:30
parent 3bfee6bb9b
commit 90034140b5
3 changed files with 126 additions and 17 deletions

View File

@ -10,6 +10,7 @@ Haskell Web3 Documentation
ethereum_node_api
ethereum_accounts
smart_contracts
ipfs_client_api
ens
.. toctree::

69
docs/ipfs_client_api.rst Normal file
View File

@ -0,0 +1,69 @@
Ipfs Client API
=================
As many Ethereum Dapps use Ipfs for data storage, an `Ipfs Client Api <https://docs.ipfs.io/reference/api/http/>`_ has been included.
.. note::
The api client is placed at ``Network.Ipfs.Api``. ``Network.Ipfs.Api.Ipfs`` exports the api functions.
Api Type
~~~~~~~~
The api type is defined in ``Network.Ipfs.Api.Api``. The client uses the `Servant <https://www.servant.dev>`_ Library.
.. code-block:: haskell
ipfsApi :: Proxy IpfsApi
ipfsApi = Proxy
_cat :<|> _ls ... :<|> _shutdown = client ipfsApi
The aeson definitions of the data types returned by the api functions are also present in ``Network.Ipfs.Api.Api``.
Monad Runner
~~~~~~~~~~~~
``Network.Ipfs.Api.Ipfs`` exports ``runIpfs`` monad runner and api functions.
.. code-block:: haskell
runIpfs' :: BaseUrl -> Ipfs a -> IO ()
runIpfs :: Ipfs a -> IO ()
runIpfs = runIpfs' (BaseUrl Http "localhost" 5001 "/api/v0")
.. note::
As you can see ``runIpfs`` uses the default BaseUrl at **http://localhost:5001/api/v0/** .
You can create a `BaseUrl <http://hackage.haskell.org/package/servant-client-core-0.16/docs/Servant-Client-Core-BaseUrl.html#t:BaseUrl>`_ instance for any other IPFS Api provider and pass it to **runIpfs'**.
Example of calling functions (Non-Stream) with runIpfs :
.. code-block:: haskell
main = I.runIpfs $ do
ret <- I.cat <Cid>
Cid should be of the type Text.
Call Functions
~~~~~~~~~~~~~~
There are three type of call functions:
================ =======================================================================
Type Description
================ =======================================================================
call Regular Call function.
multipartCall Call function for multipart/form-data.
streamCall Call function for Streams.
================ =======================================================================
As streamCall returns IO(), the API functions using it has to be called with **liftIO** (Specified in Function Documentation).
.. code-block:: haskell
main = I.runIpfs $ do
ret3 <- liftIO $ I.repoVerify

View File

@ -26,19 +26,23 @@ import Control.Monad.Reader
import Data.Aeson (decode)
import Data.Text as TextS
import qualified Data.Text.Encoding as TextS
import Data.Base58String.Bitcoin (fromBytes, toText)
import qualified Data.ByteString as BS'(ByteString, foldr)
import qualified Data.ByteArray.Encoding as Enc(convertFromBase, Base(..))
import qualified Data.ByteString.Lazy as BS (ByteString, fromStrict)
import Network.HTTP.Client as Net hiding (Proxy)
import Network.HTTP.Client.MultipartFormData
import Network.HTTP.Types (Status(..))
import Numeric (showInt)
import Servant.Client
import Servant.Types.SourceT (SourceT(..), foreach)
import qualified Servant.Client.Streaming as S
import Servant.Types.SourceT (SourceT, foreach)
import qualified Network.Ipfs.Api.Api as Api
import Network.Ipfs.Api.Multipart (AddObj)
import Network.Ipfs.Api.Stream (_ping, _dhtFindPeer, _dhtFindProvs, _dhtGet, _dhtProvide,
_dhtQuery, _logTail, _repoGc, _repoVerify, _refs, _refsLocal, _pubsubSubscribe)
_dhtQuery, _logTail, _repoGc, _repoVerify, _refs, _refsLocal,
_pubsubSubscribe, PubsubSubObj(..))
newtype IpfsT m a = IpfsT { unIpfs :: ReaderT (Manager, BaseUrl, String) (ExceptT ServantError m) a}
deriving ( Functor
@ -54,6 +58,8 @@ instance MonadTrans IpfsT where
type Ipfs a = IpfsT IO a
------------------------------------------- Monad Runners ---------------------------------------------------
-- | 'IpfsT' monad runner.
runIpfs' :: BaseUrl -> Ipfs a -> IO ()
runIpfs' url ipfs = do
@ -67,6 +73,9 @@ runIpfs' url ipfs = do
runIpfs :: Ipfs a -> IO ()
runIpfs = runIpfs' (BaseUrl Http "localhost" 5001 "/api/v0")
------------------------------------------- Call functions ---------------------------------------------------
-- | Regular Call function.
call :: (ClientM a) -> Ipfs a
call func = do
@ -74,7 +83,7 @@ call func = do
resp <- lift (runClientM func (mkClientEnv manager' url))
case resp of
Left l -> throwError l
Right r -> pure r
Right r -> pure r
-- | Call function for Streams.
streamCall :: Show a => S.ClientM (SourceT IO a) -> IO()
@ -84,6 +93,14 @@ streamCall func = do
Left err -> putStrLn $ "Error: " ++ show err
Right rs -> foreach fail print rs
-- | Call function for 'PubsubSubObj'.
pubsubCall :: S.ClientM (SourceT IO PubsubSubObj) -> IO()
pubsubCall func = do
manager' <- newManager defaultManagerSettings
S.withClientM func (S.mkClientEnv manager' (BaseUrl Http "localhost" 5001 "/api/v0")) $ \e -> case e of
Left err -> putStrLn $ "Error: " ++ show err
Right rs -> foreach fail printPubsub rs
-- | Call function for multipart/form-data.
multipartCall :: Text -> Text -> Ipfs (Net.Response BS.ByteString)
multipartCall funcUri filePath = do
@ -94,6 +111,28 @@ multipartCall funcUri filePath = do
where form = [ partFileSource "file" $ TextS.unpack filePath ]
------------------------------------------- Print Functions ---------------------------------------------------
-- | Print function for the Base64 decoded 'PubsubSubObj'.
printPubsub :: PubsubSubObj -> IO ()
printPubsub PubsubSubObj {mssgdata = mssg, from = sender, seqno = num, topicIDs = topic } =
print $ PubsubSubObj (fromB64 mssg) (fromB64toB58 sender) (fromB64' num) topic
where fromB64toB58 val = case Enc.convertFromBase Enc.Base64 (TextS.encodeUtf8 val) of
Left e -> TextS.pack $ "Invalid input: " ++ e
Right decoded -> toText $ fromBytes (decoded :: BS'.ByteString)
fromB64 val = case Enc.convertFromBase Enc.Base64 (TextS.encodeUtf8 val) of
Left e -> TextS.pack $ "Invalid input: " ++ e
Right decoded -> TextS.decodeUtf8 (decoded :: BS'.ByteString)
fromB64' val = case Enc.convertFromBase Enc.Base64 (TextS.encodeUtf8 val) of
Left e -> TextS.pack $ "Invalid input: " ++ e
Right decoded -> TextS.pack $ BS'.foldr showInt "" (decoded :: BS'.ByteString)
------------------------------------------- Ipfs functions ---------------------------------------------------
-- | Show IPFS object data.
cat :: Text -> Ipfs Api.CatReturnType
cat hash = call $ Api._cat hash
@ -115,11 +154,11 @@ get hash = do
do liftIO $ Tar.unpack "getResponseDirectory" . Tar.read $ BS.fromStrict $ TextS.encodeUtf8 ret
pure "The content has been stored in getResponseDirectory."
-- | List links (references) from an object.
-- | List links (references) from an object. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
refs :: Text -> IO ()
refs hash = streamCall $ _refs hash
-- | List all local references.
-- | List all local references. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
refsLocal :: IO ()
refsLocal = streamCall _refsLocal
@ -322,27 +361,27 @@ idPeer peerId = call $ Api._idPeer peerId
dns :: Text -> Ipfs Api.DnsObj
dns name = call $ Api._dns name
-- | Send echo request packets to IPFS hosts.
-- | Send echo request packets to IPFS hosts. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
ping :: Text -> IO ()
ping cid = streamCall $ _ping cid
-- | Find the multiaddresses associated with the given peerId.
-- | Find the multiaddresses associated with the given peerId. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
dhtFindPeer :: Text -> IO ()
dhtFindPeer peerId = streamCall $ _dhtFindPeer peerId
-- | Find peers that can provide a specific value, given a key.
-- | Find peers that can provide a specific value, given a key. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
dhtFindProvs :: Text -> IO ()
dhtFindProvs cid = streamCall $ _dhtFindProvs cid
-- | 'Given a key, query the routing system for its best value.
-- | 'Given a key, query the routing system for its best value. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
dhtGet :: Text -> IO ()
dhtGet cid = streamCall $ _dhtGet cid
-- | 'Announce to the network that you are providing given values.
-- | 'Announce to the network that you are providing given values. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
dhtProvide :: Text -> IO ()
dhtProvide cid = streamCall $ _dhtProvide cid
-- | Find the closest Peer IDs to a given peerID by querying the DHT.
-- | Find the closest Peer IDs to a given peerID by querying the DHT. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
dhtQuery :: Text -> IO ()
dhtQuery peerId = streamCall $ _dhtQuery peerId
@ -360,9 +399,9 @@ pubsubPublish topic mssg = do
call $ Api._pubsubPublish topic $ Just mssg
pure "The given message has been published."
-- | Subscribe to messages on a given topic.
-- | Subscribe to messages on a given topic. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
pubsubSubscribe :: Text -> IO ()
pubsubSubscribe topic = streamCall $ _pubsubSubscribe topic
pubsubSubscribe topic = pubsubCall $ _pubsubSubscribe topic
-- | List the logging subsystems.
logLs :: Ipfs Api.LogLsObj
@ -372,7 +411,7 @@ logLs = call Api._logLs
logLevel :: Text -> Text -> Ipfs Api.LogLevelObj
logLevel subsystem level = call $ Api._logLevel subsystem $ Just level
-- | Read the event log.
-- | Read the event log. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
logTail :: IO ()
logTail = streamCall _logTail
@ -384,11 +423,11 @@ repoVersion = call Api._repoVersion
repoFsck :: Ipfs Api.RepoFsckObj
repoFsck = call Api._repoFsck
-- | Perform a garbage collection sweep on the repo.
-- | Perform a garbage collection sweep on the repo. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
repoGc :: IO ()
repoGc = streamCall _repoGc
-- | Verify all blocks in repo are not corrupted.
-- | Verify all blocks in repo are not corrupted. Stream function, returns IO(), use liftIO while passing to 'runIpfs' or 'runIpfs''.
repoVerify :: IO ()
repoVerify = streamCall _repoVerify