Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(#1612): Fix connection to the metadata-validation service #1618

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ changes.

### Fixed

-
- Fix querying metadata-validation service from haskell backend [Issue 1612](https://github.com/IntersectMBO/govtool/issues/1612)
- Fix thread killed by timeout manager [Issue 1417](https://github.com/IntersectMBO/govtool/issues/1417)

### Changed

Expand Down
118 changes: 66 additions & 52 deletions govtool/backend/src/VVA/Metadata.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

module VVA.Metadata where

import Control.Exception (Exception, try)
import Control.Exception (SomeException, Exception, try)
import Control.Monad.Except (MonadError, throwError)
import Control.Monad.Reader

import Data.Aeson (Value (..), decode, encode, object, (.=))
import Data.Aeson.KeyMap (lookup)
import Data.Aeson.KeyMap (KeyMap, lookup)
import Data.ByteString (ByteString)
import Data.FileEmbed (embedFile)
import Data.Has (Has, getter)
Expand All @@ -23,7 +23,7 @@ import Data.Vector (toList)

import qualified Database.PostgreSQL.Simple as SQL

import Network.HTTP.Client
import Network.HTTP.Client (httpLbs, parseRequest, Request(..), RequestBody(..), Response, Manager, newManager, managerResponseTimeout, responseTimeoutMicro, defaultManagerSettings, responseBody)
import Network.HTTP.Client.TLS

import Prelude hiding (lookup)
Expand All @@ -32,31 +32,51 @@ import VVA.Config
import VVA.Pool (ConnectionPool, withPool)
import VVA.Types


logException :: (MonadIO m) => Text -> SomeException -> m ()
logException url ex = liftIO $ putStrLn $ "Failed to validate metadata for URL: " ++ unpack url ++ " with error: " ++ show ex

validateMetadata
:: (Has VVAConfig r, Has Manager r, MonadReader r m, MonadIO m, MonadError AppError m)
=> Text
-> Text
-> Maybe Text
-> m (Either Text Value)
-> m (MetadataValidationResult Value)
validateMetadata url hash standard = do
metadataEnabled <- getMetadataValidationEnabled
if not metadataEnabled
then return $ MetadataValidationResult True (Just "Metadata validation disabled") Nothing
else do
metadataHost <- getMetadataValidationHost
metadataPort <- getMetadataValidationPort
manager <- asks getter
(if metadataEnabled then (do
let requestBody = encode $ object (["url" .= unpack url, "hash" .= unpack hash] ++ maybe [] (\x -> ["standard" .= unpack x]) standard)
initialRequest <- liftIO $ parseRequest (unpack metadataHost <> ":" <> show metadataPort <> "/validate")
let request = initialRequest
{ method = "POST"
, requestBody = RequestBodyLBS requestBody
, requestHeaders = [("Content-Type", "application/json")]
}
response <- liftIO $ try $ httpLbs request manager
case response of
Left (e :: HttpException) -> return $ Left (pack $ show e)
Right r -> case decode $ responseBody r of
Nothing -> throwError $ InternalError "Failed to validate metadata"
Just x -> return $ Right x) else return $ Right "")

let timeout = responseTimeoutMicro 1000
manager <- liftIO $ newManager $ tlsManagerSettings { managerResponseTimeout = timeout }

let requestBody = encode $ object $
["url" .= url, "hash" .= hash] ++ maybe [] (\x -> ["standard" .= x]) standard
requestUrl = unpack metadataHost ++ ":" ++ show metadataPort ++ "/validate"

parsedRequestResult <- liftIO $ try $ parseRequest requestUrl
case parsedRequestResult of
Left (e :: SomeException) -> do
logException url e
return $ MetadataValidationResult False (Just "VALIDATION_FAILED") Nothing
Right initialRequest -> do
let request = initialRequest
{ method = "POST"
, requestBody = RequestBodyLBS requestBody
, requestHeaders = [("Content-Type", "application/json")]
}

responseResult <- liftIO $ try $ httpLbs request manager
case responseResult of
Left (e :: SomeException) -> do
logException url e
return $ MetadataValidationResult False (Just "VALIDATION_FAILED") Nothing
Right response -> case decode (responseBody response) of
Nothing -> return $ MetadataValidationResult False (Just "VALIDATION_FAILED") Nothing
Just x -> return $ MetadataValidationResult True (Just "VALIDATION_SUCCESS") (Just x)

getProposalMetadataValidationResult ::
(Has ConnectionPool r, Has Manager r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadFail m, MonadError AppError m) =>
Expand All @@ -66,27 +86,23 @@ getProposalMetadataValidationResult ::
getProposalMetadataValidationResult url hash = do
result <- validateMetadata url hash (Just "CIP108")
case result of
Left e -> return $ MetadataValidationResult False (Just e) Nothing
Right (Object r) -> case go r of
MetadataValidationResult False status _ -> return $ MetadataValidationResult False status Nothing
MetadataValidationResult True status (Just (Object r)) -> case go r of
Nothing -> throwError $ InternalError "Failed to validate metadata"
Just x -> return x
Right "" -> return $ MetadataValidationResult True (Just "200") Nothing
Just x -> return $ MetadataValidationResult True status (Just x)
_ -> return $ MetadataValidationResult False (Just "VALIDATION_FAILED") Nothing
where
go :: KeyMap Value -> Maybe ProposalMetadata
go result = do
(Bool valid) <- lookup "valid" result
let status = case lookup "status" result of
Just (String s) -> Just s
_ -> Nothing
(Object m) <- lookup "metadata" result
let abstract = (\(String s) -> s) <$> lookup "abstract" m
let motivation = (\(String s) -> s) <$> lookup "motivation" m
let rationale = (\(String s) -> s) <$> lookup "rationale" m
let title = (\(String s) -> s) <$> lookup "title" m
let references = (\(Array references') -> map (\(String x) -> x) $ toList references') <$> lookup "references" m
let proposalMetadata = ProposalMetadata <$> abstract <*> motivation <*> rationale <*> title <*> references
return $ MetadataValidationResult valid status proposalMetadata


(Bool valid) <- lookup "valid" result
(Object metadata) <- lookup "metadata" result
(String abstract) <- lookup "abstract" metadata
(String motivation) <- lookup "motivation" metadata
(String rationale) <- lookup "rationale" metadata
(String title) <- lookup "title" metadata
(Array references') <- lookup "references" metadata
let references = map (\(String x) -> x) (toList references')
return $ ProposalMetadata abstract motivation rationale title references

getDRepMetadataValidationResult ::
(Has ConnectionPool r, Has Manager r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadFail m, MonadError AppError m) =>
Expand All @@ -96,21 +112,19 @@ getDRepMetadataValidationResult ::
getDRepMetadataValidationResult url hash = do
result <- validateMetadata url hash (Just "CIPQQQ")
case result of
Left e -> return $ MetadataValidationResult False (Just e) Nothing
Right (Object r) -> case go r of
MetadataValidationResult False status _ -> return $ MetadataValidationResult False status Nothing
MetadataValidationResult True status (Just (Object r)) -> case go r of
Nothing -> throwError $ InternalError "Failed to validate metadata"
Just x -> return x
Right "" -> return $ MetadataValidationResult True (Just "200") Nothing
Just x -> return $ MetadataValidationResult True status (Just x)
_ -> return $ MetadataValidationResult False (Just "VALIDATION_FAILED") Nothing
where
go :: KeyMap Value -> Maybe DRepMetadata
go result = do
(Bool valid) <- lookup "valid" result
let status = case lookup "status" result of
Just (String s) -> Just s
_ -> Nothing
(Object m) <- lookup "metadata" result
let bio = (\(String s) -> s) <$> lookup "bio" m
let dRepName = (\(String s) -> s) <$> lookup "dRepName" m
let email = (\(String s) -> s) <$> lookup "email" m
let references = (\(Array references') -> map (\(String x) -> x) $ toList references') <$> lookup "references" m
let proposalMetadata = DRepMetadata <$> bio <*> dRepName <*> email <*> references
return $ MetadataValidationResult valid status proposalMetadata
(Bool valid) <- lookup "valid" result
(Object metadata) <- lookup "metadata" result
(String bio) <- lookup "bio" metadata
(String dRepName) <- lookup "dRepName" metadata
(String email) <- lookup "email" metadata
(Array references') <- lookup "references" metadata
let references = map (\(String x) -> x) (toList references')
return $ DRepMetadata bio dRepName email references
4 changes: 1 addition & 3 deletions govtool/backend/src/VVA/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,7 @@ data MetadataValidationResult a
, metadataValidationResultMetadata :: Maybe a
}
deriving (Show)





data CacheEnv
= CacheEnv
Expand Down
Loading