module Simplex.Messaging.Agent.QueryString
  ( QueryStringParams (..),
    QSPEscaping (..),
    queryParam,
    queryParamParser,
    queryParam_,
    queryParamStr,
  ) where

import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.List (find)
import qualified Network.HTTP.Types as Q
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll)

data QueryStringParams = QSP QSPEscaping Q.SimpleQuery
  deriving (Int -> QueryStringParams -> ShowS
[QueryStringParams] -> ShowS
QueryStringParams -> String
(Int -> QueryStringParams -> ShowS)
-> (QueryStringParams -> String)
-> ([QueryStringParams] -> ShowS)
-> Show QueryStringParams
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> QueryStringParams -> ShowS
showsPrec :: Int -> QueryStringParams -> ShowS
$cshow :: QueryStringParams -> String
show :: QueryStringParams -> String
$cshowList :: [QueryStringParams] -> ShowS
showList :: [QueryStringParams] -> ShowS
Show)

data QSPEscaping = QEscape | QNoEscaping
  deriving (Int -> QSPEscaping -> ShowS
[QSPEscaping] -> ShowS
QSPEscaping -> String
(Int -> QSPEscaping -> ShowS)
-> (QSPEscaping -> String)
-> ([QSPEscaping] -> ShowS)
-> Show QSPEscaping
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> QSPEscaping -> ShowS
showsPrec :: Int -> QSPEscaping -> ShowS
$cshow :: QSPEscaping -> String
show :: QSPEscaping -> String
$cshowList :: [QSPEscaping] -> ShowS
showList :: [QSPEscaping] -> ShowS
Show)

instance StrEncoding QueryStringParams where
  strEncode :: QueryStringParams -> ByteString
strEncode (QSP QSPEscaping
esc SimpleQuery
q) = case QSPEscaping
esc of
    QSPEscaping
QEscape -> Bool -> SimpleQuery -> ByteString
Q.renderSimpleQuery Bool
False SimpleQuery
q
    QSPEscaping
QNoEscaping ->
      Bool -> PartialEscapeQuery -> ByteString
Q.renderQueryPartialEscape Bool
False (PartialEscapeQuery -> ByteString)
-> PartialEscapeQuery -> ByteString
forall a b. (a -> b) -> a -> b
$
        ((ByteString, ByteString) -> PartialEscapeQueryItem)
-> SimpleQuery -> PartialEscapeQuery
forall a b. (a -> b) -> [a] -> [b]
map (\(ByteString
n, ByteString
v) -> (ByteString
n, [ByteString -> EscapeItem
Q.QN ByteString
v])) SimpleQuery
q
  strP :: Parser QueryStringParams
strP = QSPEscaping -> SimpleQuery -> QueryStringParams
QSP QSPEscaping
QEscape (SimpleQuery -> QueryStringParams)
-> (ByteString -> SimpleQuery) -> ByteString -> QueryStringParams
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> SimpleQuery
Q.parseSimpleQuery (ByteString -> QueryStringParams)
-> Parser ByteString ByteString -> Parser QueryStringParams
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser ByteString ByteString
A.takeTill (\Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n')

queryParam :: StrEncoding a => ByteString -> QueryStringParams -> Parser a
queryParam :: forall a.
StrEncoding a =>
ByteString -> QueryStringParams -> Parser a
queryParam = Parser a -> ByteString -> QueryStringParams -> Parser a
forall a. Parser a -> ByteString -> QueryStringParams -> Parser a
queryParamParser Parser a
forall a. StrEncoding a => Parser a
strP

queryParamParser :: Parser a -> ByteString -> QueryStringParams -> Parser a
queryParamParser :: forall a. Parser a -> ByteString -> QueryStringParams -> Parser a
queryParamParser Parser a
p ByteString
name QueryStringParams
q =
  case ByteString -> QueryStringParams -> Maybe ByteString
queryParamStr ByteString
name QueryStringParams
q of
    Just ByteString
s -> (String -> Parser a)
-> (a -> Parser a) -> Either String a -> Parser a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser a
forall a. String -> Parser ByteString a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail a -> Parser a
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String a -> Parser a) -> Either String a -> Parser a
forall a b. (a -> b) -> a -> b
$ Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
parseAll Parser a
p ByteString
s
    Maybe ByteString
_ -> String -> Parser a
forall a. String -> Parser ByteString a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser a) -> String -> Parser a
forall a b. (a -> b) -> a -> b
$ String
"no qs param " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ByteString -> String
B.unpack ByteString
name

queryParam_ :: StrEncoding a => ByteString -> QueryStringParams -> Parser (Maybe a)
queryParam_ :: forall a.
StrEncoding a =>
ByteString -> QueryStringParams -> Parser (Maybe a)
queryParam_ ByteString
name QueryStringParams
q =
  case ByteString -> QueryStringParams -> Maybe ByteString
queryParamStr ByteString
name QueryStringParams
q of
    Just ByteString
p -> (String -> Parser (Maybe a))
-> (Maybe a -> Parser (Maybe a))
-> Either String (Maybe a)
-> Parser (Maybe a)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser (Maybe a)
forall a. String -> Parser ByteString a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail Maybe a -> Parser (Maybe a)
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String (Maybe a) -> Parser (Maybe a))
-> Either String (Maybe a) -> Parser (Maybe a)
forall a b. (a -> b) -> a -> b
$ Parser (Maybe a) -> ByteString -> Either String (Maybe a)
forall a. Parser a -> ByteString -> Either String a
parseAll Parser (Maybe a)
forall a. StrEncoding a => Parser a
strP ByteString
p
    Maybe ByteString
_ -> Maybe a -> Parser (Maybe a)
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing

queryParamStr :: ByteString -> QueryStringParams -> Maybe ByteString
queryParamStr :: ByteString -> QueryStringParams -> Maybe ByteString
queryParamStr ByteString
name (QSP QSPEscaping
_ SimpleQuery
q) = (ByteString, ByteString) -> ByteString
forall a b. (a, b) -> b
snd ((ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString) -> Maybe ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((ByteString, ByteString) -> Bool)
-> SimpleQuery -> Maybe (ByteString, ByteString)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
name) (ByteString -> Bool)
-> ((ByteString, ByteString) -> ByteString)
-> (ByteString, ByteString)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString, ByteString) -> ByteString
forall a b. (a, b) -> a
fst) SimpleQuery
q