ipfs-1.0.0: library/Network/IPFS/Add.hs
module Network.IPFS.Add
( addRaw
, addFile
, addPath
, addDir
) where
import Network.IPFS.Prelude hiding (link)
import Network.IPFS.Local.Class as IPFS
import Data.ByteString.Lazy.Char8 as CL
import Data.List as List
import qualified System.FilePath.Glob as Glob
import RIO.Directory
import RIO.FilePath
import qualified RIO.ByteString.Lazy as Lazy
import qualified Network.IPFS.Internal.UTF8 as UTF8
import Network.IPFS.Add.Error as IPFS.Add
import Network.IPFS.Types as IPFS
import Network.IPFS.DAG.Node.Types as DAG
import Network.IPFS.DAG.Link as DAG.Link
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] ->
cid
|> UTF8.textShow
|> UTF8.stripN 1
|> mkCID
|> Right
|> return
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 <| UTF8.textShow outer
fileCID = CID . UTF8.stripN 1 <| UTF8.textShow 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