module Network.IPFS.Peer
( all
, rawList
, connect
, connectRetry
, getExternalAddress
) where
import qualified RIO.Text as Text
import qualified RIO.List as List
import qualified Net.IPv4 as IPv4
import Text.Regex
import Network.IPFS.Prelude hiding (all)
import qualified Network.IPFS.Internal.UTF8 as UTF8
import qualified Network.IPFS.Types as IPFS
import qualified Network.IPFS.Process.Error as Process
import Network.IPFS.Local.Class as IPFS
import Network.IPFS.Peer.Error as IPFS.Peer
import Network.IPFS.Peer.Types
import Network.IPFS.Info.Types
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
-> Int
-> m (Either IPFS.Peer.Error ())
connectRetry peer (-1) = 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.:]*)/"
extractIPfromPeerAddress :: String -> Maybe String
extractIPfromPeerAddress peer = matchRegex peerAddressRe peer >>= List.headMaybe
isExternalIPv4 :: Text -> Bool
isExternalIPv4 ip = maybe False not isReserved
where
isReserved :: Maybe Bool
isReserved = do
ipAddress <- extractIPfromPeerAddress <| Text.unpack ip
normalized <- IPv4.decode <| Text.pack ipAddress
return <| IPv4.reserved normalized
filterExternalPeers :: [Peer] -> [Peer]
filterExternalPeers = filter (isExternalIPv4 . peer)
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