-- | IPFS client functions
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}

module Blockfrost.Client.IPFS
  ( ipfsAdd
  , ipfsGateway
  , ipfsGetPin
  , ipfsListPins
  , ipfsListPins'
  , ipfsPin
  , ipfsRemovePin
  ) where

import Blockfrost.API
import Blockfrost.Client.Types
import Blockfrost.Types
import Control.Monad.Except
import Data.ByteString.Lazy (ByteString)
import Data.Text (Text)
import qualified Data.Text
import qualified System.Directory
import qualified System.FilePath

ipfsAdd_ :: MonadBlockfrost m => Project -> (ByteString, Form) -> m IPFSAdd
ipfsAdd_ :: Project -> (ByteString, Form) -> m IPFSAdd
ipfsAdd_ = IPFSAPI (AsClientT m) -> (ByteString, Form) -> m IPFSAdd
forall route.
IPFSAPI route
-> route
   :- (Summary "Add a file or directory to IPFS"
       :> (Description
             "You need to `/ipfs/pin/add` an object to avoid it being garbage collected. This usage is being counted in your user account quota."
           :> (Tag "IPFS \187 Add"
               :> ("add" :> (MultipartForm Tmp Form :> Post '[JSON] IPFSAdd)))))
_add (IPFSAPI (AsClientT m) -> (ByteString, Form) -> m IPFSAdd)
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> (ByteString, Form)
-> m IPFSAdd
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | Add a file or directory to IPFS
ipfsAdd :: (MonadError BlockfrostError m, MonadBlockfrost m) => FilePath -> m IPFSAdd
ipfsAdd :: FilePath -> m IPFSAdd
ipfsAdd FilePath
fp = do
  Bool
hasFile <- IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
System.Directory.doesFileExist FilePath
fp
  if Bool
hasFile
    then do
      IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
putStrLn (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Uploading: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
fp
      let fn :: Text
fn = FilePath -> Text
Data.Text.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
System.FilePath.takeBaseName FilePath
fp
      (Project -> m IPFSAdd) -> m IPFSAdd
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (\Project
proj -> Project -> (ByteString, Form) -> m IPFSAdd
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> (ByteString, Form) -> m IPFSAdd
ipfsAdd_ Project
proj (ByteString
"suchBoundary", (Text -> FilePath -> Form
Form Text
fn FilePath
fp)))
    else
      BlockfrostError -> m IPFSAdd
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (Text -> BlockfrostError
BlockfrostError Text
"No such file")

ipfsGateway_ :: MonadBlockfrost m => Project -> Text -> m IPFSData
ipfsGateway_ :: Project -> Text -> m IPFSData
ipfsGateway_ = IPFSAPI (AsClientT m) -> Text -> m IPFSData
forall route.
IPFSAPI route
-> route
   :- (Summary "Relay to an IPFS gateway"
       :> (Description
             "Retrieve an object from the IFPS gateway. (Useful if you do not want to rely on a public gateway, such as ``ipfs.blockfrost.dev`)."
           :> (Tag "IPFS \187 Gateway"
               :> ("gateway"
                   :> (Capture "IPFS_path" Text
                       :> Get '[PlainText, OctetStream] IPFSData)))))
_gateway (IPFSAPI (AsClientT m) -> Text -> m IPFSData)
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> Text
-> m IPFSData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | Fetch file via API
ipfsGateway :: MonadBlockfrost m => Text -> m IPFSData
ipfsGateway :: Text -> m IPFSData
ipfsGateway Text
x = (Project -> m IPFSData) -> m IPFSData
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (Project -> Text -> m IPFSData
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> Text -> m IPFSData
`ipfsGateway_` Text
x)

ipfsPin_ ::  MonadBlockfrost m => Project -> Text -> m IPFSPinChange
ipfsPin_ :: Project -> Text -> m IPFSPinChange
ipfsPin_ = IPFSAPI (AsClientT m) -> Text -> m IPFSPinChange
forall route.
IPFSAPI route
-> route
   :- (Summary "Pin an object"
       :> (Description
             "Pinned objects are counted in your user storage quota."
           :> (Tag "IPFS \187 Pins"
               :> ("pin"
                   :> ("add"
                       :> (Capture "IPFS_path" Text :> Post '[JSON] IPFSPinChange))))))
_pin (IPFSAPI (AsClientT m) -> Text -> m IPFSPinChange)
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> Text
-> m IPFSPinChange
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | Pin an object
ipfsPin :: MonadBlockfrost m => Text -> m IPFSPinChange
ipfsPin :: Text -> m IPFSPinChange
ipfsPin Text
x = (Project -> m IPFSPinChange) -> m IPFSPinChange
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (Project -> Text -> m IPFSPinChange
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> Text -> m IPFSPinChange
`ipfsPin_` Text
x)

ipfsListPins_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [IPFSPin]
ipfsListPins_ :: Project -> Paged -> SortOrder -> m [IPFSPin]
ipfsListPins_ = IPFSAPI (AsClientT m) -> Paged -> SortOrder -> m [IPFSPin]
forall route.
IPFSAPI route
-> route
   :- (Summary "List pinned objects"
       :> (Description "List objects pinned to local storage."
           :> (Tag "IPFS \187 Pins"
               :> ("pin"
                   :> ("list"
                       :> (Pagination :> (Sorting :> Get '[JSON] [IPFSPin])))))))
_listPins (IPFSAPI (AsClientT m) -> Paged -> SortOrder -> m [IPFSPin])
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> Paged
-> SortOrder
-> m [IPFSPin]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | List objects pinned to local storage
-- Allows custom paging and ordering using @Paged@ and @SortOrder@.
ipfsListPins' :: MonadBlockfrost m => Paged -> SortOrder -> m [IPFSPin]
ipfsListPins' :: Paged -> SortOrder -> m [IPFSPin]
ipfsListPins' Paged
pg SortOrder
s = (Project -> m [IPFSPin]) -> m [IPFSPin]
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (\Project
p -> Project -> Paged -> SortOrder -> m [IPFSPin]
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> Paged -> SortOrder -> m [IPFSPin]
ipfsListPins_ Project
p Paged
pg SortOrder
s)

-- | List objects pinned to local storage
ipfsListPins :: MonadBlockfrost m => m [IPFSPin]
ipfsListPins :: m [IPFSPin]
ipfsListPins = Paged -> SortOrder -> m [IPFSPin]
forall (m :: * -> *).
MonadBlockfrost m =>
Paged -> SortOrder -> m [IPFSPin]
ipfsListPins' Paged
forall a. Default a => a
def SortOrder
forall a. Default a => a
def

ipfsGetPin_ :: MonadBlockfrost m => Project -> Text -> m IPFSPin
ipfsGetPin_ :: Project -> Text -> m IPFSPin
ipfsGetPin_ = IPFSAPI (AsClientT m) -> Text -> m IPFSPin
forall route.
IPFSAPI route
-> route
   :- (Summary "Get pinned object details"
       :> (Description "Obtain inormation about specific pinned object."
           :> (Tag "IPFS \187 Pins"
               :> ("pin"
                   :> ("list"
                       :> (Capture "IPFS_path" Text :> Get '[JSON] IPFSPin))))))
_getPin (IPFSAPI (AsClientT m) -> Text -> m IPFSPin)
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> Text
-> m IPFSPin
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | Get pinned object details
ipfsGetPin :: MonadBlockfrost m => Text -> m IPFSPin
ipfsGetPin :: Text -> m IPFSPin
ipfsGetPin Text
x = (Project -> m IPFSPin) -> m IPFSPin
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (Project -> Text -> m IPFSPin
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> Text -> m IPFSPin
`ipfsGetPin_` Text
x)

ipfsRemovePin_ :: MonadBlockfrost m => Project -> Text -> m IPFSPinChange
ipfsRemovePin_ :: Project -> Text -> m IPFSPinChange
ipfsRemovePin_ = IPFSAPI (AsClientT m) -> Text -> m IPFSPinChange
forall route.
IPFSAPI route
-> route
   :- (Summary "Remove pinned object from local storage"
       :> (Description "Remove pinned object from local storage"
           :> (Tag "IPFS \187 Pins"
               :> ("pin"
                   :> ("remove"
                       :> (Capture "IPFS_path" Text :> Post '[JSON] IPFSPinChange))))))
_removePin (IPFSAPI (AsClientT m) -> Text -> m IPFSPinChange)
-> (Project -> IPFSAPI (AsClientT m))
-> Project
-> Text
-> m IPFSPinChange
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Project -> IPFSAPI (AsClientT m)
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> IPFSAPI (AsClientT m)
ipfsClient

-- | Remove pinned object from local storage
ipfsRemovePin :: MonadBlockfrost m => Text -> m IPFSPinChange
ipfsRemovePin :: Text -> m IPFSPinChange
ipfsRemovePin Text
x = (Project -> m IPFSPinChange) -> m IPFSPinChange
forall (m :: * -> *) a.
MonadBlockfrost m =>
(Project -> m a) -> m a
go (Project -> Text -> m IPFSPinChange
forall (m :: * -> *).
MonadBlockfrost m =>
Project -> Text -> m IPFSPinChange
`ipfsRemovePin_` Text
x)