Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
195
Issues
195
List
Board
Labels
Milestones
Merge Requests
12
Merge Requests
12
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
haskell-gargantext
Commits
58d9fcb0
Commit
58d9fcb0
authored
Dec 16, 2024
by
Alfredo Di Napoli
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Proper error handling for remote import and export handlers
parent
23a06d28
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
40 additions
and
19 deletions
+40
-19
Types.hs
src/Gargantext/API/Errors/Types.hs
+8
-0
Prelude.hs
src/Gargantext/API/Prelude.hs
+4
-1
Client.hs
src/Gargantext/API/Routes/Client.hs
+1
-1
Remote.hs
src/Gargantext/API/Routes/Named/Remote.hs
+3
-2
Remote.hs
src/Gargantext/API/Server/Named/Remote.hs
+24
-15
No files found.
src/Gargantext/API/Errors/Types.hs
View file @
58d9fcb0
...
@@ -35,6 +35,7 @@ module Gargantext.API.Errors.Types (
...
@@ -35,6 +35,7 @@ module Gargantext.API.Errors.Types (
,
GraphQLError
(
..
)
,
GraphQLError
(
..
)
,
ToFrontendErrorData
(
..
)
,
ToFrontendErrorData
(
..
)
,
AccessPolicyErrorReason
(
..
)
,
AccessPolicyErrorReason
(
..
)
,
HasBackendInternalError
(
..
)
-- * Constructing frontend errors
-- * Constructing frontend errors
,
mkFrontendErrNoDiagnostic
,
mkFrontendErrNoDiagnostic
...
@@ -67,6 +68,7 @@ import Gargantext.Prelude hiding (Location, WithStacktrace)
...
@@ -67,6 +68,7 @@ import Gargantext.Prelude hiding (Location, WithStacktrace)
import
Gargantext.Utils.Dict
(
Dict
(
..
))
import
Gargantext.Utils.Dict
(
Dict
(
..
))
import
Gargantext.Utils.Jobs.Monad
qualified
as
Jobs
import
Gargantext.Utils.Jobs.Monad
qualified
as
Jobs
import
Servant
(
ServerError
)
import
Servant
(
ServerError
)
import
Control.Lens.Prism
(
prism'
)
-- | A 'WithStacktrace' carries an error alongside its
-- | A 'WithStacktrace' carries an error alongside its
-- 'CallStack', to be able to print the correct source location
-- 'CallStack', to be able to print the correct source location
...
@@ -121,6 +123,12 @@ data BackendInternalError
...
@@ -121,6 +123,12 @@ data BackendInternalError
makePrisms
''
B
ackendInternalError
makePrisms
''
B
ackendInternalError
class
HasBackendInternalError
e
where
_BackendInternalError
::
Prism'
e
BackendInternalError
instance
HasBackendInternalError
BackendInternalError
where
_BackendInternalError
=
prism'
identity
Just
instance
ToJSON
BackendInternalError
where
instance
ToJSON
BackendInternalError
where
toJSON
(
InternalJobError
s
)
=
toJSON
(
InternalJobError
s
)
=
object
[
(
"status"
,
toJSON
(
"IsFailure"
::
Text
))
object
[
(
"status"
,
toJSON
(
"IsFailure"
::
Text
))
...
...
src/Gargantext/API/Prelude.hs
View file @
58d9fcb0
...
@@ -17,11 +17,12 @@ module Gargantext.API.Prelude
...
@@ -17,11 +17,12 @@ module Gargantext.API.Prelude
,
HasServerError
(
..
)
,
HasServerError
(
..
)
,
serverError
)
where
,
serverError
)
where
import
Control.Exception.Safe
qualified
as
Safe
import
Control.Lens
((
#
))
import
Control.Lens
((
#
))
import
Control.Monad.Random
(
MonadRandom
)
import
Control.Monad.Random
(
MonadRandom
)
import
Gargantext.API.Admin.Auth.Types
(
AuthenticationError
)
import
Gargantext.API.Admin.Auth.Types
(
AuthenticationError
)
import
Gargantext.API.Errors.Class
(
HasAuthenticationError
,
_AuthenticationError
)
import
Gargantext.API.Errors.Class
(
HasAuthenticationError
,
_AuthenticationError
)
import
Gargantext.API.Errors.Types
(
HasServerError
(
..
),
serverError
)
import
Gargantext.API.Errors.Types
(
HasServerError
(
..
),
serverError
,
HasBackendInternalError
)
import
Gargantext.Core.Notifications.CentralExchange.Types
(
HasCentralExchangeNotification
)
import
Gargantext.Core.Notifications.CentralExchange.Types
(
HasCentralExchangeNotification
)
import
Gargantext.Core.Config
(
HasConfig
,
HasManager
)
import
Gargantext.Core.Config
(
HasConfig
,
HasManager
)
import
Gargantext.Core.Mail.Types
(
HasMail
)
import
Gargantext.Core.Mail.Types
(
HasMail
)
...
@@ -54,6 +55,7 @@ type ErrC err =
...
@@ -54,6 +55,7 @@ type ErrC err =
,
HasValidationError
err
,
HasValidationError
err
,
HasTreeError
err
,
HasTreeError
err
,
HasServerError
err
,
HasServerError
err
,
HasBackendInternalError
err
,
HasAuthenticationError
err
,
HasAuthenticationError
err
-- , ToJSON err -- TODO this is arguable
-- , ToJSON err -- TODO this is arguable
,
Exception
err
,
Exception
err
...
@@ -63,6 +65,7 @@ type GargServerC env err m =
...
@@ -63,6 +65,7 @@ type GargServerC env err m =
(
HasNodeStory
env
err
m
(
HasNodeStory
env
err
m
,
HasMail
env
,
HasMail
env
,
MonadRandom
m
,
MonadRandom
m
,
Safe
.
MonadCatch
m
,
EnvC
env
,
EnvC
env
,
ErrC
err
,
ErrC
err
,
ToJSON
err
,
ToJSON
err
...
...
src/Gargantext/API/Routes/Client.hs
View file @
58d9fcb0
...
@@ -38,7 +38,7 @@ clientRoutes = genericClient
...
@@ -38,7 +38,7 @@ clientRoutes = genericClient
remoteImportClient
::
Auth
.
Token
remoteImportClient
::
Auth
.
Token
->
C
.
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
C
.
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
ClientM
(
C
.
ConduitT
()
Named
.
RemoteBinaryData
IO
()
)
->
ClientM
()
remoteImportClient
(
S
.
Token
.
TE
.
encodeUtf8
->
token
)
c
=
remoteImportClient
(
S
.
Token
.
TE
.
encodeUtf8
->
token
)
c
=
clientRoutes
&
apiWithCustomErrorScheme
clientRoutes
&
apiWithCustomErrorScheme
&
(
$
GES_new
)
&
(
$
GES_new
)
...
...
src/Gargantext/API/Routes/Named/Remote.hs
View file @
58d9fcb0
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DerivingStrategies #-}
module
Gargantext.API.Routes.Named.Remote
(
module
Gargantext.API.Routes.Named.Remote
(
-- * Routes types
-- * Routes types
RemoteAPI
(
..
)
RemoteAPI
(
..
)
...
@@ -8,6 +9,7 @@ module Gargantext.API.Routes.Named.Remote (
...
@@ -8,6 +9,7 @@ module Gargantext.API.Routes.Named.Remote (
,
RemoteBinaryData
(
..
)
,
RemoteBinaryData
(
..
)
)
where
)
where
import
Conduit
qualified
as
C
import
Data.Aeson
as
JSON
import
Data.Aeson
as
JSON
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.ByteString
qualified
as
BS
import
Data.ByteString
qualified
as
BS
...
@@ -20,7 +22,6 @@ import Prelude
...
@@ -20,7 +22,6 @@ import Prelude
import
Servant.API
import
Servant.API
import
Servant.Client.Core.BaseUrl
import
Servant.Client.Core.BaseUrl
import
Test.QuickCheck
import
Test.QuickCheck
import
qualified
Conduit
as
C
data
RemoteAPI
mode
=
RemoteAPI
data
RemoteAPI
mode
=
RemoteAPI
...
@@ -77,5 +78,5 @@ instance ToSchema RemoteBinaryData where
...
@@ -77,5 +78,5 @@ instance ToSchema RemoteBinaryData where
data
RemoteAPI'
mode
=
RemoteAPI'
data
RemoteAPI'
mode
=
RemoteAPI'
{
remoteExportEp
::
mode
:-
"export"
:>
ReqBody
'[
J
SON
]
RemoteExportRequest
:>
Post
'[
J
SON
]
()
{
remoteExportEp
::
mode
:-
"export"
:>
ReqBody
'[
J
SON
]
RemoteExportRequest
:>
Post
'[
J
SON
]
()
,
remoteImportEp
::
mode
:-
"import"
:>
StreamBody
NoFraming
OctetStream
(
C
.
ConduitT
()
RemoteBinaryData
IO
()
)
,
remoteImportEp
::
mode
:-
"import"
:>
StreamBody
NoFraming
OctetStream
(
C
.
ConduitT
()
RemoteBinaryData
IO
()
)
:>
StreamPost
NoFraming
OctetStream
(
C
.
ConduitT
()
RemoteBinaryData
IO
()
)
:>
Post
'[
J
SON
]
(
)
}
deriving
Generic
}
deriving
Generic
src/Gargantext/API/Server/Named/Remote.hs
View file @
58d9fcb0
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module
Gargantext.API.Server.Named.Remote
(
module
Gargantext.API.Server.Named.Remote
(
remoteAPI
remoteAPI
...
@@ -9,16 +10,21 @@ module Gargantext.API.Server.Named.Remote (
...
@@ -9,16 +10,21 @@ module Gargantext.API.Server.Named.Remote (
import
Codec.Serialise
import
Codec.Serialise
import
Conduit
import
Conduit
import
Control.Lens
(
view
)
import
Control.Exception.Safe
qualified
as
Safe
import
Control.Exception
(
toException
)
import
Control.Lens
(
view
,
(
#
))
import
Control.Monad.Except
(
throwError
)
import
Data.ByteString.Builder
qualified
as
B
import
Data.ByteString.Builder
qualified
as
B
import
Data.ByteString.Char8
qualified
as
C8
import
Data.ByteString.Char8
qualified
as
C8
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.Conduit.Combinators
qualified
as
C
import
Data.Conduit.Combinators
qualified
as
C
import
Data.Conduit.List
qualified
as
CL
import
Data.Conduit.List
qualified
as
CL
import
Gargantext.API.Errors.Types
import
Gargantext.API.Prelude
(
IsGargServer
)
import
Gargantext.API.Prelude
(
IsGargServer
)
import
Gargantext.API.Routes.Client
(
remoteImportClient
)
import
Gargantext.API.Routes.Client
(
remoteImportClient
)
import
Gargantext.API.Routes.Named.Remote
qualified
as
Named
import
Gargantext.API.Routes.Named.Remote
qualified
as
Named
import
Gargantext.Core.Config
import
Gargantext.Core.Config
import
Gargantext.Database.Prelude
(
IsDBCmd
)
import
Prelude
import
Prelude
import
Servant.Client.Streaming
(
mkClientEnv
,
withClientM
,
ClientError
)
import
Servant.Client.Streaming
(
mkClientEnv
,
withClientM
,
ClientError
)
import
Servant.Server.Generic
(
AsServerT
)
import
Servant.Server.Generic
(
AsServerT
)
...
@@ -27,19 +33,21 @@ remoteAPI :: (MonadIO m, IsGargServer env err m) => Named.RemoteAPI (AsServerT m
...
@@ -27,19 +33,21 @@ remoteAPI :: (MonadIO m, IsGargServer env err m) => Named.RemoteAPI (AsServerT m
remoteAPI
=
Named
.
RemoteAPI
$
remoteAPI
=
Named
.
RemoteAPI
$
Named
.
RemoteAPI'
Named
.
RemoteAPI'
{
remoteExportEp
=
remoteExportHandler
{
remoteExportEp
=
remoteExportHandler
,
remoteImportEp
=
pure
,
remoteImportEp
=
remoteImportHandler
}
}
type
ExpectedPayload
=
C8
.
ByteString
-- FIXME(adn)
type
ExpectedPayload
=
C8
.
ByteString
-- FIXME(adn)
remoteImportHandler
::
(
MonadIO
m
,
Serialise
a
)
=>
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
m
a
remoteImportHandler
::
(
HasBackendInternalError
err
,
IsDBCmd
env
err
m
,
MonadIO
m
)
remoteImportHandler
c
=
liftIO
$
do
=>
ConduitT
()
Named
.
RemoteBinaryData
IO
()
chunks
<-
sourceToList
$
c
.|
C
.
map
(
B
.
byteString
.
Named
.
getRemoteBinaryData
)
->
m
()
case
deserialiseOrFail
(
B
.
toLazyByteString
$
mconcat
chunks
)
of
remoteImportHandler
c
=
do
Left
err
->
liftIO
$
error
$
"Deserialization error: "
++
show
err
chunks
<-
liftIO
$
sourceToList
$
c
.|
C
.
map
(
B
.
byteString
.
Named
.
getRemoteBinaryData
)
Right
value
->
pure
value
case
deserialiseOrFail
@
ExpectedPayload
(
B
.
toLazyByteString
$
mconcat
chunks
)
of
Left
err
->
throwError
$
_BackendInternalError
#
InternalUnexpectedError
(
toException
$
userError
$
"Deserialization error: "
++
show
err
)
Right
value
->
liftIO
$
putStrLn
$
show
$
value
remoteExportHandler
::
(
MonadIO
m
remoteExportHandler
::
(
MonadIO
m
,
Safe
.
MonadCatch
m
,
IsGargServer
err
env
m
,
IsGargServer
err
env
m
)
)
=>
Named
.
RemoteExportRequest
=>
Named
.
RemoteExportRequest
...
@@ -48,13 +56,14 @@ remoteExportHandler Named.RemoteExportRequest{..} = do
...
@@ -48,13 +56,14 @@ remoteExportHandler Named.RemoteExportRequest{..} = do
mgr
<-
view
gargHttpManager
mgr
<-
view
gargHttpManager
-- FIXME(adn) eventually we want to be sending nodes here.
-- FIXME(adn) eventually we want to be sending nodes here.
let
node
=
C8
.
pack
"hello world"
let
node
=
C8
.
pack
"hello world"
result
<-
liftIO
$
withClientM
(
remoteImportClient
_rer_instance_auth
(
streamEncoder
node
))
(
mkClientEnv
mgr
_rer_instance_url
)
streamDecode
liftIO
(
withClientM
(
remoteImportClient
_rer_instance_auth
(
streamEncoder
node
))
(
mkClientEnv
mgr
_rer_instance_url
)
streamDecode
)
liftIO
$
putStrLn
(
show
(
result
::
ExpectedPayload
))
`
Safe
.
catch
`
\
(
e
::
BackendInternalError
)
->
throwError
$
_BackendInternalError
#
e
streamEncoder
::
Serialise
a
=>
a
->
ConduitT
()
Named
.
RemoteBinaryData
IO
()
streamEncoder
::
(
MonadIO
m
,
Serialise
a
)
=>
a
->
ConduitT
()
Named
.
RemoteBinaryData
m
()
streamEncoder
=
CL
.
sourceList
.
map
Named
.
RemoteBinaryData
.
BL
.
toChunks
.
serialise
streamEncoder
=
CL
.
sourceList
.
map
Named
.
RemoteBinaryData
.
BL
.
toChunks
.
serialise
streamDecode
::
Either
ClientError
(
ConduitT
()
Named
.
RemoteBinaryData
IO
()
)
->
IO
ExpectedPayload
-- | Returns a conduit which can be used to decode
streamDecode
::
Either
ClientError
()
->
IO
()
streamDecode
=
\
case
streamDecode
=
\
case
Left
err
->
error
$
show
err
-- FIXME(adn) How to deal with the error properly?
Left
err
->
Safe
.
throwIO
$
InternalUnexpectedError
(
toException
$
userError
$
show
err
)
Right
c
->
remoteImportHandler
c
Right
_
->
pure
()
Przemyslaw Kaminski
@cgenie
mentioned in commit
942e663f
·
Jan 29, 2025
mentioned in commit
942e663f
mentioned in commit 942e663f539b287b4cc0469fe2bcf735813b4ff2
Toggle commit list
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment