\subsection{DHT (0x02)}

\begin{code}
module Network.Tox.SaveData.DHT (DHT) where

import           Control.Arrow              (second)
import           Control.Monad              (when)
import           Data.Binary                (Binary (..))
import           Data.Binary.Get            (Get)
import qualified Data.Binary.Get            as Get
import           Data.Binary.Put            (Put)
import qualified Data.Binary.Put            as Put
import qualified Data.ByteString.Lazy       as LBS
import           Data.Word                  (Word16, Word32)
import           Network.Tox.SaveData.Nodes (Nodes)
import qualified Network.Tox.SaveData.Util  as Util
import           Test.QuickCheck.Arbitrary  (Arbitrary, arbitrary)
import qualified Test.QuickCheck.Gen        as Gen

\end{code}

This section contains a list of DHT-related sections.

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{4}    & \texttt{uint32\_t} (0x159000D) \\
  \texttt{?}    & List of DHT sections \\
\end{tabular}

\subsubsection{DHT Sections}

Every DHT section has the following structure:

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{4}    & \texttt{uint32\_t} Length of this section \\
  \texttt{2}    & \texttt{uint16\_t} DHT section type \\
  \texttt{2}    & \texttt{uint16\_t} (0x11CE) \\
  \texttt{?}    & DHT section \\
\end{tabular}

DHT section types:

\begin{tabular}{l|l}
  Name  & Value \\
  \hline
  Nodes & 0x04 \\
\end{tabular}

\paragraph{Nodes (0x04)}

This section contains a list of nodes. These nodes are used to quickly reconnect
to the DHT after a Tox client is restarted.

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{?}    & List of nodes \\
\end{tabular}

The structure of a node is the same as \texttt{Node Info}. Note: this means
that the integers stored in these nodes are stored in Big Endian as well.

\begin{code}

dhtMagic :: Word32
dhtMagic = 0x0159000D

sectionMagic :: Word16
sectionMagic =  0x11CE

newtype DHT = DHT [DhtSection]
    deriving (Eq, Show, Read)

instance Arbitrary DHT where
    arbitrary = DHT <$> arbitrary

instance Binary DHT where
    get = do
        magic <- Get.getWord32le
        when (magic /= dhtMagic) $
            fail $ "wrong magic number for DHT savedata: "
                ++ show magic ++ " != " ++ show dhtMagic

        DHT <$> Util.getList

    put (DHT sections) = do
        Put.putWord32le dhtMagic
        mapM_ put sections


newtype DhtSection
    = DhtSectionNodes Nodes
    deriving (Eq, Show, Read)

instance Binary DhtSection where
    get = do
        (len, ty) <- Util.getSectionHeader sectionMagic
        Get.isolate len $ case ty of
            0x04 -> DhtSectionNodes <$> get
            _    -> fail $ show ty

    put section = do
        let (ty, bytes) = second Put.runPut output

        Util.putSectionHeader sectionMagic (fromIntegral $ LBS.length bytes) ty
        Put.putLazyByteString bytes

      where
        output = case section of
            DhtSectionNodes x -> (0x04, put x)

instance Arbitrary DhtSection where
    arbitrary = Gen.oneof
        [ DhtSectionNodes <$> arbitrary
        ]

\end{code}