{-# LANGUAGE LambdaCase #-}

module Ouroboros.Network.PeerSelection.PeerSharing.Codec
  ( encodePortNumber
  , decodePortNumber
  , encodeRemoteAddress
  , decodeRemoteAddress
  ) where

import Codec.CBOR.Decoding qualified as CBOR
import Codec.CBOR.Encoding qualified as CBOR

import Network.Socket (PortNumber, SockAddr (..))
import Ouroboros.Network.NodeToNode.Version (NodeToNodeVersion (..))

encodePortNumber :: PortNumber -> CBOR.Encoding
encodePortNumber :: PortNumber -> Encoding
encodePortNumber = Word16 -> Encoding
CBOR.encodeWord16 (Word16 -> Encoding)
-> (PortNumber -> Word16) -> PortNumber -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PortNumber -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral

decodePortNumber :: CBOR.Decoder s PortNumber
decodePortNumber :: forall s. Decoder s PortNumber
decodePortNumber = Word16 -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> PortNumber) -> Decoder s Word16 -> Decoder s PortNumber
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder s Word16
forall s. Decoder s Word16
CBOR.decodeWord16


-- | This encoder should be faithful to the PeerSharing
-- CDDL Specification.
--
-- See the network design document for more details
---
-- /Invariant:/ not a unix socket address type.
---
encodeRemoteAddress :: NodeToNodeVersion -> SockAddr -> CBOR.Encoding
encodeRemoteAddress :: NodeToNodeVersion -> SockAddr -> Encoding
encodeRemoteAddress NodeToNodeVersion
_ = \case
  SockAddrInet PortNumber
pn HostAddress
w -> Word -> Encoding
CBOR.encodeListLen Word
3
                    Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> Word -> Encoding
CBOR.encodeWord Word
0
                    Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> HostAddress -> Encoding
CBOR.encodeWord32 HostAddress
w
                    Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PortNumber -> Encoding
encodePortNumber PortNumber
pn
  SockAddrInet6 PortNumber
pn HostAddress
_ (HostAddress
w1, HostAddress
w2, HostAddress
w3, HostAddress
w4) HostAddress
_ -> Word -> Encoding
CBOR.encodeListLen Word
6
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> Word -> Encoding
CBOR.encodeWord Word
1
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> HostAddress -> Encoding
CBOR.encodeWord32 HostAddress
w1
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> HostAddress -> Encoding
CBOR.encodeWord32 HostAddress
w2
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> HostAddress -> Encoding
CBOR.encodeWord32 HostAddress
w3
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> HostAddress -> Encoding
CBOR.encodeWord32 HostAddress
w4
                                        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PortNumber -> Encoding
encodePortNumber PortNumber
pn
  SockAddrUnix String
_ -> String -> Encoding
forall a. HasCallStack => String -> a
error String
"Should never be encoding a SockAddrUnix!"

-- | This decoder should be faithful to the PeerSharing
-- CDDL Specification.
--
-- See the network design document for more details
--
decodeRemoteAddress :: NodeToNodeVersion -> CBOR.Decoder s SockAddr
decodeRemoteAddress :: forall s. NodeToNodeVersion -> Decoder s SockAddr
decodeRemoteAddress NodeToNodeVersion
_ = do
  _ <- Decoder s Int
forall s. Decoder s Int
CBOR.decodeListLen
  tok <- CBOR.decodeWord
  case tok of
    Word
0 -> do
      w <- Decoder s HostAddress
forall s. Decoder s HostAddress
CBOR.decodeWord32
      pn <- decodePortNumber
      return (SockAddrInet pn w)
    Word
1 -> do
      w1 <- Decoder s HostAddress
forall s. Decoder s HostAddress
CBOR.decodeWord32
      w2 <- CBOR.decodeWord32
      w3 <- CBOR.decodeWord32
      w4 <- CBOR.decodeWord32
      pn <- decodePortNumber
      return (SockAddrInet6 pn 0 (w1, w2, w3, w4) 0)
    Word
_ -> String -> Decoder s SockAddr
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Serialise.decode.SockAddr unexpected tok " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word -> String
forall a. Show a => a -> String
show Word
tok)