{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Simplex.Messaging.Parsers where

import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.Bifunctor (first)
import Data.ByteString.Base64
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Char (isAlphaNum)
import Data.Time.Clock (UTCTime)
import Data.Time.ISO8601 (parseISO8601)
import Data.Typeable (Typeable)
import Database.SQLite.Simple (ResultError (..), SQLData (..))
import Database.SQLite.Simple.FromField (FieldParser, returnError)
import Database.SQLite.Simple.Internal (Field (..))
import Database.SQLite.Simple.Ok (Ok (Ok))
import Simplex.Messaging.Util ((<$?>))
import Text.Read (readMaybe)

base64P :: Parser ByteString
base64P :: Parser ByteString
base64P = ByteString -> Either String ByteString
decode (ByteString -> Either String ByteString)
-> Parser ByteString -> Parser ByteString
forall (m :: * -> *) a b.
MonadFail m =>
(a -> Either String b) -> m a -> m b
<$?> Parser ByteString
base64StringP

base64StringP :: Parser ByteString
base64StringP :: Parser ByteString
base64StringP = do
  ByteString
str <- (Char -> Bool) -> Parser ByteString
A.takeWhile1 (\c :: Char
c -> Char -> Bool
isAlphaNum Char
c Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '/')
  ByteString
pad <- (Char -> Bool) -> Parser ByteString
A.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '=')
  ByteString -> Parser ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Parser ByteString)
-> ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ ByteString
str ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
pad

tsISO8601P :: Parser UTCTime
tsISO8601P :: Parser UTCTime
tsISO8601P = Parser UTCTime
-> (UTCTime -> Parser UTCTime) -> Maybe UTCTime -> Parser UTCTime
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Parser UTCTime
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "timestamp") UTCTime -> Parser UTCTime
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe UTCTime -> Parser UTCTime)
-> (ByteString -> Maybe UTCTime) -> ByteString -> Parser UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe UTCTime
parseISO8601 (String -> Maybe UTCTime)
-> (ByteString -> String) -> ByteString -> Maybe UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
B.unpack (ByteString -> Parser UTCTime)
-> Parser ByteString -> Parser UTCTime
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Char -> Bool) -> Parser ByteString
A.takeTill (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ')

parse :: Parser a -> e -> (ByteString -> Either e a)
parse :: Parser a -> e -> ByteString -> Either e a
parse parser :: Parser a
parser err :: e
err = (String -> e) -> Either String a -> Either e a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (e -> String -> e
forall a b. a -> b -> a
const e
err) (Either String a -> Either e a)
-> (ByteString -> Either String a) -> ByteString -> Either e a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
parseAll Parser a
parser

parseAll :: Parser a -> (ByteString -> Either String a)
parseAll :: Parser a -> ByteString -> Either String a
parseAll parser :: Parser a
parser = Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
A.parseOnly (Parser a
parser Parser a -> Parser ByteString () -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
forall t. Chunk t => Parser t ()
A.endOfInput)

parseRead :: Read a => Parser ByteString -> Parser a
parseRead :: Parser ByteString -> Parser a
parseRead = (Parser ByteString -> (ByteString -> Parser a) -> Parser a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Parser a -> (a -> Parser a) -> Maybe a -> Parser a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "cannot read") a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe a -> Parser a)
-> (ByteString -> Maybe a) -> ByteString -> Parser a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe a
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe a)
-> (ByteString -> String) -> ByteString -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
B.unpack)

parseRead1 :: Read a => Parser a
parseRead1 :: Parser a
parseRead1 = Parser ByteString -> Parser a
forall a. Read a => Parser ByteString -> Parser a
parseRead (Parser ByteString -> Parser a) -> Parser ByteString -> Parser a
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser ByteString
A.takeTill (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ')

parseRead2 :: Read a => Parser a
parseRead2 :: Parser a
parseRead2 = Parser ByteString -> Parser a
forall a. Read a => Parser ByteString -> Parser a
parseRead (Parser ByteString -> Parser a) -> Parser ByteString -> Parser a
forall a b. (a -> b) -> a -> b
$ do
  ByteString
w1 <- (Char -> Bool) -> Parser ByteString
A.takeTill (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ') Parser ByteString -> Parser ByteString Char -> Parser ByteString
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser ByteString Char
A.char ' '
  ByteString
w2 <- (Char -> Bool) -> Parser ByteString
A.takeTill (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ')
  ByteString -> Parser ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Parser ByteString)
-> ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ ByteString
w1 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> " " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
w2

parseString :: (ByteString -> Either String a) -> (String -> a)
parseString :: (ByteString -> Either String a) -> String -> a
parseString p :: ByteString -> Either String a
p = (String -> a) -> (a -> a) -> Either String a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> a
forall a. HasCallStack => String -> a
error a -> a
forall a. a -> a
id (Either String a -> a)
-> (String -> Either String a) -> String -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String a
p (ByteString -> Either String a)
-> (String -> ByteString) -> String -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
B.pack

blobFieldParser :: Typeable k => Parser k -> FieldParser k
blobFieldParser :: Parser k -> FieldParser k
blobFieldParser p :: Parser k
p = \case
  f :: Field
f@(Field (SQLBlob b :: ByteString
b) _) ->
    case Parser k -> ByteString -> Either String k
forall a. Parser a -> ByteString -> Either String a
parseAll Parser k
p ByteString
b of
      Right k :: k
k -> k -> Ok k
forall a. a -> Ok a
Ok k
k
      Left e :: String
e -> (String -> String -> String -> ResultError)
-> Field -> String -> Ok k
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f ("couldn't parse field: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
e)
  f :: Field
f -> (String -> String -> String -> ResultError)
-> Field -> String -> Ok k
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLBlob column type"