]> Git — Sourcephile - gargantext.git/blob - src/Gargantext/API/Prelude.hs
Merge branch 'dev-phylo' of ssh://gitlab.iscpif.fr:20022/gargantext/haskell-gargantex...
[gargantext.git] / src / Gargantext / API / Prelude.hs
1 {-|
2 Module : Gargantext.API.Prelude
3 Description : Server API main Types
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
8 Portability : POSIX
9
10 -}
11
12 {-# LANGUAGE ConstraintKinds #-}
13 {-# LANGUAGE FunctionalDependencies #-}
14 {-# LANGUAGE TemplateHaskell #-}
15 {-# LANGUAGE TypeOperators #-}
16 {-# LANGUAGE UndecidableInstances #-}
17
18 module Gargantext.API.Prelude
19 ( module Gargantext.API.Prelude
20 , HasServerError(..)
21 , serverError
22 )
23 where
24
25 import Control.Concurrent (threadDelay)
26 import Control.Exception (Exception)
27 import Control.Lens (Prism', (#))
28 import Control.Lens.TH (makePrisms)
29 import Control.Monad.Error.Class (MonadError(..))
30 import Control.Monad.Except (ExceptT)
31 import Control.Monad.Reader (ReaderT)
32 import Crypto.JOSE.Error as Jose
33 import Data.Aeson.Types
34 import Data.Typeable
35 import Data.Validity
36 import Servant
37 import Servant.Job.Async
38 import Servant.Job.Core (HasServerError(..), serverError)
39
40 import Gargantext.API.Admin.Orchestrator.Types
41 import Gargantext.API.Admin.Types
42 import Gargantext.API.Ngrams.Types
43 import Gargantext.Core.Types
44 import Gargantext.Database.Prelude
45 import Gargantext.Database.Query.Table.Node.Error (NodeError(..), HasNodeError(..))
46 import Gargantext.Database.Query.Tree
47 import Gargantext.Prelude
48
49 class HasJoseError e where
50 _JoseError :: Prism' e Jose.Error
51
52 joseError :: (MonadError e m, HasJoseError e) => Jose.Error -> m a
53 joseError = throwError . (_JoseError #)
54
55 class ThrowAll' e a | a -> e where
56 -- | 'throwAll' is a convenience function to throw errors across an entire
57 -- sub-API
58 --
59 --
60 -- > throwAll err400 :: Handler a :<|> Handler b :<|> Handler c
61 -- > == throwError err400 :<|> throwError err400 :<|> err400
62 throwAll' :: e -> a
63
64 instance (ThrowAll' e a, ThrowAll' e b) => ThrowAll' e (a :<|> b) where
65 throwAll' e = throwAll' e :<|> throwAll' e
66
67 -- Really this shouldn't be necessary - ((->) a) should be an instance of
68 -- MonadError, no?
69 instance {-# OVERLAPPING #-} ThrowAll' e b => ThrowAll' e (a -> b) where
70 throwAll' e = const $ throwAll' e
71
72 instance {-# OVERLAPPABLE #-} (MonadError e m) => ThrowAll' e (m a) where
73 throwAll' = throwError
74
75 type GargServerC env err m =
76 ( CmdM env err m
77 , HasNodeError err
78 , HasInvalidError err
79 , HasTreeError err
80 , HasServerError err
81 , HasJoseError err
82 , ToJSON err -- TODO this is arguable
83 , Exception err
84 , HasRepo env -- TODO rename HasNgramsRepo
85 , HasSettings env -- TODO rename HasDbSettings
86 , HasJobEnv env JobLog JobLog
87 , HasConfig env
88 )
89
90
91 type GargServer api =
92 forall env err m. GargServerT env err m api
93
94 type GargServerT env err m api = GargServerC env err m => ServerT api m
95
96 -- This is the concrete monad. It needs to be used as little as possible,
97 -- instead, prefer GargServer, GargServerT, GargServerC.
98 type GargServerM env err = ReaderT env (ExceptT err IO)
99
100 type EnvC env =
101 ( HasConnectionPool env
102 , HasRepo env
103 , HasSettings env
104 , HasJobEnv env JobLog JobLog
105 , HasConfig env
106 )
107
108 -------------------------------------------------------------------
109 -- | This Type is needed to prepare the function before the GargServer
110 type GargNoServer t =
111 forall env err m. GargNoServer' env err m => m t
112
113 type GargNoServer' env err m =
114 ( CmdM env err m
115 , HasRepo env
116 , HasSettings env
117 , HasNodeError err
118 )
119
120 -------------------------------------------------------------------
121
122 data GargError
123 = GargNodeError NodeError
124 | GargTreeError TreeError
125 | GargInvalidError Validation
126 | GargJoseError Jose.Error
127 | GargServerError ServerError
128 deriving (Show, Typeable)
129
130 makePrisms ''GargError
131
132 instance ToJSON GargError where
133 toJSON _ = String "SomeGargErrorPleaseReport"
134
135 instance Exception GargError
136
137 instance HasNodeError GargError where
138 _NodeError = _GargNodeError
139
140 instance HasInvalidError GargError where
141 _InvalidError = _GargInvalidError
142
143 instance HasTreeError GargError where
144 _TreeError = _GargTreeError
145
146 instance HasServerError GargError where
147 _ServerError = _GargServerError
148
149 instance HasJoseError GargError where
150 _JoseError = _GargJoseError
151
152
153 ------------------------------------------------------------------------
154 -- | Utils
155 -- | Simulate logs
156 simuLogs :: MonadBase IO m
157 => (JobLog -> m ())
158 -> Int
159 -> m JobLog
160 simuLogs logStatus t = do
161 _ <- mapM (\n -> simuTask logStatus n t) $ take t [0,1..]
162 pure $ JobLog { _scst_succeeded = Just t
163 , _scst_failed = Just 0
164 , _scst_remaining = Just 0
165 , _scst_events = Just []
166 }
167
168 simuTask :: MonadBase IO m
169 => (JobLog -> m ())
170 -> Int
171 -> Int
172 -> m ()
173 simuTask logStatus cur total = do
174 let m = (10 :: Int) ^ (6 :: Int)
175 liftBase $ threadDelay (m*5)
176
177 let status = JobLog { _scst_succeeded = Just cur
178 , _scst_failed = Just 0
179 , _scst_remaining = (-) <$> Just total <*> Just cur
180 , _scst_events = Just []
181 }
182 printDebug "status" status
183 logStatus status