module NetSpider.CLI.Snapshot
( parserSnapshotQuery,
makeSnapshotQuery,
SnapshotConfig(..),
CLISnapshotQuery
) where
import Control.Applicative ((<$>), (<*>), (<|>), many, optional, empty)
import Data.Int (Int64)
import NetSpider.Interval
( interval, parseTimeIntervalEnd, secSince, secUntil,
IntervalEnd, Interval
)
import qualified NetSpider.Query as Q
import NetSpider.Timestamp (Timestamp)
import qualified Options.Applicative as Opt
import qualified Options.Applicative.Types as OptT
data SnapshotConfig n =
SnapshotConfig
{ nodeIDReader :: Opt.ReadM n,
startsFromAsArguments :: Bool
}
data CLISnapshotQuery n =
CLISnapshotQuery
{ startsFrom :: [n],
timeDurationSec :: Maybe Int64,
timeFrom :: Maybe (IntervalEnd Timestamp),
timeTo :: Maybe (IntervalEnd Timestamp)
}
deriving (Show,Eq,Ord)
makeSnapshotQuery :: Q.Query n na fla sla
-> CLISnapshotQuery n
-> Either String (Q.Query n na fla sla)
makeSnapshotQuery q cliq = do
ivl <- makeTimeInterval cliq
return $ q { Q.startsFrom = startsFrom cliq,
Q.timeInterval = ivl
}
makeTimeInterval :: CLISnapshotQuery n -> Either String (Interval Timestamp)
makeTimeInterval c =
case (timeFrom c, timeTo c, timeDurationSec c) of
(ms, me, Nothing) -> Right $ interval s e
where
s = maybe (Q.NegInf, False) id ms
e = maybe (Q.PosInf, False) id me
(Just s, Nothing, Just d) -> Right $ secSince d s
(Nothing, Just e, Just d) -> Right $ secUntil d e
(Just _, Just _, Just _) -> Left ("Specifying all --time-to, --time-from and --duration is not allowed.")
(Nothing, Nothing, Just _) -> Left ("Specifying --duration only is not allowed. Specify --time-to or --time-from, too.")
parserSnapshotQuery :: SnapshotConfig n
-> Opt.Parser (CLISnapshotQuery n)
parserSnapshotQuery conf =
CLISnapshotQuery <$> pStartsFromTotal <*> pDuration <*> pTimeLower <*> pTimeUpper
where
pStartsFromTotal = (++) <$> pStartsFrom <*> pStartsFromArgs
rNodeID = nodeIDReader conf
nodeID_metavar = "NODE-ID"
pStartsFrom = many $ Opt.option rNodeID $ mconcat
[ Opt.short 's',
Opt.long "starts-from",
Opt.help "ID of a node from which the Spider starts traversing the history graph. You can specify this option multiple times.",
Opt.metavar nodeID_metavar
]
pStartsFromArgs = if not $ startsFromAsArguments conf
then pure []
else many $ Opt.argument rNodeID $ mconcat
[ Opt.help $ "Same as -s option.",
Opt.metavar $ nodeID_metavar
]
pTimeLower =
optional $ Opt.option (Opt.eitherReader parseTimeIntervalEnd) $ mconcat
( [ Opt.short 'f',
Opt.long "time-from",
Opt.help ( "Lower bound of query timestamp. "
++ "Local findings with timestamp newer than this value are used to create the snapshot graph. "
++ "ISO 8601 format is used for timestamps (e.g. `2019-03-22T10:20:12+09:00`). "
++ "The timezone is optional. "
++ "By default, the lower bound is inclusive. "
++ "Add prefix 'x' to make it exclusive (e.g. `x2019-03-22T10:20:12+09:00`). "
++ "Prefix of 'i' explicitly mark the lower bound is inclusive. "
++ "Special value `x-inf` indicates there is no lower bound. "
++ "Default: x-inf"
),
Opt.metavar "TIMESTAMP"
]
)
pTimeUpper =
optional $ Opt.option (Opt.eitherReader parseTimeIntervalEnd) $ mconcat
( [ Opt.short 't',
Opt.long "time-to",
Opt.help ( "Upper bound of query timestamp. "
++ "Local findings with timestamp older than this value are used to create the snapshot graph. "
++ "See --time-from for format of timestamps. "
++ "Special value `x+inf` indicates there is no upper bound. "
++ "Default: x+inf"
),
Opt.metavar "TIMESTAMP"
]
)
pDuration = optional $ Opt.option Opt.auto $ mconcat
[ Opt.short 'd',
Opt.long "duration",
Opt.help ( "Duration of the query time interval in seconds. "
++ " Use with either --time-to or --time-from option."
),
Opt.metavar "SECONDS"
]