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
160
Issues
160
List
Board
Labels
Milestones
Merge Requests
14
Merge Requests
14
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 (
,
GraphQLError
(
..
)
,
ToFrontendErrorData
(
..
)
,
AccessPolicyErrorReason
(
..
)
,
HasBackendInternalError
(
..
)
-- * Constructing frontend errors
,
mkFrontendErrNoDiagnostic
...
...
@@ -67,6 +68,7 @@ import Gargantext.Prelude hiding (Location, WithStacktrace)
import
Gargantext.Utils.Dict
(
Dict
(
..
))
import
Gargantext.Utils.Jobs.Monad
qualified
as
Jobs
import
Servant
(
ServerError
)
import
Control.Lens.Prism
(
prism'
)
-- | A 'WithStacktrace' carries an error alongside its
-- 'CallStack', to be able to print the correct source location
...
...
@@ -121,6 +123,12 @@ data BackendInternalError
makePrisms
''
B
ackendInternalError
class
HasBackendInternalError
e
where
_BackendInternalError
::
Prism'
e
BackendInternalError
instance
HasBackendInternalError
BackendInternalError
where
_BackendInternalError
=
prism'
identity
Just
instance
ToJSON
BackendInternalError
where
toJSON
(
InternalJobError
s
)
=
object
[
(
"status"
,
toJSON
(
"IsFailure"
::
Text
))
...
...
src/Gargantext/API/Prelude.hs
View file @
58d9fcb0
...
...
@@ -17,11 +17,12 @@ module Gargantext.API.Prelude
,
HasServerError
(
..
)
,
serverError
)
where
import
Control.Exception.Safe
qualified
as
Safe
import
Control.Lens
((
#
))
import
Control.Monad.Random
(
MonadRandom
)
import
Gargantext.API.Admin.Auth.Types
(
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.Config
(
HasConfig
,
HasManager
)
import
Gargantext.Core.Mail.Types
(
HasMail
)
...
...
@@ -54,6 +55,7 @@ type ErrC err =
,
HasValidationError
err
,
HasTreeError
err
,
HasServerError
err
,
HasBackendInternalError
err
,
HasAuthenticationError
err
-- , ToJSON err -- TODO this is arguable
,
Exception
err
...
...
@@ -63,6 +65,7 @@ type GargServerC env err m =
(
HasNodeStory
env
err
m
,
HasMail
env
,
MonadRandom
m
,
Safe
.
MonadCatch
m
,
EnvC
env
,
ErrC
err
,
ToJSON
err
...
...
src/Gargantext/API/Routes/Client.hs
View file @
58d9fcb0
...
...
@@ -38,7 +38,7 @@ clientRoutes = genericClient
remoteImportClient
::
Auth
.
Token
->
C
.
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
ClientM
(
C
.
ConduitT
()
Named
.
RemoteBinaryData
IO
()
)
->
ClientM
()
remoteImportClient
(
S
.
Token
.
TE
.
encodeUtf8
->
token
)
c
=
clientRoutes
&
apiWithCustomErrorScheme
&
(
$
GES_new
)
...
...
src/Gargantext/API/Routes/Named/Remote.hs
View file @
58d9fcb0
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DerivingStrategies #-}
module
Gargantext.API.Routes.Named.Remote
(
-- * Routes types
RemoteAPI
(
..
)
...
...
@@ -8,6 +9,7 @@ module Gargantext.API.Routes.Named.Remote (
,
RemoteBinaryData
(
..
)
)
where
import
Conduit
qualified
as
C
import
Data.Aeson
as
JSON
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.ByteString
qualified
as
BS
...
...
@@ -20,7 +22,6 @@ import Prelude
import
Servant.API
import
Servant.Client.Core.BaseUrl
import
Test.QuickCheck
import
qualified
Conduit
as
C
data
RemoteAPI
mode
=
RemoteAPI
...
...
@@ -77,5 +78,5 @@ instance ToSchema RemoteBinaryData where
data
RemoteAPI'
mode
=
RemoteAPI'
{
remoteExportEp
::
mode
:-
"export"
:>
ReqBody
'[
J
SON
]
RemoteExportRequest
:>
Post
'[
J
SON
]
()
,
remoteImportEp
::
mode
:-
"import"
:>
StreamBody
NoFraming
OctetStream
(
C
.
ConduitT
()
RemoteBinaryData
IO
()
)
:>
StreamPost
NoFraming
OctetStream
(
C
.
ConduitT
()
RemoteBinaryData
IO
()
)
:>
Post
'[
J
SON
]
(
)
}
deriving
Generic
src/Gargantext/API/Server/Named/Remote.hs
View file @
58d9fcb0
...
...
@@ -2,6 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module
Gargantext.API.Server.Named.Remote
(
remoteAPI
...
...
@@ -9,16 +10,21 @@ module Gargantext.API.Server.Named.Remote (
import
Codec.Serialise
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.Char8
qualified
as
C8
import
Data.ByteString.Lazy
qualified
as
BL
import
Data.Conduit.Combinators
qualified
as
C
import
Data.Conduit.List
qualified
as
CL
import
Gargantext.API.Errors.Types
import
Gargantext.API.Prelude
(
IsGargServer
)
import
Gargantext.API.Routes.Client
(
remoteImportClient
)
import
Gargantext.API.Routes.Named.Remote
qualified
as
Named
import
Gargantext.Core.Config
import
Gargantext.Database.Prelude
(
IsDBCmd
)
import
Prelude
import
Servant.Client.Streaming
(
mkClientEnv
,
withClientM
,
ClientError
)
import
Servant.Server.Generic
(
AsServerT
)
...
...
@@ -27,19 +33,21 @@ remoteAPI :: (MonadIO m, IsGargServer env err m) => Named.RemoteAPI (AsServerT m
remoteAPI
=
Named
.
RemoteAPI
$
Named
.
RemoteAPI'
{
remoteExportEp
=
remoteExportHandler
,
remoteImportEp
=
pure
,
remoteImportEp
=
remoteImportHandler
}
type
ExpectedPayload
=
C8
.
ByteString
-- FIXME(adn)
remoteImportHandler
::
(
MonadIO
m
,
Serialise
a
)
=>
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
m
a
remoteImportHandler
c
=
liftIO
$
do
chunks
<-
sourceToList
$
c
.|
C
.
map
(
B
.
byteString
.
Named
.
getRemoteBinaryData
)
case
deserialiseOrFail
(
B
.
toLazyByteString
$
mconcat
chunks
)
of
Left
err
->
liftIO
$
error
$
"Deserialization error: "
++
show
err
Right
value
->
pure
value
remoteImportHandler
::
(
HasBackendInternalError
err
,
IsDBCmd
env
err
m
,
MonadIO
m
)
=>
ConduitT
()
Named
.
RemoteBinaryData
IO
()
->
m
()
remoteImportHandler
c
=
do
chunks
<-
liftIO
$
sourceToList
$
c
.|
C
.
map
(
B
.
byteString
.
Named
.
getRemoteBinaryData
)
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
)
=>
Named
.
RemoteExportRequest
...
...
@@ -48,13 +56,14 @@ remoteExportHandler Named.RemoteExportRequest{..} = do
mgr
<-
view
gargHttpManager
-- FIXME(adn) eventually we want to be sending nodes here.
let
node
=
C8
.
pack
"hello world"
result
<-
liftIO
$
withClientM
(
remoteImportClient
_rer_instance_auth
(
streamEncoder
node
))
(
mkClientEnv
mgr
_rer_instance_url
)
streamDecode
liftIO
$
putStrLn
(
show
(
result
::
ExpectedPayload
))
liftIO
(
withClientM
(
remoteImportClient
_rer_instance_auth
(
streamEncoder
node
))
(
mkClientEnv
mgr
_rer_instance_url
)
streamDecode
)
`
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
streamDecode
::
Either
ClientError
(
ConduitT
()
Named
.
RemoteBinaryData
IO
()
)
->
IO
ExpectedPayload
-- | Returns a conduit which can be used to decode
streamDecode
::
Either
ClientError
()
->
IO
()
streamDecode
=
\
case
Left
err
->
error
$
show
err
-- FIXME(adn) How to deal with the error properly?
Right
c
->
remoteImportHandler
c
Left
err
->
Safe
.
throwIO
$
InternalUnexpectedError
(
toException
$
userError
$
show
err
)
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