ipfs-1.3.0.1: library/Network/IPFS/Peer.hs
module Network.IPFS.Peer
( all
, rawList
, connect
, connectRetry
, getExternalAddress
) where
import qualified RIO.List as List
import qualified RIO.Text as Text
import qualified Network.IP.Addr as Addr
import Text.Regex
import qualified Network.IPFS.Internal.UTF8 as UTF8
import Network.IPFS.Prelude hiding (all)
import Network.IPFS.Info.Types
import Network.IPFS.Local.Class as IPFS
import Network.IPFS.Peer.Error as IPFS.Peer
import Network.IPFS.Peer.Types
import qualified Network.IPFS.Process.Error as Process
import qualified Network.IPFS.Types as IPFS
all :: MonadLocalIPFS m => m (Either IPFS.Peer.Error [IPFS.Peer])
all = rawList <&> \case
Right raw -> case UTF8.encode raw of
Left _ -> Left . DecodeFailure $ show raw
Right text -> Right $ IPFS.Peer <$> Text.lines text
Left err -> Left . UnknownErr $ UTF8.textShow err
rawList :: MonadLocalIPFS m => m (Either Process.Error Process.RawMessage)
rawList = IPFS.runLocal ["bootstrap", "list"] ""
connect :: MonadLocalIPFS m => Peer -> m (Either IPFS.Peer.Error ())
connect peer@(Peer peerID) = IPFS.runLocal ["swarm", "connect"] (UTF8.textToLazyBS peerID) >>= pure . \case
Left _ -> Left $ CannotConnect peer
Right _ -> Right ()
connectRetry :: MonadLocalIPFS m => Peer -> Natural -> m (Either IPFS.Peer.Error ())
connectRetry peer 0 = return . Left $ CannotConnect peer
connectRetry peer tries = connect peer >>= \case
Right _ -> return $ Right ()
Left _err -> connectRetry peer (tries - 1)
peerAddressRe :: Regex
peerAddressRe = mkRegex "^/ip[46]/([a-zA-Z0-9.:]*)/"
-- | Retrieve just the ip address from a peer address
extractIPfromPeerAddress :: String -> Maybe String
extractIPfromPeerAddress peer = matchRegex peerAddressRe peer >>= List.headMaybe
-- | True if a given peer address is externally accessable
isExternalIPv4 :: Text -> Bool
isExternalIPv4 ip = maybe False not isReserved
where
isReserved :: Maybe Bool
isReserved = do
ipAddress <- extractIPfromPeerAddress $ Text.unpack ip
normalized <- readMaybe ipAddress
return (Addr.ip4Range normalized == Addr.ReservedIP4)
-- | Filter a list of peers to include only the externally accessable addresses
filterExternalPeers :: [Peer] -> [Peer]
filterExternalPeers = filter (isExternalIPv4 . peer)
-- | Get all external ipfs peer addresses
getExternalAddress :: MonadLocalIPFS m => m (Either IPFS.Peer.Error [Peer])
getExternalAddress =
IPFS.runLocal ["id"] "" >>= \case
Left err ->
return . Left . UnknownErr $ UTF8.textShow err
Right raw ->
raw
|> decode
|> maybe [] addresses
|> Right . filterExternalPeers
|> pure