module DRcon.CommandArgs (
ProtocolOptions(..),
BaseArgs(..),
CommandArgs(..),
parseRconMode,
checkTimeout,
parseEncoding,
showEncoding,
parseColorMode,
argsParser,
maybeArgsParser
) where
import Options.Applicative
import DarkPlaces.Text (DecodeType(..))
import DarkPlaces.Rcon hiding (connect, send)
import DRcon.Polyfills (readMaybe)
import Data.Tuple (swap)
import Data.Maybe (fromMaybe)
data BaseArgs = BaseArgs {
confServerString :: String,
confPassword :: Maybe String,
confMode :: Maybe RconMode,
confTimeDiff :: Maybe Int,
confTimeout :: Maybe Float,
confEncoding :: Maybe DecodeType,
confProtoOptions :: Maybe ProtocolOptions
} deriving(Show, Read, Eq)
data CommandArgs = CommandArgs {
cliServerName :: String,
cliBaseArgs :: BaseArgs,
cliColor :: Maybe Bool,
cliCommand :: Maybe String
} deriving(Show, Read, Eq)
eitherArgs :: Either String a -> ReadM a
eitherArgs (Right v) = return v
eitherArgs (Left msg) = readerError msg
parseRconMode :: String -> Either String RconMode
parseRconMode ms = case readMaybe ms of
Just x | x >= 0 && x < 3 -> Right $ toEnum x
_ -> Left "value should be 0, 1 or 2"
checkTimeout :: Float -> Either String Float
checkTimeout t
| t > 0 = Right t
| otherwise = Left "value should be bigger then 0"
encodings :: [(String, DecodeType)]
encodings = [
("utf8", Utf8Lenient),
("utf8-lenient", Utf8Lenient),
("utf8-ignore", Utf8Ignore),
("utf8-strict", Utf8Strict),
("nexuiz", NexuizDecode)]
parseEncoding :: String -> Either String DecodeType
parseEncoding encname = case lookup encname encodings of
Just v -> Right v
Nothing -> Left "Error bad decode type. Major values are ut8 and nexuiz"
showEncoding :: DecodeType -> String
showEncoding enc = fromMaybe first $ lookup enc encLst
where
encLst = map swap encodings
first = fst $ head encodings
parseColorMode :: String -> ReadM (Maybe Bool)
parseColorMode mode_str
| mode_str == "always" = return $ Just True
| mode_str == "auto" = return Nothing
| mode_str == "never" = return $ Just False
| otherwise = readerError "value should be always, auto or never"
protoOptionsParser :: Parser (Maybe ProtocolOptions)
protoOptionsParser =
flag' (Just OnlyIPv4) (short '4' <> help "Forces to use IPv4 addresses only")
<|> flag' (Just OnlyIPv6) (short '6' <> help "Forces to use IPv6 addresses only")
<|> (pure Nothing)
commandParser :: Parser String
commandParser = unwords <$> (some $ argument str (
metavar "COMMAND"
<> help "Command that will be sent to server"))
argsParser :: Parser CommandArgs
argsParser = argsConstructor
<$> protoOptionsParser
<*> optional (strOption (
short 'p'
<> long "password"
<> help "Server's password"
<> metavar "PASSWORD"))
<*> optional (option (str >>= eitherArgs . parseRconMode) (
short 'm'
<> long "mode"
<> help "Use secure rcon, same as `rcon_secure' cvar, 1 is default"
<> metavar "MODE"))
<*> optional (option auto (
short 'd'
<> long "time-diff"
<> help "Integer difference between client and server time, can be negative"
<> metavar "TIMEDIFF"))
<*> optional (option (auto >>= eitherArgs . checkTimeout) (
short 't'
<> long "timeout"
<> help "How many time wait for response after send or previous response"
<> metavar "TIMEOUT"))
<*> optional (option (str >>= eitherArgs . parseEncoding) (
short 'e'
<> long "encoding"
<> help "Server encoding. Major options is `utf8' and `nexuiz'"
<> metavar "ENCODING"))
<*> option (str >>= parseColorMode) (
long "color"
<> value Nothing
<> help "Possible values are: `auto', `always' and `never'"
<> metavar "COLOR_MODE")
<*> argument str (
help "Server to connect or config section"
<> metavar "SERVER")
<*> optional commandParser
where
argsConstructor protoOpt password mode tdiff tout enc color server cmd =
let baseArgs = BaseArgs {confServerString=server,
confPassword=password,
confMode=mode,
confTimeDiff=tdiff,
confTimeout=tout,
confEncoding=enc,
confProtoOptions=protoOpt}
in CommandArgs {cliServerName=server,
cliBaseArgs=baseArgs,
cliColor=color,
cliCommand=cmd}
maybeArgsParser :: Parser (Maybe CommandArgs)
maybeArgsParser = flag' Nothing (
long "version"
<> short 'V'
<> hidden) <|> (Just <$> argsParser)