module Silvi.Random
( randLogExplicit
, randLog
, print
, printMany
, Gen(..)
) where
import qualified Chronos
import Chronos.Types
import Control.Applicative (liftA2)
import Control.Monad (replicateM, replicateM_)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Exists (Exists (..), Reify (..), SingList (..))
import Data.Text (Text)
import Data.Word (Word8)
import Net.IPv4 (ipv4)
import Net.Types (IPv4 (..))
import qualified Network.HTTP.Types.Method as HttpM
import qualified Network.HTTP.Types.Status as HttpS
import Network.HTTP.Types.Version (http09, http10, http11, http20)
import qualified Network.HTTP.Types.Version as HttpV
import Savage
import Savage.Internal.Gen (printOnly)
import Savage.Randy (element, enum, enumBounded, int, int8, word16, word8)
import Savage.Range (constantBounded)
import Silvi.Record (Field (..), SingField (..), Value (..))
import Silvi.Types
import Topaz.Rec (Rec (..), fromSingList)
import qualified Topaz.Rec as Topaz
import Prelude hiding (print)
rand :: SingField a -> Gen (Value a)
rand = \case
SingBracketNum -> ValueBracketNum <$> randomBracketNum
SingHttpMethod -> ValueHttpMethod <$> randomHttpMethod
SingHttpStatus -> ValueHttpStatus <$> randomHttpStatus
SingHttpVersion -> ValueHttpVersion <$> randomHttpVersion
SingUrl -> ValueUrl <$> randomUrl
SingUserId -> ValueUserId <$> randomUserident
SingObjSize -> ValueObjSize <$> randomObjSize
SingIp -> ValueIp <$> randomIPv4
SingTimestamp -> ValueTimestamp <$> randomOffsetDatetime
randLog :: forall as. (Reify as) => Gen (Rec Value as)
randLog = randLogExplicit (fromSingList (reify :: SingList as))
randLogExplicit :: Rec SingField rs -> Gen (Rec Value rs)
randLogExplicit = Topaz.traverse rand
print :: (MonadIO m, Show a) => Gen a -> m ()
print = printOnly
printMany :: (MonadIO m, Show a) => Int -> Gen a -> m ()
printMany n gen = replicateM_ n (print gen)
randomIPv4 :: Gen IPv4
randomIPv4 = ipv4
<$> word8 constantBounded
<*> word8 constantBounded
<*> word8 constantBounded
<*> word8 constantBounded
randomBracketNum :: Gen BracketNum
randomBracketNum = BracketNum <$> word8 constantBounded
randomHttpMethod :: Gen HttpM.StdMethod
randomHttpMethod = enumBounded
randomHttpStatus :: Gen HttpS.Status
randomHttpStatus = enumBounded
randomHttpVersion :: Gen HttpV.HttpVersion
randomHttpVersion = element [http09, http10, http11, http20]
randomUserident :: Gen UserId
randomUserident = element userIdents
randomObjSize :: Gen ObjSize
randomObjSize = ObjSize <$> word16 constantBounded
randomUrl :: Gen Url
randomUrl = element urls
randomDatetime :: Gen Datetime
randomDatetime = Datetime
<$> randomDate
<*> randomTimeOfDay
randomTimeOfDay :: Gen TimeOfDay
randomTimeOfDay = TimeOfDay
<$> enum 0 24
<*> enum 0 59
<*> enum 0 59999
randomDate :: Gen Date
randomDate = do
let year = randomYear 1995 2021
month = Month <$> int constantBounded
day = randomDay 1 =<< liftA2 daysUpperBound year month
Date <$> year <*> month <*> day
where daysUpperBound :: Year -> Month -> Int
daysUpperBound y m = Chronos.daysInMonth (Chronos.isLeapYear y) m
randomYear :: Int
-> Int
-> Gen Year
randomYear a b = Year <$> enum (min a b) (max a b)
randomMonth :: Int
-> Int
-> Gen Month
randomMonth a b = Month <$> enum (min a b) (max a b)
randomDay :: Int
-> Int
-> Gen DayOfMonth
randomDay a b = DayOfMonth <$> enum (min a b) (max a b)
randomOffsetDatetime :: Gen OffsetDatetime
randomOffsetDatetime = OffsetDatetime
<$> randomDatetime
<*> randomOffset
randomOffset :: Gen Offset
randomOffset = element offsets
offsets :: [Offset]
offsets = map Offset [100,200,300,330,400,430,500,530,545,600,630,700,800,845,900,930,1000,1030,1100,1200,1245,1300,1345,1400,0,100,200,230,300,330,400,500,600,700,800,900,930,1000,1100,1200]
userIdents :: [UserId]
userIdents = map UserId ["-","andrewthad","cement","chessai"]
urls :: [Url]
urls = map Url ["https://github.com","https://youtube.com","layer3com.com"]