ipfs-1.2.0.0: library/Network/IPFS/Add.hs
module Network.IPFS.Add
( addRaw
, addFile
, addPath
, addDir
) where
import Network.IPFS.Local.Class as IPFS
import Network.IPFS.Prelude hiding (link)
import Data.ByteString.Lazy.Char8 as CL
import qualified System.FilePath.Glob as Glob
import qualified RIO.ByteString.Lazy as Lazy
import RIO.Directory
import RIO.FilePath
import qualified RIO.List as List
import qualified Network.IPFS.Internal.UTF8 as UTF8
import Network.IPFS.Add.Error as IPFS.Add
import Network.IPFS.DAG.Link as DAG.Link
import Network.IPFS.DAG.Node.Types as DAG
import Network.IPFS.Types as IPFS
import Network.IPFS.DAG as DAG
addRaw ::
MonadLocalIPFS m
=> Lazy.ByteString
-> m (Either IPFS.Add.Error IPFS.CID)
addRaw raw =
IPFS.runLocal ["add", "-HQ"] raw >>= \case
Right result ->
case CL.lines result of
[cid] ->
return . Right . mkCID . UTF8.stripN 1 . decodeUtf8Lenient $ Lazy.toStrict cid
bad ->
return . Left . UnexpectedOutput $ UTF8.textShow bad
Left err ->
return . Left . UnknownAddErr $ UTF8.textShow err
addFile ::
MonadLocalIPFS m
=> Lazy.ByteString
-> IPFS.Name
-> m (Either IPFS.Add.Error (IPFS.SparseTree, IPFS.CID))
addFile raw name =
IPFS.runLocal opts raw >>= \case
Right result ->
case CL.lines result of
[inner, outer] ->
let
sparseTree = Directory [(Hash rootCID, fileWrapper)]
fileWrapper = Directory [(fileName, Content fileCID)]
rootCID = CID . decodeUtf8Lenient $ Lazy.toStrict outer
fileCID = CID . UTF8.stripN 1 . decodeUtf8Lenient $ Lazy.toStrict inner
fileName = Key name
in
return $ Right (sparseTree, rootCID)
bad ->
return . Left . UnexpectedOutput $ UTF8.textShow bad
Left err ->
return . Left . UnknownAddErr $ UTF8.textShow err
where
opts = [ "add"
, "-wq"
, "--stdin-name"
, unName name
]
addPath ::
MonadLocalIPFS m
=> FilePath
-> m (Either IPFS.Add.Error CID)
addPath path = IPFS.runLocal ["add", "-HQ", path] "" >>= pure . \case
Right result ->
case CL.lines result of
[cid] -> Right . mkCID . UTF8.stripN 1 $ UTF8.textShow cid
bad -> Left . UnexpectedOutput $ UTF8.textShow bad
Left err ->
Left . UnknownAddErr $ UTF8.textShow err
addDir ::
( MonadIO m
, MonadLocalIPFS m
)
=> IPFS.Ignored
-> FilePath
-> m (Either IPFS.Add.Error IPFS.CID)
addDir ignored path = doesFileExist path >>= \case
True -> addPath path
False -> walkDir ignored path
walkDir ::
( MonadIO m
, MonadLocalIPFS m
)
=> IPFS.Ignored
-> FilePath
-> m (Either IPFS.Add.Error IPFS.CID)
walkDir ignored path = do
files <- listDirectory path
let
toAdd = removeIgnored ignored files
reducer = foldResults path ignored
seed = Right $ Node
{ dataBlock = "CAE="
, links = []
}
foldM reducer seed toAdd >>= \case
Left err -> return $ Left err
Right node -> DAG.putNode node
foldResults ::
( MonadIO m
, MonadLocalIPFS m
)
=> FilePath
-> IPFS.Ignored
-> Either IPFS.Add.Error Node
-> FilePath
-> m (Either IPFS.Add.Error Node)
foldResults _ _ (Left err) _ = return $ Left err
foldResults path ignored (Right node) filename = do
addDir ignored (path </> filename) >>= \case
Left err -> return $ Left err
Right cid ->
DAG.Link.create cid (IPFS.Name filename) >>= \case
Left err -> return . Left $ RecursiveAddErr err
Right link ->
return $ Right node { links = link: links node }
removeIgnored :: IPFS.Ignored -> [FilePath] -> [FilePath]
removeIgnored ignored files = List.filter (not . matchesAny ignored) files
matchesAny :: IPFS.Ignored -> FilePath -> Bool
matchesAny globs path = List.any (\x -> Glob.match x path) globs