The Close List and the Search Entries are termed the \texttt{Node Lists} of
the DHT State.

\begin{code}
{-# LANGUAGE StrictData #-}
module Network.Tox.DHT.NodeList where

import           Control.Applicative           (Const (..), getConst)
import           Control.Monad                 (guard)
import           Data.Maybe                    (listToMaybe)
import           Data.Monoid                   (Dual (..), Endo (..), appEndo,
                                                getDual)

import           Network.Tox.Crypto.Key        (PublicKey)
import           Network.Tox.DHT.ClientList    (ClientList)
import qualified Network.Tox.DHT.ClientList    as ClientList
import           Network.Tox.DHT.Distance      (Distance)
import           Network.Tox.DHT.KBuckets      (KBuckets)
import qualified Network.Tox.DHT.KBuckets      as KBuckets
import           Network.Tox.NodeInfo.NodeInfo (NodeInfo)
import           Network.Tox.Time              (Timestamp)

class NodeList l where
  addNode :: Timestamp -> NodeInfo -> l -> l

  removeNode :: PublicKey -> l -> l

  viable :: NodeInfo -> l -> Bool

  baseKey :: l -> PublicKey

  traverseClientLists ::
    Applicative f => (ClientList -> f ClientList) -> l -> f l

  -- | 'closeNodes pub' returns the (pub',node) pairs of the Node List in
  -- increasing order of distance of pub' from pub.
  closeNodes :: PublicKey -> l -> [(Distance, NodeInfo)]

  -- | copied from Data.Traversable.foldMapDefault
  foldMapClientLists :: Monoid m => (ClientList -> m) -> l -> m
  foldMapClientLists ClientList -> m
f = Const m l -> m
forall a k (b :: k). Const a b -> a
getConst (Const m l -> m) -> (l -> Const m l) -> l -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ClientList -> Const m ClientList) -> l -> Const m l
forall l (f :: * -> *).
(NodeList l, Applicative f) =>
(ClientList -> f ClientList) -> l -> f l
traverseClientLists (m -> Const m ClientList
forall k a (b :: k). a -> Const a b
Const (m -> Const m ClientList)
-> (ClientList -> m) -> ClientList -> Const m ClientList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClientList -> m
f)

  -- | copied from Data.Foldable.foldl
  foldlClientLists :: (a -> ClientList -> a) -> a -> l -> a
  foldlClientLists a -> ClientList -> a
f a
z l
t =
    Endo a -> a -> a
forall a. Endo a -> a -> a
appEndo (Dual (Endo a) -> Endo a
forall a. Dual a -> a
getDual ((ClientList -> Dual (Endo a)) -> l -> Dual (Endo a)
forall l m. (NodeList l, Monoid m) => (ClientList -> m) -> l -> m
foldMapClientLists (Endo a -> Dual (Endo a)
forall a. a -> Dual a
Dual (Endo a -> Dual (Endo a))
-> (ClientList -> Endo a) -> ClientList -> Dual (Endo a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a) -> Endo a
forall a. (a -> a) -> Endo a
Endo ((a -> a) -> Endo a)
-> (ClientList -> a -> a) -> ClientList -> Endo a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> ClientList -> a) -> ClientList -> a -> a
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> ClientList -> a
f) l
t)) a
z

  nodeListList :: l -> [NodeInfo]
  nodeListList = (ClientList -> [NodeInfo]) -> l -> [NodeInfo]
forall l m. (NodeList l, Monoid m) => (ClientList -> m) -> l -> m
foldMapClientLists ClientList -> [NodeInfo]
ClientList.nodeInfos

  foldNodes :: (a -> NodeInfo -> a) -> a -> l -> a
  foldNodes = (a -> ClientList -> a) -> a -> l -> a
forall l a. NodeList l => (a -> ClientList -> a) -> a -> l -> a
foldlClientLists ((a -> ClientList -> a) -> a -> l -> a)
-> ((a -> NodeInfo -> a) -> a -> ClientList -> a)
-> (a -> NodeInfo -> a)
-> a
-> l
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> NodeInfo -> a) -> a -> ClientList -> a
forall a. (a -> NodeInfo -> a) -> a -> ClientList -> a
ClientList.foldNodes

  lookupPublicKey :: PublicKey -> l -> Maybe NodeInfo
  lookupPublicKey PublicKey
publicKey l
list = do
    (Distance
dist,NodeInfo
node) <- [(Distance, NodeInfo)] -> Maybe (Distance, NodeInfo)
forall a. [a] -> Maybe a
listToMaybe ([(Distance, NodeInfo)] -> Maybe (Distance, NodeInfo))
-> [(Distance, NodeInfo)] -> Maybe (Distance, NodeInfo)
forall a b. (a -> b) -> a -> b
$ PublicKey -> l -> [(Distance, NodeInfo)]
forall l. NodeList l => PublicKey -> l -> [(Distance, NodeInfo)]
closeNodes PublicKey
publicKey l
list
    Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Distance
dist Distance -> Distance -> Bool
forall a. Eq a => a -> a -> Bool
== Distance
forall a. Monoid a => a
mempty)
    NodeInfo -> Maybe NodeInfo
forall a. a -> Maybe a
Just NodeInfo
node

instance NodeList ClientList where
  addNode :: Timestamp -> NodeInfo -> ClientList -> ClientList
addNode = Timestamp -> NodeInfo -> ClientList -> ClientList
ClientList.addNode
  removeNode :: PublicKey -> ClientList -> ClientList
removeNode = PublicKey -> ClientList -> ClientList
ClientList.removeNode
  viable :: NodeInfo -> ClientList -> Bool
viable = NodeInfo -> ClientList -> Bool
ClientList.viable
  baseKey :: ClientList -> PublicKey
baseKey = ClientList -> PublicKey
ClientList.baseKey
  traverseClientLists :: (ClientList -> f ClientList) -> ClientList -> f ClientList
traverseClientLists = (ClientList -> f ClientList) -> ClientList -> f ClientList
forall a. a -> a
id
  closeNodes :: PublicKey -> ClientList -> [(Distance, NodeInfo)]
closeNodes = PublicKey -> ClientList -> [(Distance, NodeInfo)]
ClientList.closeNodes

instance NodeList KBuckets where
  addNode :: Timestamp -> NodeInfo -> KBuckets -> KBuckets
addNode = Timestamp -> NodeInfo -> KBuckets -> KBuckets
KBuckets.addNode
  removeNode :: PublicKey -> KBuckets -> KBuckets
removeNode = PublicKey -> KBuckets -> KBuckets
KBuckets.removeNode
  viable :: NodeInfo -> KBuckets -> Bool
viable = NodeInfo -> KBuckets -> Bool
KBuckets.viable
  baseKey :: KBuckets -> PublicKey
baseKey = KBuckets -> PublicKey
KBuckets.baseKey
  traverseClientLists :: (ClientList -> f ClientList) -> KBuckets -> f KBuckets
traverseClientLists = (ClientList -> f ClientList) -> KBuckets -> f KBuckets
forall (f :: * -> *).
Applicative f =>
(ClientList -> f ClientList) -> KBuckets -> f KBuckets
KBuckets.traverseClientLists
  closeNodes :: PublicKey -> KBuckets -> [(Distance, NodeInfo)]
closeNodes = PublicKey -> KBuckets -> [(Distance, NodeInfo)]
KBuckets.closeNodes
\end{code}