Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit 8736747

Browse files
committed
[CDEC-439] Matt's review
* use `These` from `these` package * `prop` in tests * comment why `4310` appears in the test
1 parent 726a154 commit 8736747

File tree

4 files changed

+62
-88
lines changed

4 files changed

+62
-88
lines changed

networking/cardano-sl-networking.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Library
6969
, safe-exceptions
7070
, stm
7171
, text
72+
, these
7273
, formatting
7374
, time
7475
, time-units

networking/src/Ntp/Client.hs

+17-18
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import qualified Data.List.NonEmpty as NE
3535
import Data.Semigroup (Last (..))
3636
import Data.Time.Units (Microsecond, TimeUnit, fromMicroseconds,
3737
toMicroseconds)
38+
import Data.These (These (..))
3839
import Data.Typeable (Typeable)
3940
import Formatting (sformat, shown, (%))
4041
import qualified Network.Socket as Socket
@@ -43,11 +44,10 @@ import qualified System.Wlog as Wlog
4344

4445
import Ntp.Packet (NtpOffset, NtpPacket (..), clockOffset,
4546
mkNtpPacket, ntpPacketSize)
46-
import Ntp.Util (AddrFamily (..), Addresses, EitherOrBoth (..),
47-
Sockets, WithAddrFamily (..), createAndBindSock,
48-
foldEitherOrBoth, logDebug, logInfo, logWarning, ntpTrace,
49-
resolveNtpHost, runWithAddrFamily, sendPacket,
50-
udpLocalAddresses)
47+
import Ntp.Util (AddrFamily (..), Addresses, Sockets,
48+
WithAddrFamily (..), createAndBindSock, foldThese,
49+
logDebug, logInfo, logWarning, ntpTrace, resolveNtpHost,
50+
runWithAddrFamily, sendPacket, udpLocalAddresses)
5151
import Pos.Util.Trace (traceWith)
5252

5353
data NtpStatus =
@@ -197,13 +197,13 @@ sendLoop cli addrs = do
197197
startReceive :: NtpClient -> IO ()
198198
startReceive cli =
199199
atomically (readTVar $ ncSockets cli) >>= \case
200-
EBBoth (Last (WithIPv6 sock_ipv6)) (Last (WithIPv4 sock_ipv4)) ->
200+
These (Last (WithIPv6 sock_ipv6)) (Last (WithIPv4 sock_ipv4)) ->
201201
loop IPv6 sock_ipv6
202202
`concurrently_`
203203
loop IPv4 sock_ipv4
204-
EBFirst (Last (WithIPv6 sock_ipv6)) ->
204+
This (Last (WithIPv6 sock_ipv6)) ->
205205
loop IPv6 sock_ipv6
206-
EBSecond (Last (WithIPv4 sock_ipv4)) ->
206+
That (Last (WithIPv4 sock_ipv4)) ->
207207
loop IPv4 sock_ipv4
208208
where
209209
-- Receive responses from the network and update NTP client state.
@@ -231,11 +231,11 @@ startReceive cli =
231231
Just sock -> do
232232
atomically $ modifyTVar' (ncSockets cli) (\s -> s <> sock)
233233
case sock of
234-
EBFirst (Last sock_)
234+
This (Last sock_)
235235
-> loop addressFamily $ runWithAddrFamily sock_
236-
EBSecond (Last sock_)
236+
That (Last sock_)
237237
-> loop addressFamily $ runWithAddrFamily sock_
238-
EBBoth _ _
238+
These _ _
239239
-> error "NtpClient: startReceive: impossible"
240240

241241
-- Compute the clock offset based on current time and record it in the NTP
@@ -274,7 +274,7 @@ spawnNtpClient settings ncStatus = do
274274
where
275275
closeSockets :: Sockets -> IO ()
276276
closeSockets sockets = do
277-
foldEitherOrBoth $ bimap fn fn sockets
277+
foldThese $ bimap fn fn sockets
278278
logInfo "stopped"
279279

280280
fn :: Last (WithAddrFamily t Socket.Socket) -> IO ()
@@ -298,19 +298,18 @@ withNtpClient ntpSettings = do
298298
-- Try to create IPv4 and IPv6 socket.
299299
mkSockets :: NtpClientSettings -> IO Sockets
300300
mkSockets settings =
301-
(doMkSockets) `catch` handleIOException >>= \case
301+
doMkSockets `catch` handleIOException >>= \case
302302
Option (Just sock) -> pure sock
303303
Option Nothing -> do
304304
logWarning "Couldn't create both IPv4 and IPv6 socket, retrying in 5 sec..."
305305
threadDelay 5000000
306306
mkSockets settings
307307
where
308308
doMkSockets :: IO (Option Sockets)
309-
doMkSockets =
310-
do
311-
addrs <- udpLocalAddresses
312-
(<>) <$> (Option <$> createAndBindSock IPv4 addrs)
313-
<*> (Option <$> createAndBindSock IPv6 addrs)
309+
doMkSockets = do
310+
addrs <- udpLocalAddresses
311+
(<>) <$> (Option <$> createAndBindSock IPv4 addrs)
312+
<*> (Option <$> createAndBindSock IPv6 addrs)
314313

315314
handleIOException :: IOException -> IO (Option Sockets)
316315
handleIOException e = do

networking/src/Ntp/Util.hs

+35-64
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ module Ntp.Util
1919
, createAndBindSock
2020
, udpLocalAddresses
2121

22-
, EitherOrBoth (..)
23-
, foldEitherOrBoth
24-
, pairEitherOrBoth
22+
, foldThese
23+
, pairThese
2524

2625
, ntpTrace
2726
, logDebug
@@ -41,6 +40,7 @@ import Data.List (find)
4140
import Data.Semigroup (First (..), Last (..), Option (..),
4241
Semigroup (..))
4342
import Data.Text (Text)
43+
import Data.These (These (..))
4444
import Formatting (sformat, shown, (%))
4545
import Network.Socket (AddrInfo,
4646
AddrInfoFlag (AI_ADDRCONFIG, AI_PASSIVE),
@@ -99,70 +99,41 @@ getAddrFamily (WithIPv6 _) = IPv6
9999
getAddrFamily (WithIPv4 _) = IPv4
100100

101101
-- |
102-
-- Keep either of the two types or both.
103-
data EitherOrBoth a b
104-
= EBFirst !a
105-
| EBSecond !b
106-
| EBBoth !a !b
107-
deriving (Show, Eq, Ord)
108-
109-
instance Bifunctor EitherOrBoth where
110-
bimap f _ (EBFirst a) = EBFirst $ f a
111-
bimap _ g (EBSecond b) = EBSecond $ g b
112-
bimap f g (EBBoth a b) = EBBoth (f a) (g b)
113-
114-
-- |
115-
-- @'EitehrOrBoth'@ is an (associative) semigroup whenever both @a@ and @b@ are.
116-
instance (Semigroup a, Semigroup b) => Semigroup (EitherOrBoth a b) where
117-
118-
EBFirst a <> EBFirst a' = EBFirst (a <> a')
119-
EBFirst a <> EBSecond b = EBBoth a b
120-
EBFirst a <> EBBoth a' b = EBBoth (a <> a') b
121-
122-
EBSecond b <> EBFirst a = EBBoth a b
123-
EBSecond b <> EBSecond b' = EBSecond (b <> b')
124-
EBSecond b <> EBBoth a b' = EBBoth a (b <> b')
125-
126-
EBBoth a b <> EBFirst a' = EBBoth (a <> a') b
127-
EBBoth a b <> EBSecond b' = EBBoth a (b <> b')
128-
EBBoth a b <> EBBoth a' b' = EBBoth (a <> a') (b <> b')
129-
130-
-- |
131-
-- Note that the composition of `foldEitherOrBoth . bimap f g` is a proof that
132-
-- @'EitherOrBoth a b@ is the [free
102+
-- Note that the composition of `foldThese . bimap f g` is a proof that
103+
-- @'These a b@ is the [free
133104
-- product](https://en.wikipedia.org/wiki/Free_product) of two semigroups @a@
134105
-- and @b@.
135-
foldEitherOrBoth
106+
foldThese
136107
:: Semigroup a
137-
=> EitherOrBoth a a
108+
=> These a a
138109
-> a
139-
foldEitherOrBoth (EBFirst a) = a
140-
foldEitherOrBoth (EBSecond a) = a
141-
foldEitherOrBoth (EBBoth a1 a2) = a1 <> a2
142-
143-
pairEitherOrBoth
144-
:: EitherOrBoth a b
145-
-> EitherOrBoth x y
146-
-> Maybe (EitherOrBoth (a, x) (b, y))
147-
pairEitherOrBoth (EBBoth a b) (EBBoth x y) = Just $ EBBoth (a, x) (b, y)
148-
pairEitherOrBoth (EBFirst a) (EBFirst x) = Just $ EBFirst (a, x)
149-
pairEitherOrBoth (EBBoth a _) (EBFirst x) = Just $ EBFirst (a, x)
150-
pairEitherOrBoth (EBFirst a) (EBBoth x _) = Just $ EBFirst (a, x)
151-
pairEitherOrBoth (EBSecond b) (EBSecond y) = Just $ EBSecond (b, y)
152-
pairEitherOrBoth (EBBoth _ b) (EBSecond y) = Just $ EBSecond (b, y)
153-
pairEitherOrBoth (EBSecond b) (EBBoth _ y) = Just $ EBSecond (b, y)
154-
pairEitherOrBoth _ _ = Nothing
110+
foldThese (This a) = a
111+
foldThese (That a) = a
112+
foldThese (These a1 a2) = a1 <> a2
113+
114+
pairThese
115+
:: These a b
116+
-> These x y
117+
-> Maybe (These (a, x) (b, y))
118+
pairThese (These a b) (These x y) = Just $ These (a, x) (b, y)
119+
pairThese (This a) (This x) = Just $ This (a, x)
120+
pairThese (These a _) (This x) = Just $ This (a, x)
121+
pairThese (This a) (These x _) = Just $ This (a, x)
122+
pairThese (That b) (That y) = Just $ That (b, y)
123+
pairThese (These _ b) (That y) = Just $ That (b, y)
124+
pairThese (That b) (These _ y) = Just $ That (b, y)
125+
pairThese _ _ = Nothing
155126

156127
-- |
157128
-- Store created sockets. If system supports IPv6 and IPv4 we create socket for
158129
-- IPv4 and IPv6. Otherwise only one.
159-
type Sockets = EitherOrBoth
130+
type Sockets = These
160131
(Last (WithAddrFamily 'IPv6 Socket))
161132
(Last (WithAddrFamily 'IPv4 Socket))
162133

163134
-- |
164135
-- A counter part of @'Ntp.Client.Sockets'@ data type.
165-
type Addresses = EitherOrBoth
136+
type Addresses = These
166137
(First (WithAddrFamily 'IPv6 SockAddr))
167138
(First (WithAddrFamily 'IPv4 SockAddr))
168139

@@ -190,7 +161,7 @@ resolveHost host = do
190161
let g :: First (WithAddrFamily t SockAddr) -> [SockAddr]
191162
g (First a) = [runWithAddrFamily a]
192163
addrs :: [SockAddr]
193-
addrs = foldEitherOrBoth . bimap g g $ addr
164+
addrs = foldThese . bimap g g $ addr
194165
in logInfo $ sformat ("Host "%shown%" is resolved: "%shown)
195166
host addrs
196167
return maddr
@@ -199,9 +170,9 @@ resolveHost host = do
199170
fn :: AddrInfo -> Option Addresses
200171
fn addr = case Socket.addrFamily addr of
201172
Socket.AF_INET6 ->
202-
Option $ Just $ EBFirst $ First $ (WithIPv6 $ Socket.addrAddress addr)
173+
Option $ Just $ This $ First $ (WithIPv6 $ Socket.addrAddress addr)
203174
Socket.AF_INET ->
204-
Option $ Just $ EBSecond $ First $ (WithIPv4 $ Socket.addrAddress addr)
175+
Option $ Just $ That $ First $ (WithIPv4 $ Socket.addrAddress addr)
205176
_ -> mempty
206177

207178
resolveNtpHost :: String -> IO (Maybe Addresses)
@@ -240,8 +211,8 @@ createAndBindSock addressFamily addrs =
240211
sformat ("Created socket (family/addr): "%shown%"/"%shown)
241212
(addrFamily addr) (addrAddress addr)
242213
case addressFamily of
243-
IPv6 -> return $ EBFirst $ Last $ (WithIPv6 sock)
244-
IPv4 -> return $ EBSecond $ Last $ (WithIPv4 sock)
214+
IPv6 -> return $ This $ Last $ (WithIPv6 sock)
215+
IPv4 -> return $ That $ Last $ (WithIPv4 sock)
245216

246217
udpLocalAddresses :: IO [AddrInfo]
247218
udpLocalAddresses = do
@@ -268,7 +239,7 @@ sendTo
268239
-> Addresses
269240
-- ^ addresses to send to
270241
-> IO ()
271-
sendTo sock bs addr = case fmap (foldEitherOrBoth . bimap fn fn) $ pairEitherOrBoth sock addr of
242+
sendTo sock bs addr = case fmap (foldThese . bimap fn fn) $ pairThese sock addr of
272243
Just io -> io
273244
Nothing -> throw NoMatchingSocket
274245
where
@@ -309,11 +280,11 @@ sendPacket sock packet addrs = do
309280
case (addr, addressFamily) of
310281
-- try to send the packet to the other address in case the current
311282
-- system does not support IPv4/6.
312-
(EBBoth _ r, IPv6) -> do
283+
(These _ r, IPv6) -> do
313284
logDebug $ sformat ("sendPacket re-sending using: "%shown) (runWithAddrFamily $ getFirst r)
314-
sendPacket sock packet [EBSecond r]
315-
(EBBoth l _, IPv4) -> do
285+
sendPacket sock packet [That r]
286+
(These l _, IPv4) -> do
316287
logDebug $ sformat ("sendPacket re-sending using: "%shown) (runWithAddrFamily $ getFirst l)
317-
sendPacket sock packet [EBFirst l]
288+
sendPacket sock packet [This l]
318289
_ ->
319290
logDebug "sendPacket: not retrying"

networking/test/Test/NtpSpec.hs

+9-6
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import Data.Binary (decodeOrFail, encode)
88
import Data.Time.Units (Microsecond, fromMicroseconds)
99
import Data.Word (Word32)
1010

11-
import Test.Hspec (Spec, describe, it)
12-
import Test.QuickCheck (Arbitrary (..), Gen, counterexample, property,
11+
import Test.Hspec (Spec, describe)
12+
import Test.Hspec.QuickCheck (prop)
13+
import Test.QuickCheck (Arbitrary (..), Gen, counterexample,
1314
sized, suchThat, (.&&.), (===))
1415

1516
import Ntp.Packet (NtpOffset (..), NtpPacket (..), clockOffsetPure,
@@ -81,17 +82,19 @@ instance Arbitrary NtpMicrosecond where
8182
spec :: Spec
8283
spec = describe "NtpClient" $ do
8384
describe "clockOffsetPure" $ do
84-
it "should return clock offset" $ property $ \(NtpPacketWithOffset {..}) ->
85+
prop "should return clock offset" $ \(NtpPacketWithOffset {..}) ->
8586
let offset = clockOffsetPure npoNtpPacket npoDestinationTime
8687
in npoOffset === offset
8788
describe "realMcsToNtp" $ do
88-
it "should be right inverse of ntpToRealMcs" $ property $ \(NtpMicrosecond x) ->
89+
prop "should be right inverse of ntpToRealMcs" $ \(NtpMicrosecond x) ->
8990
x === uncurry ntpToRealMcs (realMcsToNtp x)
90-
it "should be left inverse of ntpToRealMcs" $ property $ \(NtpTime x@(sec, frac)) ->
91+
prop "should be left inverse of ntpToRealMcs" $ \(NtpTime x@(sec, frac)) ->
9192
let (sec', frac') = realMcsToNtp (uncurry ntpToRealMcs x)
93+
-- Each npt fraction unit correspond to 232 picoseconds, there are
94+
-- 4310 of them in a millisecond.
9295
in sec === sec' .&&. frac `div` 4310 === frac' `div` 4310
9396
describe "NptPacket" $ do
94-
it "should serialize and deserialize" $ property $ \(ArbitraryNtpPacket ntpPacket) ->
97+
prop "should serialize and deserialize" $ \(ArbitraryNtpPacket ntpPacket) ->
9598
let bs = encode ntpPacket
9699
in do
97100
case decodeOrFail bs of

0 commit comments

Comments
 (0)