module Tonatona.Google ( run , Dsl , DslBackend , Config , ServantError , JWT , JWT.Scope(..) ) where import Tonalude import qualified Google.Client as Client import qualified Google.Form as Form import Google.JWT (JWT) import qualified Google.JWT as JWT import Google.Response (Token) import qualified Google.Response as Response import Servant.Client (ServantError) import Tonatona (HasConfig(..), HasParser(..)) import TonaParser (Parser, (.||), argLong, envVar, liftWith, requiredVal) import Tonatona.Google.Internal -- | Main function. run :: (HasConfig env Config) => (ServantError -> RIO env a) -- ^ Error handler -> [JWT.Scope] -> Dsl env a -> RIO env a run errorHandler scopes query = do Config {..} <- asks config eToken <- liftIO $ Client.getToken (Just delegationEmail) jwt scopes case eToken of Left err -> errorHandler err Right token -> runReaderT query (DslBackend token) `catch` errorHandler ------------ -- Config -- ------------ data Config = Config { serviceKeyFile :: ServiceKeyFile , jwt :: JWT , delegationEmail :: JWT.Email } newtype ServiceKeyFile = ServiceKeyFile { unServiceKeyFile :: FilePath } deriving (Eq, Read, Show) instance HasParser ServiceKeyFile where parser = ServiceKeyFile <$> requiredVal "File path to service key file (Example: \"gmail-3abc452de.json\")" ( argLong "service-key-file" .|| envVar "SERVICE_KEY_FILE") parseJwt :: ServiceKeyFile -> Parser JWT parseJwt (ServiceKeyFile fp) = do mjwt <- liftIO $ JWT.readServiceKeyFile fp case mjwt of Nothing -> error $ "Failed to parse service key file: " <> fp Just jwt -> pure jwt parseEmail :: Parser JWT.Email parseEmail = JWT.Email <$> requiredVal "Email account to use for delegation." ( argLong "delegation-email" .|| envVar "DELEGATION_EMAIL") instance HasParser Config where parser = do keyFile <- parser Config <$> pure keyFile <*> parseJwt keyFile <*> parseEmail