root / src / Ganeti / THH / RPC.hs @ a85aef5c
History | View | Annotate | Download (3.4 kB)
1 |
{-# LANGUAGE TemplateHaskell, ExistentialQuantification #-} |
---|---|
2 |
|
3 |
{-| Implements Template Haskell generation of RPC server components from Haskell |
4 |
functions. |
5 |
|
6 |
-} |
7 |
|
8 |
{- |
9 |
|
10 |
Copyright (C) 2013 Google Inc. |
11 |
|
12 |
This program is free software; you can redistribute it and/or modify |
13 |
it under the terms of the GNU General Public License as published by |
14 |
the Free Software Foundation; either version 2 of the License, or |
15 |
(at your option) any later version. |
16 |
|
17 |
This program is distributed in the hope that it will be useful, but |
18 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
19 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 |
General Public License for more details. |
21 |
|
22 |
You should have received a copy of the GNU General Public License |
23 |
along with this program; if not, write to the Free Software |
24 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
25 |
02110-1301, USA. |
26 |
|
27 |
-} |
28 |
|
29 |
module Ganeti.THH.RPC |
30 |
( Request(..) |
31 |
, RpcServer |
32 |
, dispatch |
33 |
, mkRpcM |
34 |
) where |
35 |
|
36 |
import Control.Applicative |
37 |
import Control.Arrow ((&&&)) |
38 |
import Control.Monad |
39 |
import Control.Monad.Error.Class |
40 |
import Data.Map (Map) |
41 |
import qualified Data.Map as Map |
42 |
import Language.Haskell.TH |
43 |
import qualified Text.JSON as J |
44 |
|
45 |
import Ganeti.BasicTypes |
46 |
import Ganeti.Errors |
47 |
import Ganeti.JSON |
48 |
import Ganeti.THH.Types |
49 |
import qualified Ganeti.UDSServer as US |
50 |
|
51 |
data RpcFn m = forall i o . (J.JSON i, J.JSON o) => RpcFn (i -> m o) |
52 |
|
53 |
type RpcServer m = US.Handler Request m J.JSValue |
54 |
|
55 |
-- | A RPC request consiting of a method and its argument(s). |
56 |
data Request = Request { rMethod :: String, rArgs :: J.JSValue } |
57 |
deriving (Eq, Ord, Show) |
58 |
|
59 |
decodeRequest :: J.JSValue -> J.JSValue -> Result Request |
60 |
decodeRequest method args = Request <$> fromJVal method <*> pure args |
61 |
|
62 |
|
63 |
dispatch :: (Monad m) |
64 |
=> Map String (RpcFn (ResultT GanetiException m)) -> RpcServer m |
65 |
dispatch fs = |
66 |
US.Handler { US.hParse = decodeRequest |
67 |
, US.hInputLogShort = rMethod |
68 |
, US.hInputLogLong = show |
69 |
, US.hExec = liftToHandler . exec |
70 |
} |
71 |
where |
72 |
orError :: (MonadError e m, Error e) => Maybe a -> e -> m a |
73 |
orError m e = maybe (throwError e) return m |
74 |
|
75 |
exec (Request m as) = do |
76 |
(RpcFn f) <- orError (Map.lookup m fs) |
77 |
(strMsg $ "No such method: " ++ m) |
78 |
i <- fromJResultE "RPC input" . J.readJSON $ as |
79 |
o <- f i -- lift $ f i |
80 |
return $ J.showJSON o |
81 |
|
82 |
liftToHandler :: (Monad m) |
83 |
=> ResultT GanetiException m J.JSValue |
84 |
-> US.HandlerResult m J.JSValue |
85 |
liftToHandler = liftM ((,) True) . runResultT |
86 |
|
87 |
-- | Converts a function into the appropriate @RpcFn m@ expression. |
88 |
-- The function's result must be monadic. |
89 |
toRpcFn :: Name -> Q Exp |
90 |
toRpcFn name = [| RpcFn $( uncurryVar name ) |] |
91 |
|
92 |
-- | Convert a list of named expressions into an expression containing a list |
93 |
-- of name/expression pairs. |
94 |
rpcFnsList :: [(String, Q Exp)] -> Q Exp |
95 |
rpcFnsList = listE . map (\(name, expr) -> tupE [stringE name, expr]) |
96 |
|
97 |
-- | Takes a list of function names and creates a RPC handler that delegates |
98 |
-- calls to them. |
99 |
-- |
100 |
-- The functions must conform to |
101 |
-- @(J.JSON i, J.JSON o) => i -> ResultT GanetiException m o@. The @m@ |
102 |
-- monads types of all the functions must unify. |
103 |
-- |
104 |
-- The result expression is of type @RpcServer m@. |
105 |
mkRpcM |
106 |
:: [Name] -- ^ the names of functions to include |
107 |
-> Q Exp |
108 |
mkRpcM names = [| dispatch . Map.fromList $ |
109 |
$( rpcFnsList . map (nameBase &&& toRpcFn) $ names ) |] |