{-# LANGUAGE DeriveFunctor   #-}
{-# LANGUAGE LambdaCase      #-}
{-# LANGUAGE NamedFieldPuns  #-}
{-# LANGUAGE RecordWildCards #-}

{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

module Ouroboros.Network.PeerSelection.EstablishedPeers
  ( EstablishedPeers
  , empty
  , toMap
  , toSet
  , readyPeers
  , size
  , sizeReady
  , member
  , insert
  , delete
  , deletePeers
    -- * Special operations
  , setCurrentTime
  , setActivateTimes
    -- ** Tracking when we can (re)activate
  , minActivateTime
    -- ** Tracking when we can peer share
  , minPeerShareTime
  , setPeerShareTime
  , availableForPeerShare
  , invariant
  ) where

import           Prelude

import qualified Data.List as List
import           Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import           Data.OrdPSQ (OrdPSQ)
import qualified Data.OrdPSQ as PSQ
import           Data.Semigroup (Min (..))
import           Data.Set (Set)
import qualified Data.Set as Set

import           Control.Exception (assert)
import           Control.Monad.Class.MonadTime.SI


-------------------------------
-- Established peer set representation
--

-- | The set of established peers. To a first approximation it can be thought of
-- as a 'Set' of @peeraddr@.
--
-- It has one special feature:
--
--  * It tracks which peers we are permitted to ask for peers now, or for peers
--    we cannot issue share requests with now the time at which we would next be
--    allowed to do so.
--
data EstablishedPeers peeraddr peerconn = EstablishedPeers {
    -- | Peers which are either ready to become active or are active.
    --
    forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers              :: !(Map peeraddr peerconn),

    -- | The subset of established peers that we would be allowed to peer share
    -- with now. This is because we have not peer shared with them recently.
    --
    -- NOTE that this is the set of available peers one would be able to perform
    -- peer sharing _now_, it doesn't mean they are 100% eligible. This will
    -- depend on other factors like the peer's 'PeerSharing' value.
    --
    forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare :: !(Set peeraddr),

    -- | The subset of established peers that we cannot peer share with now. It
    -- keeps track of the next time we are allowed to peer share with them.
    --
    forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes    :: !(OrdPSQ peeraddr Time ()),


    -- | Peers which are not ready to become active.
    forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes     :: !(OrdPSQ peeraddr Time ())
  }
  deriving (Int -> EstablishedPeers peeraddr peerconn -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
Int -> EstablishedPeers peeraddr peerconn -> ShowS
forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
[EstablishedPeers peeraddr peerconn] -> ShowS
forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
EstablishedPeers peeraddr peerconn -> String
showList :: [EstablishedPeers peeraddr peerconn] -> ShowS
$cshowList :: forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
[EstablishedPeers peeraddr peerconn] -> ShowS
show :: EstablishedPeers peeraddr peerconn -> String
$cshow :: forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
EstablishedPeers peeraddr peerconn -> String
showsPrec :: Int -> EstablishedPeers peeraddr peerconn -> ShowS
$cshowsPrec :: forall peeraddr peerconn.
(Show peeraddr, Show peerconn) =>
Int -> EstablishedPeers peeraddr peerconn -> ShowS
Show, forall a b.
a -> EstablishedPeers peeraddr b -> EstablishedPeers peeraddr a
forall a b.
(a -> b)
-> EstablishedPeers peeraddr a -> EstablishedPeers peeraddr b
forall peeraddr a b.
a -> EstablishedPeers peeraddr b -> EstablishedPeers peeraddr a
forall peeraddr a b.
(a -> b)
-> EstablishedPeers peeraddr a -> EstablishedPeers peeraddr b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b.
a -> EstablishedPeers peeraddr b -> EstablishedPeers peeraddr a
$c<$ :: forall peeraddr a b.
a -> EstablishedPeers peeraddr b -> EstablishedPeers peeraddr a
fmap :: forall a b.
(a -> b)
-> EstablishedPeers peeraddr a -> EstablishedPeers peeraddr b
$cfmap :: forall peeraddr a b.
(a -> b)
-> EstablishedPeers peeraddr a -> EstablishedPeers peeraddr b
Functor)


empty :: EstablishedPeers peeraddr perconn
empty :: forall peeraddr perconn. EstablishedPeers peeraddr perconn
empty = EstablishedPeers {
      allPeers :: Map peeraddr perconn
allPeers              = forall k a. Map k a
Map.empty,
      availableForPeerShare :: Set peeraddr
availableForPeerShare = forall a. Set a
Set.empty,
      nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes    = forall k p v. OrdPSQ k p v
PSQ.empty,
      nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes     = forall k p v. OrdPSQ k p v
PSQ.empty
    }


invariant :: Ord peeraddr
          => EstablishedPeers peeraddr peerconn
          -> Bool
invariant :: forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Bool
invariant EstablishedPeers {Map peeraddr peerconn
Set peeraddr
OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
availableForPeerShare :: Set peeraddr
allPeers :: Map peeraddr peerconn
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
..} =
       -- The combo of the peer share set + psq = the whole set of peers
       Set peeraddr
availableForPeerShare
    forall a. Semigroup a => a -> a -> a
<> forall a. Ord a => [a] -> Set a
Set.fromList (forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextPeerShareTimes)
    forall a. Eq a => a -> a -> Bool
== forall k a. Map k a -> Set k
Map.keysSet Map peeraddr peerconn
allPeers
       -- The peer share set and psq do not overlap
 Bool -> Bool -> Bool
&& forall a. Set a -> Bool
Set.null
      (forall a. Ord a => Set a -> Set a -> Set a
Set.intersection
         Set peeraddr
availableForPeerShare
        (forall a. Ord a => [a] -> Set a
Set.fromList (forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextPeerShareTimes)))
     -- nextActivateTimes is a subset of allPeers
 Bool -> Bool -> Bool
&&  forall a. Ord a => [a] -> Set a
Set.fromList (forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextActivateTimes)
     forall a. Ord a => Set a -> Set a -> Bool
`Set.isSubsetOf`
     forall k a. Map k a -> Set k
Map.keysSet Map peeraddr peerconn
allPeers


-- | /O(1)/
toMap :: EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
toMap :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
toMap = forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers

-- | /O(n)/
toSet :: EstablishedPeers peeraddr peerconn -> Set peeraddr
toSet :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
toSet = forall k a. Map k a -> Set k
Map.keysSet forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers


-- | Map of established peers that are either active or ready to be promoted
-- to active.
--
-- /O(n log m), for n not-ready peers, and m established peers/
--
readyPeers :: Ord peeraddr
           => EstablishedPeers peeraddr peerconn
           -> Set peeraddr
readyPeers :: forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Set peeraddr
readyPeers EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers, OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes } =
    forall k p v a. (k -> p -> v -> a -> a) -> a -> OrdPSQ k p v -> a
PSQ.fold'
      (\peeraddr
peeraddr Time
_ ()
_ -> forall a. Ord a => a -> Set a -> Set a
Set.delete peeraddr
peeraddr)
      (forall k a. Map k a -> Set k
Map.keysSet Map peeraddr peerconn
allPeers)
      OrdPSQ peeraddr Time ()
nextActivateTimes


-- | The number of established peers. The size of 'allPeers'
--
-- /O(1)/
--
size :: EstablishedPeers peeraddr peerconn -> Int
size :: forall peeraddr peerconn. EstablishedPeers peeraddr peerconn -> Int
size EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers } = forall k a. Map k a -> Int
Map.size Map peeraddr peerconn
allPeers


-- | The number of ready peers. The size of 'readyPeers'
--
-- /O(1)/
--
sizeReady :: EstablishedPeers peeraddr peerconn -> Int
sizeReady :: forall peeraddr peerconn. EstablishedPeers peeraddr peerconn -> Int
sizeReady EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers, OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes } =
    forall k a. Map k a -> Int
Map.size Map peeraddr peerconn
allPeers forall a. Num a => a -> a -> a
- forall k p v. OrdPSQ k p v -> Int
PSQ.size OrdPSQ peeraddr Time ()
nextActivateTimes


member :: Ord peeraddr => peeraddr -> EstablishedPeers peeraddr peerconn -> Bool
member :: forall peeraddr peerconn.
Ord peeraddr =>
peeraddr -> EstablishedPeers peeraddr peerconn -> Bool
member peeraddr
peeraddr = forall k a. Ord k => k -> Map k a -> Bool
Map.member peeraddr
peeraddr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers


-- | Insert a peer into 'EstablishedPeers'.
--
insert :: Ord peeraddr
       => peeraddr
       -> peerconn
       -> EstablishedPeers peeraddr peerconn
       -> EstablishedPeers peeraddr peerconn
insert :: forall peeraddr peerconn.
Ord peeraddr =>
peeraddr
-> peerconn
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
insert peeraddr
peeraddr peerconn
peerconn ep :: EstablishedPeers peeraddr peerconn
ep@EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers, Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare } =
   EstablishedPeers peeraddr peerconn
ep { allPeers :: Map peeraddr peerconn
allPeers = forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert peeraddr
peeraddr peerconn
peerconn Map peeraddr peerconn
allPeers,

        -- The sets tracking peers ready for peer share need to be updated with any
        -- /fresh/ peers, but any already present are ignored since they are
        -- either already in these sets or they are in the corresponding PSQs,
        -- for which we also preserve existing info.
        availableForPeerShare :: Set peeraddr
availableForPeerShare =
          if forall k a. Ord k => k -> Map k a -> Bool
Map.member peeraddr
peeraddr Map peeraddr peerconn
allPeers
             then Set peeraddr
availableForPeerShare
             else forall a. Ord a => a -> Set a -> Set a
Set.insert peeraddr
peeraddr Set peeraddr
availableForPeerShare
      }

delete :: Ord peeraddr
       => peeraddr
       -> EstablishedPeers peeraddr peerconn
       -> EstablishedPeers peeraddr peerconn
delete :: forall peeraddr peerconn.
Ord peeraddr =>
peeraddr
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
delete peeraddr
peeraddr es :: EstablishedPeers peeraddr peerconn
es@EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers
                                    , Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare
                                    , OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes
                                    , OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes
                                    } =
    EstablishedPeers peeraddr peerconn
es { allPeers :: Map peeraddr peerconn
allPeers              = forall k a. Ord k => k -> Map k a -> Map k a
Map.delete peeraddr
peeraddr Map peeraddr peerconn
allPeers,
         availableForPeerShare :: Set peeraddr
availableForPeerShare = forall a. Ord a => a -> Set a -> Set a
Set.delete peeraddr
peeraddr Set peeraddr
availableForPeerShare,
         nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes    = forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete peeraddr
peeraddr OrdPSQ peeraddr Time ()
nextPeerShareTimes,
         nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes     = forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete peeraddr
peeraddr OrdPSQ peeraddr Time ()
nextActivateTimes
       }



-- | Bulk delete of peers from 'EstablishedPeers.
--
deletePeers :: Ord peeraddr
            => Set peeraddr
            -> EstablishedPeers peeraddr peerconn
            -> EstablishedPeers peeraddr peerconn
deletePeers :: forall peeraddr peerconn.
Ord peeraddr =>
Set peeraddr
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
deletePeers Set peeraddr
peeraddrs es :: EstablishedPeers peeraddr peerconn
es@EstablishedPeers { Map peeraddr peerconn
allPeers :: Map peeraddr peerconn
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers,
                                            Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare,
                                            OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes,
                                            OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes
                                          } =
    EstablishedPeers peeraddr peerconn
es { allPeers :: Map peeraddr peerconn
allPeers              = forall k a. Ord k => Map k a -> Set k -> Map k a
Map.withoutKeys Map peeraddr peerconn
allPeers Set peeraddr
peeraddrs,
         availableForPeerShare :: Set peeraddr
availableForPeerShare = forall a. Ord a => Set a -> Set a -> Set a
Set.difference Set peeraddr
availableForPeerShare Set peeraddr
peeraddrs,
         nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes    =
           forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete) OrdPSQ peeraddr Time ()
nextPeerShareTimes Set peeraddr
peeraddrs,
         nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes     =
           forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete) OrdPSQ peeraddr Time ()
nextActivateTimes Set peeraddr
peeraddrs
       }


--
-- Time managment
--

setCurrentTime :: Ord peeraddr
               => Time
               -> EstablishedPeers peeraddr peerconn
               -> EstablishedPeers peeraddr peerconn
setCurrentTime :: forall peeraddr peerconn.
Ord peeraddr =>
Time
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
setCurrentTime Time
now ep :: EstablishedPeers peeraddr peerconn
ep@EstablishedPeers { OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes
                                       , OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes
                                       }
 -- Efficient check for the common case of there being nothing to do:
    | Just (Min Time
t) <- (forall {a} {a} {c} {d}. (a, a, c, d) -> Min a
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextPeerShareTimes)
                   forall a. Semigroup a => a -> a -> a
<> (forall {a} {a} {c} {d}. (a, a, c, d) -> Min a
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextActivateTimes)
    , Time
t forall a. Ord a => a -> a -> Bool
> Time
now
    = EstablishedPeers peeraddr peerconn
ep
  where
    f :: (a, a, c, d) -> Min a
f (a
_,a
t,c
_,d
_) = forall a. a -> Min a
Min a
t

setCurrentTime Time
now ep :: EstablishedPeers peeraddr peerconn
ep@EstablishedPeers { OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes
                                       , Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare
                                       , OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes
                                       } =
  let ep' :: EstablishedPeers peeraddr peerconn
ep' = EstablishedPeers peeraddr peerconn
ep { nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes    = OrdPSQ peeraddr Time ()
nextPeerShareTimes'
               , availableForPeerShare :: Set peeraddr
availableForPeerShare = Set peeraddr
availableForPeerShare'
               , nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes     = OrdPSQ peeraddr Time ()
nextActivateTimes'
               }
    in forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Bool
invariant EstablishedPeers peeraddr peerconn
ep') EstablishedPeers peeraddr peerconn
ep'
  where
    ([(peeraddr, Time, ())]
nowAvailableForPeerShare, OrdPSQ peeraddr Time ()
nextPeerShareTimes') =
      forall k p v.
(Ord k, Ord p) =>
p -> OrdPSQ k p v -> ([(k, p, v)], OrdPSQ k p v)
PSQ.atMostView Time
now OrdPSQ peeraddr Time ()
nextPeerShareTimes

    availableForPeerShare' :: Set peeraddr
availableForPeerShare' =
         Set peeraddr
availableForPeerShare
      forall a. Semigroup a => a -> a -> a
<> forall a. Ord a => [a] -> Set a
Set.fromList [ peeraddr
peeraddr | (peeraddr
peeraddr, Time
_, ()
_) <- [(peeraddr, Time, ())]
nowAvailableForPeerShare ]

    ([(peeraddr, Time, ())]
_, OrdPSQ peeraddr Time ()
nextActivateTimes') = forall k p v.
(Ord k, Ord p) =>
p -> OrdPSQ k p v -> ([(k, p, v)], OrdPSQ k p v)
PSQ.atMostView Time
now OrdPSQ peeraddr Time ()
nextActivateTimes


minActivateTime :: Ord peeraddr
                => EstablishedPeers peeraddr peerconn
                -> Maybe Time
minActivateTime :: forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Maybe Time
minActivateTime EstablishedPeers { OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes }
  | Just (peeraddr
_k, Time
t, ()
_, OrdPSQ peeraddr Time ()
_psq) <- forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextActivateTimes
  = forall a. a -> Maybe a
Just Time
t

  | Bool
otherwise
  = forall a. Maybe a
Nothing


setActivateTimes :: Ord peeraddr
                 => Map peeraddr Time
                 -> EstablishedPeers peeraddr peerconn
                 -> EstablishedPeers peeraddr peerconn
setActivateTimes :: forall peeraddr peerconn.
Ord peeraddr =>
Map peeraddr Time
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
setActivateTimes Map peeraddr Time
times EstablishedPeers peeraddr peerconn
ep | forall k a. Map k a -> Bool
Map.null Map peeraddr Time
times = EstablishedPeers peeraddr peerconn
ep
setActivateTimes Map peeraddr Time
times ep :: EstablishedPeers peeraddr peerconn
ep@EstablishedPeers { OrdPSQ peeraddr Time ()
nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextActivateTimes } =
    let ep' :: EstablishedPeers peeraddr peerconn
ep' = EstablishedPeers peeraddr peerconn
ep { nextActivateTimes :: OrdPSQ peeraddr Time ()
nextActivateTimes =
                     forall a k b. (a -> k -> b -> a) -> a -> Map k b -> a
Map.foldlWithKey'
                       (\OrdPSQ peeraddr Time ()
psq peeraddr
peeraddr Time
time ->
                             forall a b. (a, b) -> b
snd forall a b. (a -> b) -> a -> b
$
                             forall k p v b.
(Ord k, Ord p) =>
(Maybe (p, v) -> (b, Maybe (p, v)))
-> k -> OrdPSQ k p v -> (b, OrdPSQ k p v)
PSQ.alter (\case
                                           Maybe (Time, ())
Nothing         -> ((), forall a. a -> Maybe a
Just (Time
time, ()))
                                           Just (Time
time', ()
_) -> ((), forall a. a -> Maybe a
Just (Time
time forall a. Ord a => a -> a -> a
`max` Time
time', ()))
                                       )
                                       peeraddr
peeraddr OrdPSQ peeraddr Time ()
psq)
                       OrdPSQ peeraddr Time ()
nextActivateTimes
                       Map peeraddr Time
times
                 }
    in   forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Ord a => a -> Set a -> Bool
`Set.member` forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Set peeraddr
readyPeers EstablishedPeers peeraddr peerconn
ep')) (forall k a. Map k a -> [k]
Map.keys Map peeraddr Time
times))
       forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Bool
invariant EstablishedPeers peeraddr peerconn
ep')
       forall a b. (a -> b) -> a -> b
$ EstablishedPeers peeraddr peerconn
ep'

-------------------------------
-- Tracking when we can peer share
--

-- | The first time that a peer will become available for peer sharing. If
-- peers are already available for peer share, or there are no peers at all
-- then the result is @Nothing@.
--
minPeerShareTime :: Ord peeraddr
                 => EstablishedPeers peeraddr peercon
                 -> Maybe Time
minPeerShareTime :: forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Maybe Time
minPeerShareTime EstablishedPeers { Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare,
                                    OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes
                                  }
  | forall a. Set a -> Bool
Set.null Set peeraddr
availableForPeerShare
  , Just (peeraddr
_k, Time
t, ()
_, OrdPSQ peeraddr Time ()
_psq) <- forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextPeerShareTimes
  = forall a. a -> Maybe a
Just Time
t

  | Bool
otherwise
  = forall a. Maybe a
Nothing

setPeerShareTime :: Ord peeraddr
                 => Set peeraddr
                 -> Time
                 -> EstablishedPeers peeraddr peercon
                 -> EstablishedPeers peeraddr peercon
setPeerShareTime :: forall peeraddr peercon.
Ord peeraddr =>
Set peeraddr
-> Time
-> EstablishedPeers peeraddr peercon
-> EstablishedPeers peeraddr peercon
setPeerShareTime Set peeraddr
peeraddrs Time
time
                 ep :: EstablishedPeers peeraddr peercon
ep@EstablishedPeers {
                   Map peeraddr peercon
allPeers :: Map peeraddr peercon
allPeers :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Map peeraddr peerconn
allPeers,
                   Set peeraddr
availableForPeerShare :: Set peeraddr
availableForPeerShare :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> Set peeraddr
availableForPeerShare,
                   OrdPSQ peeraddr Time ()
nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes :: forall peeraddr peerconn.
EstablishedPeers peeraddr peerconn -> OrdPSQ peeraddr Time ()
nextPeerShareTimes
                 } =
    forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr peercon
allPeers) Set peeraddr
peeraddrs) forall a b. (a -> b) -> a -> b
$
    let ep' :: EstablishedPeers peeraddr peercon
ep' = EstablishedPeers peeraddr peercon
ep {
          availableForPeerShare :: Set peeraddr
availableForPeerShare =
                   Set peeraddr
availableForPeerShare
            forall a. Ord a => Set a -> Set a -> Set a
Set.\\ Set peeraddr
peeraddrs,

          nextPeerShareTimes :: OrdPSQ peeraddr Time ()
nextPeerShareTimes =
            forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (\OrdPSQ peeraddr Time ()
psq peeraddr
peeraddr -> forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.insert peeraddr
peeraddr Time
time () OrdPSQ peeraddr Time ()
psq)
                        OrdPSQ peeraddr Time ()
nextPeerShareTimes
                        Set peeraddr
peeraddrs
        }
    in forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall peeraddr peerconn.
Ord peeraddr =>
EstablishedPeers peeraddr peerconn -> Bool
invariant EstablishedPeers peeraddr peercon
ep') EstablishedPeers peeraddr peercon
ep'