\subsection{DHT (0x02)}

\begin{code}
{-# LANGUAGE StrictData #-}
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 :: Word32
dhtMagic = Word32
0x0159000D

sectionMagic :: Word16
sectionMagic :: Word16
sectionMagic =  Word16
0x11CE

newtype DHT = DHT [DhtSection]
    deriving (DHT -> DHT -> Bool
(DHT -> DHT -> Bool) -> (DHT -> DHT -> Bool) -> Eq DHT
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DHT -> DHT -> Bool
$c/= :: DHT -> DHT -> Bool
== :: DHT -> DHT -> Bool
$c== :: DHT -> DHT -> Bool
Eq, Int -> DHT -> ShowS
[DHT] -> ShowS
DHT -> String
(Int -> DHT -> ShowS)
-> (DHT -> String) -> ([DHT] -> ShowS) -> Show DHT
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DHT] -> ShowS
$cshowList :: [DHT] -> ShowS
show :: DHT -> String
$cshow :: DHT -> String
showsPrec :: Int -> DHT -> ShowS
$cshowsPrec :: Int -> DHT -> ShowS
Show, ReadPrec [DHT]
ReadPrec DHT
Int -> ReadS DHT
ReadS [DHT]
(Int -> ReadS DHT)
-> ReadS [DHT] -> ReadPrec DHT -> ReadPrec [DHT] -> Read DHT
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [DHT]
$creadListPrec :: ReadPrec [DHT]
readPrec :: ReadPrec DHT
$creadPrec :: ReadPrec DHT
readList :: ReadS [DHT]
$creadList :: ReadS [DHT]
readsPrec :: Int -> ReadS DHT
$creadsPrec :: Int -> ReadS DHT
Read)

instance Arbitrary DHT where
    arbitrary :: Gen DHT
arbitrary = [DhtSection] -> DHT
DHT ([DhtSection] -> DHT) -> Gen [DhtSection] -> Gen DHT
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [DhtSection]
forall a. Arbitrary a => Gen a
arbitrary

instance Binary DHT where
    get :: Get DHT
get = do
        Word32
magic <- Get Word32
Get.getWord32le
        Bool -> Get () -> Get ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word32
magic Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word32
dhtMagic) (Get () -> Get ()) -> Get () -> Get ()
forall a b. (a -> b) -> a -> b
$
            String -> Get ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get ()) -> String -> Get ()
forall a b. (a -> b) -> a -> b
$ String
"wrong magic number for DHT savedata: "
                String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
magic String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" != " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
dhtMagic

        [DhtSection] -> DHT
DHT ([DhtSection] -> DHT) -> Get [DhtSection] -> Get DHT
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get [DhtSection]
forall a. (Binary a, Show a) => Get [a]
Util.getList

    put :: DHT -> Put
put (DHT [DhtSection]
sections) = do
        Word32 -> Put
Put.putWord32le Word32
dhtMagic
        (DhtSection -> Put) -> [DhtSection] -> Put
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ DhtSection -> Put
forall t. Binary t => t -> Put
put [DhtSection]
sections


newtype DhtSection
    = DhtSectionNodes Nodes
    deriving (DhtSection -> DhtSection -> Bool
(DhtSection -> DhtSection -> Bool)
-> (DhtSection -> DhtSection -> Bool) -> Eq DhtSection
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DhtSection -> DhtSection -> Bool
$c/= :: DhtSection -> DhtSection -> Bool
== :: DhtSection -> DhtSection -> Bool
$c== :: DhtSection -> DhtSection -> Bool
Eq, Int -> DhtSection -> ShowS
[DhtSection] -> ShowS
DhtSection -> String
(Int -> DhtSection -> ShowS)
-> (DhtSection -> String)
-> ([DhtSection] -> ShowS)
-> Show DhtSection
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DhtSection] -> ShowS
$cshowList :: [DhtSection] -> ShowS
show :: DhtSection -> String
$cshow :: DhtSection -> String
showsPrec :: Int -> DhtSection -> ShowS
$cshowsPrec :: Int -> DhtSection -> ShowS
Show, ReadPrec [DhtSection]
ReadPrec DhtSection
Int -> ReadS DhtSection
ReadS [DhtSection]
(Int -> ReadS DhtSection)
-> ReadS [DhtSection]
-> ReadPrec DhtSection
-> ReadPrec [DhtSection]
-> Read DhtSection
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [DhtSection]
$creadListPrec :: ReadPrec [DhtSection]
readPrec :: ReadPrec DhtSection
$creadPrec :: ReadPrec DhtSection
readList :: ReadS [DhtSection]
$creadList :: ReadS [DhtSection]
readsPrec :: Int -> ReadS DhtSection
$creadsPrec :: Int -> ReadS DhtSection
Read)

instance Binary DhtSection where
    get :: Get DhtSection
get = do
        (Int
len, Word16
ty) <- Word16 -> Get (Int, Word16)
Util.getSectionHeader Word16
sectionMagic
        Int -> Get DhtSection -> Get DhtSection
forall a. Int -> Get a -> Get a
Get.isolate Int
len (Get DhtSection -> Get DhtSection)
-> Get DhtSection -> Get DhtSection
forall a b. (a -> b) -> a -> b
$ case Word16
ty of
            Word16
0x04 -> Nodes -> DhtSection
DhtSectionNodes (Nodes -> DhtSection) -> Get Nodes -> Get DhtSection
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Nodes
forall t. Binary t => Get t
get
            Word16
_    -> String -> Get DhtSection
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get DhtSection) -> String -> Get DhtSection
forall a b. (a -> b) -> a -> b
$ Word16 -> String
forall a. Show a => a -> String
show Word16
ty

    put :: DhtSection -> Put
put DhtSection
section = do
        let (Word16
ty, ByteString
bytes) = (Put -> ByteString) -> (Word16, Put) -> (Word16, ByteString)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second Put -> ByteString
Put.runPut (Word16, Put)
output

        Word16 -> Word32 -> Word16 -> Put
Util.putSectionHeader Word16
sectionMagic (Int64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Word32) -> Int64 -> Word32
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64
LBS.length ByteString
bytes) Word16
ty
        ByteString -> Put
Put.putLazyByteString ByteString
bytes

      where
        output :: (Word16, Put)
output = case DhtSection
section of
            DhtSectionNodes Nodes
x -> (Word16
0x04, Nodes -> Put
forall t. Binary t => t -> Put
put Nodes
x)

instance Arbitrary DhtSection where
    arbitrary :: Gen DhtSection
arbitrary = [Gen DhtSection] -> Gen DhtSection
forall a. [Gen a] -> Gen a
Gen.oneof
        [ Nodes -> DhtSection
DhtSectionNodes (Nodes -> DhtSection) -> Gen Nodes -> Gen DhtSection
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Nodes
forall a. Arbitrary a => Gen a
arbitrary
        ]

\end{code}