module Patrol.Type.Dsn
  ( Dsn(..)
  , fromUri
  , fromString
  , toUri
  , toString
  ) where

import qualified Data.Text as Text
import qualified Network.URI as Uri
import qualified Patrol.Utility.Maybe as Maybe

-- | <https://develop.sentry.dev/sdk/overview/#parsing-the-dsn>
data Dsn = Dsn
  { Dsn -> Text
protocol :: Text.Text
  , Dsn -> Text
publicKey :: Text.Text
  , Dsn -> Maybe Text
secretKey :: Maybe Text.Text
  , Dsn -> Text
host :: Text.Text
  , Dsn -> Maybe Text
port :: Maybe Text.Text
  , Dsn -> Text
path :: Text.Text
  , Dsn -> Text
projectId :: Text.Text
  } deriving (Dsn -> Dsn -> Bool
(Dsn -> Dsn -> Bool) -> (Dsn -> Dsn -> Bool) -> Eq Dsn
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Dsn -> Dsn -> Bool
$c/= :: Dsn -> Dsn -> Bool
== :: Dsn -> Dsn -> Bool
$c== :: Dsn -> Dsn -> Bool
Eq, Int -> Dsn -> ShowS
[Dsn] -> ShowS
Dsn -> String
(Int -> Dsn -> ShowS)
-> (Dsn -> String) -> ([Dsn] -> ShowS) -> Show Dsn
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Dsn] -> ShowS
$cshowList :: [Dsn] -> ShowS
show :: Dsn -> String
$cshow :: Dsn -> String
showsPrec :: Int -> Dsn -> ShowS
$cshowsPrec :: Int -> Dsn -> ShowS
Show)

fromUri :: Uri.URI -> Either String Dsn
fromUri :: URI -> Either String Dsn
fromUri URI
uri = do
  Text
protocol <- String -> Maybe Text -> Either String Text
forall e a. e -> Maybe a -> Either e a
Maybe.note String
"invalid protocol"
    (Maybe Text -> Either String Text)
-> (String -> Maybe Text) -> String -> Either String Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> Maybe Text
Text.stripSuffix (Char -> Text
Text.singleton Char
':')
    (Text -> Maybe Text) -> (String -> Text) -> String -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack
    (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ URI -> String
Uri.uriScheme URI
uri
  URIAuth
authority <- String -> Maybe URIAuth -> Either String URIAuth
forall e a. e -> Maybe a -> Either e a
Maybe.note String
"missing authority" (Maybe URIAuth -> Either String URIAuth)
-> Maybe URIAuth -> Either String URIAuth
forall a b. (a -> b) -> a -> b
$ URI -> Maybe URIAuth
Uri.uriAuthority URI
uri
  Text
userInfo <- String -> Maybe Text -> Either String Text
forall e a. e -> Maybe a -> Either e a
Maybe.note String
"invalid user info"
    (Maybe Text -> Either String Text)
-> (String -> Maybe Text) -> String -> Either String Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> Maybe Text
Text.stripSuffix (Char -> Text
Text.singleton Char
'@')
    (Text -> Maybe Text) -> (String -> Text) -> String -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack
    (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ URIAuth -> String
Uri.uriUserInfo URIAuth
authority
  let
    (Text
publicKey, Text
secretKey) = Int -> Text -> Text
Text.drop Int
1
      (Text -> Text) -> (Text, Text) -> (Text, Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Text -> (Text, Text)
Text.breakOn (Char -> Text
Text.singleton Char
':') Text
userInfo
    (Text
host, Text
port) = (Text -> Text) -> (Text, Text) -> (Text, Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Text -> Text
Text.drop Int
1) ((Text, Text) -> (Text, Text))
-> (String -> (Text, Text)) -> String -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> (Text, Text)
Text.breakOn (Char -> Text
Text.singleton Char
':')
      (Text -> (Text, Text))
-> (String -> Text) -> String -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack
      (String -> (Text, Text)) -> String -> (Text, Text)
forall a b. (a -> b) -> a -> b
$ URIAuth -> String
Uri.uriRegName URIAuth
authority String -> ShowS
forall a. Semigroup a => a -> a -> a
<> URIAuth -> String
Uri.uriPort URIAuth
authority
    (Text
path, Text
projectId) = Text -> Text -> (Text, Text)
Text.breakOnEnd (Char -> Text
Text.singleton Char
'/')
      (Text -> (Text, Text))
-> (String -> Text) -> String -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack
      (String -> (Text, Text)) -> String -> (Text, Text)
forall a b. (a -> b) -> a -> b
$ URI -> String
Uri.uriPath URI
uri
  Dsn -> Either String Dsn
forall a b. b -> Either a b
Right Dsn :: Text
-> Text -> Maybe Text -> Text -> Maybe Text -> Text -> Text -> Dsn
Dsn
    { Text
protocol :: Text
protocol :: Text
protocol
    , Text
publicKey :: Text
publicKey :: Text
publicKey
    , secretKey :: Maybe Text
secretKey = if Text -> Bool
Text.null Text
secretKey then Maybe Text
forall a. Maybe a
Nothing else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
secretKey
    , Text
host :: Text
host :: Text
host
    , port :: Maybe Text
port = if Text -> Bool
Text.null Text
port then Maybe Text
forall a. Maybe a
Nothing else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
port
    , Text
path :: Text
path :: Text
path
    , Text
projectId :: Text
projectId :: Text
projectId
    }

fromString :: String -> Either String Dsn
fromString :: String -> Either String Dsn
fromString String
string = do
  URI
uri <- String -> Maybe URI -> Either String URI
forall e a. e -> Maybe a -> Either e a
Maybe.note String
"invalid URI" (Maybe URI -> Either String URI) -> Maybe URI -> Either String URI
forall a b. (a -> b) -> a -> b
$ String -> Maybe URI
Uri.parseURI String
string
  URI -> Either String Dsn
fromUri URI
uri

toUri :: Dsn -> Uri.URI
toUri :: Dsn -> URI
toUri Dsn
dsn = URI :: String -> Maybe URIAuth -> String -> String -> String -> URI
Uri.URI
  { uriScheme :: String
Uri.uriScheme = Text -> String
Text.unpack (Dsn -> Text
protocol Dsn
dsn) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
":"
  , uriAuthority :: Maybe URIAuth
Uri.uriAuthority = URIAuth -> Maybe URIAuth
forall a. a -> Maybe a
Just URIAuth :: String -> String -> String -> URIAuth
Uri.URIAuth
    { uriUserInfo :: String
Uri.uriUserInfo = Text -> String
Text.unpack (Dsn -> Text
publicKey Dsn
dsn)
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String -> (Text -> String) -> Maybe Text -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\ Text
x -> String
":" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack Text
x) (Dsn -> Maybe Text
secretKey Dsn
dsn) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"@"
    , uriRegName :: String
Uri.uriRegName = Text -> String
Text.unpack (Dsn -> Text
host Dsn
dsn)
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String -> (Text -> String) -> Maybe Text -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\ Text
x -> String
":" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack Text
x) (Dsn -> Maybe Text
port Dsn
dsn)
    , uriPort :: String
Uri.uriPort = String
""
    }
  , uriPath :: String
Uri.uriPath = Text -> String
Text.unpack (Dsn -> Text
path Dsn
dsn) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
Text.unpack (Dsn -> Text
projectId Dsn
dsn)
  , uriQuery :: String
Uri.uriQuery = String
""
  , uriFragment :: String
Uri.uriFragment = String
""
  }

toString :: Dsn -> String
toString :: Dsn -> String
toString Dsn
dsn = ShowS -> URI -> ShowS
Uri.uriToString ShowS
forall a. a -> a
id (Dsn -> URI
toUri Dsn
dsn) String
""