@@ -20,8 +20,6 @@ module Network.JsonRpc.Server (
20
20
RpcResult
21
21
, Method
22
22
, toMethod
23
- , Methods
24
- , toMethods
25
23
, call
26
24
, callWithBatchStrategy
27
25
, Parameter (.. )
@@ -30,7 +28,10 @@ module Network.JsonRpc.Server (
30
28
-- ** Errors
31
29
, RpcError (.. )
32
30
, rpcError
33
- , rpcErrorWithData ) where
31
+ , rpcErrorWithData
32
+ -- ** Deprecated
33
+ , Methods
34
+ , toMethods ) where
34
35
35
36
import Network.JsonRpc.Types
36
37
import Data.Text (Text , append , pack )
@@ -40,7 +41,7 @@ import qualified Data.Aeson as A
40
41
import qualified Data.Vector as V
41
42
import qualified Data.HashMap.Strict as H
42
43
import Control.DeepSeq (NFData )
43
- import Control.Monad (liftM )
44
+ import Control.Monad (liftM , (<=<) )
44
45
import Control.Monad.Identity (runIdentity )
45
46
import Control.Monad.Except (runExceptT , throwError )
46
47
@@ -52,10 +53,8 @@ import Control.Applicative ((<$>))
52
53
-- * Create methods by calling 'toMethod' and providing the method
53
54
-- names, lists of parameters, and functions to be called.
54
55
--
55
- -- * Create a set of methods by calling 'toMethods'.
56
- --
57
56
-- * Process a request by calling 'call' or 'callWithBatchStrategy'
58
- -- on the 'Methods' and input 'B.ByteString'.
57
+ -- on the 'Method's and input 'B.ByteString'.
59
58
60
59
-- $requests
61
60
-- This library handles by-name and by-position arguments, batch and
@@ -78,54 +77,65 @@ import Control.Applicative ((<$>))
78
77
-- | Creates a method from a name, function, and parameter descriptions.
79
78
-- The parameter names must be unique.
80
79
toMethod :: (MethodParams f p m r , A. ToJSON r , Monad m ) => Text -> f -> p -> Method m
81
- toMethod name f params = let f' args = A. toJSON <$> _apply f params args
80
+ toMethod name f params = let f' args = A. toJSON `liftM` _apply f params args
82
81
in Method name f'
83
82
84
- -- | Creates a set of methods to be called by name. The names must be unique.
83
+ type Methods m = [Method m ]
84
+ {-# DEPRECATED Methods "Use ['Method' m]." #-}
85
+
85
86
toMethods :: [Method m ] -> Methods m
86
- toMethods fs = Methods $ H. fromList $ map pair fs
87
- where pair mth@ (Method name _) = (name, mth)
87
+ toMethods = id
88
+ {-# DEPRECATED toMethods "Use 'call' directly." #-}
89
+
90
+ type MethodMap m = H. HashMap Text (Method m )
88
91
89
92
-- | Handles one JSON-RPC request. It is the same as
90
93
-- @callWithBatchStrategy sequence@.
91
- call :: Monad m => Methods m -- ^ Choice of methods to call.
94
+ call :: Monad m => [ Method m ] -- ^ Choice of methods to call.
92
95
-> B. ByteString -- ^ JSON-RPC request.
93
96
-> m (Maybe B. ByteString ) -- ^ The response wrapped in 'Just', or
94
97
-- 'Nothing' in the case of a notification,
95
98
-- all wrapped in the given monad.
96
99
call = callWithBatchStrategy sequence
97
100
98
- -- | Handles one JSON-RPC request.
101
+ -- | Handles one JSON-RPC request. The method names must be unique.
99
102
callWithBatchStrategy :: Monad m =>
100
103
(forall a . NFData a => [m a ] -> m [a ]) -- ^ Function specifying the
101
104
-- evaluation strategy.
102
- -> Methods m -- ^ Choice of methods to call.
105
+ -> [ Method m ] -- ^ Choice of methods to call.
103
106
-> B. ByteString -- ^ JSON-RPC request.
104
107
-> m (Maybe B. ByteString ) -- ^ The response wrapped in 'Just', or
105
108
-- 'Nothing' in the case of a notification,
106
109
-- all wrapped in the given monad.
107
- callWithBatchStrategy strategy fs input = either returnErr callMethod request
108
- where request :: Either RpcError (Either A. Value [A. Value ])
109
- request = runIdentity $ runExceptT $ parseVal =<< parseJson input
110
- parseJson = maybe invalidJson return . A. decode
111
- parseVal val = case val of
112
- obj@ (A. Object _) -> return $ Left obj
113
- A. Array vec | V. null vec -> throwInvalidRpc " Empty batch request"
114
- | otherwise -> return $ Right $ V. toList vec
115
- _ -> throwInvalidRpc " Not a JSON object or array"
116
- callMethod rq = case rq of
117
- Left val -> encodeJust `liftM` singleCall fs val
118
- Right vals -> encodeJust `liftM` batchCall strategy fs vals
119
- where encodeJust r = A. encode <$> r
120
- returnErr = return . Just . A. encode . nullIdResponse
121
- invalidJson = throwError $ rpcError (- 32700 ) " Invalid JSON"
122
-
123
- singleCall :: Monad m => Methods m -> A. Value -> m (Maybe Response )
124
- singleCall (Methods fs) val = case parsed of
110
+ callWithBatchStrategy strategy methods =
111
+ mthMap `seq` either returnErr callMethod . parse
112
+ where
113
+ mthMap = H. fromList $
114
+ map (\ mth@ (Method name _) -> (name, mth)) methods
115
+ parse :: B. ByteString -> Either RpcError (Either A. Value [A. Value ])
116
+ parse = runIdentity . runExceptT . parseVal <=< parseJson
117
+ parseJson = maybe invalidJson return . A. decode
118
+ parseVal val =
119
+ case val of
120
+ obj@ (A. Object _) -> return $ Left obj
121
+ A. Array vec | V. null vec -> throwInvalidRpc " Empty batch request"
122
+ | otherwise -> return $ Right $ V. toList vec
123
+ _ -> throwInvalidRpc " Not a JSON object or array"
124
+ callMethod rq =
125
+ case rq of
126
+ Left val -> encodeJust `liftM` singleCall mthMap val
127
+ Right vals -> encodeJust `liftM` batchCall strategy mthMap vals
128
+ where
129
+ encodeJust r = A. encode <$> r
130
+ returnErr = return . Just . A. encode . nullIdResponse
131
+ invalidJson = throwError $ rpcError (- 32700 ) " Invalid JSON"
132
+
133
+ singleCall :: Monad m => MethodMap m -> A. Value -> m (Maybe Response )
134
+ singleCall methods val = case parsed of
125
135
Left err -> return $ nullIdResponse err
126
136
Right (Request name args i) ->
127
137
toResponse i `liftM` runExceptT (applyMethodTo args =<< method)
128
- where method = lookupMethod name fs
138
+ where method = lookupMethod name methods
129
139
where parsed = runIdentity $ runExceptT $ parseValue val
130
140
applyMethodTo args (Method _ f) = f args
131
141
@@ -137,19 +147,19 @@ parseValue val = case A.fromJSON val of
137
147
A. Error msg -> throwInvalidRpc $ pack msg
138
148
A. Success x -> return x
139
149
140
- lookupMethod :: Monad m => Text -> H. HashMap Text ( Method m ) -> RpcResult m (Method m )
150
+ lookupMethod :: Monad m => Text -> MethodMap m -> RpcResult m (Method m )
141
151
lookupMethod name = maybe notFound return . H. lookup name
142
152
where notFound = throwError $ rpcError (- 32601 ) $ " Method not found: " `append` name
143
153
144
154
throwInvalidRpc :: Monad m => Text -> RpcResult m a
145
155
throwInvalidRpc = throwError . rpcErrorWithData (- 32600 ) " Invalid JSON-RPC 2.0 request"
146
156
147
157
batchCall :: Monad m => (forall a . NFData a => [m a ] -> m [a ])
148
- -> Methods m
158
+ -> MethodMap m
149
159
-> [A. Value ]
150
160
-> m (Maybe [Response ])
151
- batchCall strategy mths vals = (noNull . catMaybes) `liftM` results
152
- where results = strategy $ map (singleCall mths ) vals
161
+ batchCall strategy methods vals = (noNull . catMaybes) `liftM` results
162
+ where results = strategy $ map (singleCall methods ) vals
153
163
noNull rs = if null rs then Nothing else Just rs
154
164
155
165
toResponse :: A. ToJSON a => Maybe Id -> Either RpcError a -> Maybe Response
0 commit comments