-- | Core types for the Kademlia DHT.
--
-- Defines the DHT keyspace (256-bit SHA-256 keys), routing table entry
-- structure, and protocol constants (k=20, alpha=10).
module Network.LibP2P.DHT.Types
  ( DHTKey (..)
  , BucketEntry (..)
  , ConnectionType (..)
  , InsertResult (..)
  , kValue
  , alphaValue
  , numBuckets
  ) where

import Data.ByteString (ByteString)
import Data.Time (UTCTime)
import Network.LibP2P.Crypto.PeerId (PeerId)
import Network.LibP2P.Multiaddr.Multiaddr (Multiaddr)

-- | 256-bit key in the DHT keyspace (always exactly 32 bytes, SHA-256 output).
newtype DHTKey = DHTKey ByteString
  deriving (DHTKey -> DHTKey -> Bool
(DHTKey -> DHTKey -> Bool)
-> (DHTKey -> DHTKey -> Bool) -> Eq DHTKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DHTKey -> DHTKey -> Bool
== :: DHTKey -> DHTKey -> Bool
$c/= :: DHTKey -> DHTKey -> Bool
/= :: DHTKey -> DHTKey -> Bool
Eq, Eq DHTKey
Eq DHTKey =>
(DHTKey -> DHTKey -> Ordering)
-> (DHTKey -> DHTKey -> Bool)
-> (DHTKey -> DHTKey -> Bool)
-> (DHTKey -> DHTKey -> Bool)
-> (DHTKey -> DHTKey -> Bool)
-> (DHTKey -> DHTKey -> DHTKey)
-> (DHTKey -> DHTKey -> DHTKey)
-> Ord DHTKey
DHTKey -> DHTKey -> Bool
DHTKey -> DHTKey -> Ordering
DHTKey -> DHTKey -> DHTKey
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: DHTKey -> DHTKey -> Ordering
compare :: DHTKey -> DHTKey -> Ordering
$c< :: DHTKey -> DHTKey -> Bool
< :: DHTKey -> DHTKey -> Bool
$c<= :: DHTKey -> DHTKey -> Bool
<= :: DHTKey -> DHTKey -> Bool
$c> :: DHTKey -> DHTKey -> Bool
> :: DHTKey -> DHTKey -> Bool
$c>= :: DHTKey -> DHTKey -> Bool
>= :: DHTKey -> DHTKey -> Bool
$cmax :: DHTKey -> DHTKey -> DHTKey
max :: DHTKey -> DHTKey -> DHTKey
$cmin :: DHTKey -> DHTKey -> DHTKey
min :: DHTKey -> DHTKey -> DHTKey
Ord, Int -> DHTKey -> ShowS
[DHTKey] -> ShowS
DHTKey -> String
(Int -> DHTKey -> ShowS)
-> (DHTKey -> String) -> ([DHTKey] -> ShowS) -> Show DHTKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DHTKey -> ShowS
showsPrec :: Int -> DHTKey -> ShowS
$cshow :: DHTKey -> String
show :: DHTKey -> String
$cshowList :: [DHTKey] -> ShowS
showList :: [DHTKey] -> ShowS
Show)

-- | Replication parameter: each k-bucket holds up to k peers.
kValue :: Int
kValue :: Int
kValue = Int
20

-- | Concurrency parameter for iterative lookups.
alphaValue :: Int
alphaValue :: Int
alphaValue = Int
10

-- | Number of buckets (one per bit of the 256-bit keyspace).
numBuckets :: Int
numBuckets :: Int
numBuckets = Int
256

-- | Connection status of a peer (from DHT protobuf spec).
data ConnectionType
  = NotConnected  -- ^ 0: no connection, no extra info
  | Connected     -- ^ 1: live connection
  | CanConnect    -- ^ 2: recently connected
  | CannotConnect -- ^ 3: recently failed to connect
  deriving (Int -> ConnectionType -> ShowS
[ConnectionType] -> ShowS
ConnectionType -> String
(Int -> ConnectionType -> ShowS)
-> (ConnectionType -> String)
-> ([ConnectionType] -> ShowS)
-> Show ConnectionType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ConnectionType -> ShowS
showsPrec :: Int -> ConnectionType -> ShowS
$cshow :: ConnectionType -> String
show :: ConnectionType -> String
$cshowList :: [ConnectionType] -> ShowS
showList :: [ConnectionType] -> ShowS
Show, ConnectionType -> ConnectionType -> Bool
(ConnectionType -> ConnectionType -> Bool)
-> (ConnectionType -> ConnectionType -> Bool) -> Eq ConnectionType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ConnectionType -> ConnectionType -> Bool
== :: ConnectionType -> ConnectionType -> Bool
$c/= :: ConnectionType -> ConnectionType -> Bool
/= :: ConnectionType -> ConnectionType -> Bool
Eq, Int -> ConnectionType
ConnectionType -> Int
ConnectionType -> [ConnectionType]
ConnectionType -> ConnectionType
ConnectionType -> ConnectionType -> [ConnectionType]
ConnectionType
-> ConnectionType -> ConnectionType -> [ConnectionType]
(ConnectionType -> ConnectionType)
-> (ConnectionType -> ConnectionType)
-> (Int -> ConnectionType)
-> (ConnectionType -> Int)
-> (ConnectionType -> [ConnectionType])
-> (ConnectionType -> ConnectionType -> [ConnectionType])
-> (ConnectionType -> ConnectionType -> [ConnectionType])
-> (ConnectionType
    -> ConnectionType -> ConnectionType -> [ConnectionType])
-> Enum ConnectionType
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: ConnectionType -> ConnectionType
succ :: ConnectionType -> ConnectionType
$cpred :: ConnectionType -> ConnectionType
pred :: ConnectionType -> ConnectionType
$ctoEnum :: Int -> ConnectionType
toEnum :: Int -> ConnectionType
$cfromEnum :: ConnectionType -> Int
fromEnum :: ConnectionType -> Int
$cenumFrom :: ConnectionType -> [ConnectionType]
enumFrom :: ConnectionType -> [ConnectionType]
$cenumFromThen :: ConnectionType -> ConnectionType -> [ConnectionType]
enumFromThen :: ConnectionType -> ConnectionType -> [ConnectionType]
$cenumFromTo :: ConnectionType -> ConnectionType -> [ConnectionType]
enumFromTo :: ConnectionType -> ConnectionType -> [ConnectionType]
$cenumFromThenTo :: ConnectionType
-> ConnectionType -> ConnectionType -> [ConnectionType]
enumFromThenTo :: ConnectionType
-> ConnectionType -> ConnectionType -> [ConnectionType]
Enum, ConnectionType
ConnectionType -> ConnectionType -> Bounded ConnectionType
forall a. a -> a -> Bounded a
$cminBound :: ConnectionType
minBound :: ConnectionType
$cmaxBound :: ConnectionType
maxBound :: ConnectionType
Bounded)

-- | A single entry in a k-bucket.
data BucketEntry = BucketEntry
  { BucketEntry -> PeerId
entryPeerId   :: !PeerId
  , BucketEntry -> DHTKey
entryKey      :: !DHTKey        -- ^ Cached SHA-256 of peer ID
  , BucketEntry -> [Multiaddr]
entryAddrs    :: ![Multiaddr]
  , BucketEntry -> UTCTime
entryLastSeen :: !UTCTime
  , BucketEntry -> ConnectionType
entryConnType :: !ConnectionType
  } deriving (Int -> BucketEntry -> ShowS
[BucketEntry] -> ShowS
BucketEntry -> String
(Int -> BucketEntry -> ShowS)
-> (BucketEntry -> String)
-> ([BucketEntry] -> ShowS)
-> Show BucketEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BucketEntry -> ShowS
showsPrec :: Int -> BucketEntry -> ShowS
$cshow :: BucketEntry -> String
show :: BucketEntry -> String
$cshowList :: [BucketEntry] -> ShowS
showList :: [BucketEntry] -> ShowS
Show, BucketEntry -> BucketEntry -> Bool
(BucketEntry -> BucketEntry -> Bool)
-> (BucketEntry -> BucketEntry -> Bool) -> Eq BucketEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BucketEntry -> BucketEntry -> Bool
== :: BucketEntry -> BucketEntry -> Bool
$c/= :: BucketEntry -> BucketEntry -> Bool
/= :: BucketEntry -> BucketEntry -> Bool
Eq)

-- | Result of attempting to insert a peer into the routing table.
data InsertResult
  = Inserted          -- ^ Peer was added to the bucket
  | Updated           -- ^ Existing peer was moved to tail (most recently seen)
  | BucketFull !PeerId -- ^ Bucket is full; returns LRS peer ID for pinging
  deriving (Int -> InsertResult -> ShowS
[InsertResult] -> ShowS
InsertResult -> String
(Int -> InsertResult -> ShowS)
-> (InsertResult -> String)
-> ([InsertResult] -> ShowS)
-> Show InsertResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InsertResult -> ShowS
showsPrec :: Int -> InsertResult -> ShowS
$cshow :: InsertResult -> String
show :: InsertResult -> String
$cshowList :: [InsertResult] -> ShowS
showList :: [InsertResult] -> ShowS
Show, InsertResult -> InsertResult -> Bool
(InsertResult -> InsertResult -> Bool)
-> (InsertResult -> InsertResult -> Bool) -> Eq InsertResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InsertResult -> InsertResult -> Bool
== :: InsertResult -> InsertResult -> Bool
$c/= :: InsertResult -> InsertResult -> Bool
/= :: InsertResult -> InsertResult -> Bool
Eq)