diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-08 06:26:35 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-08 06:26:35 +0400 |
commit | 6f909c0d81d04b997f8c81ec1ac05e94d7d1e5b6 (patch) | |
tree | 0926f49f12d629fd4813be043e7c5976d0455e14 /src/Network/KRPC | |
parent | fe87b6cec9504114dafca26166b51f6c48250106 (diff) |
Add HandlerFailure exceptions
Diffstat (limited to 'src/Network/KRPC')
-rw-r--r-- | src/Network/KRPC/Manager.hs | 60 | ||||
-rw-r--r-- | src/Network/KRPC/Message.hs | 17 |
2 files changed, 51 insertions, 26 deletions
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs index 6799277f..222b961a 100644 --- a/src/Network/KRPC/Manager.hs +++ b/src/Network/KRPC/Manager.hs | |||
@@ -31,6 +31,7 @@ module Network.KRPC.Manager | |||
31 | , query | 31 | , query |
32 | 32 | ||
33 | -- * Handlers | 33 | -- * Handlers |
34 | , HandlerFailure (..) | ||
34 | , Handler | 35 | , Handler |
35 | , handler | 36 | , handler |
36 | ) where | 37 | ) where |
@@ -39,7 +40,8 @@ import Control.Applicative | |||
39 | import Control.Concurrent | 40 | import Control.Concurrent |
40 | import Control.Concurrent.Lifted (fork) | 41 | import Control.Concurrent.Lifted (fork) |
41 | import Control.Exception hiding (Handler) | 42 | import Control.Exception hiding (Handler) |
42 | import Control.Exception.Lifted as Lifted (catch, finally) | 43 | import qualified Control.Exception.Lifted as E (Handler (..)) |
44 | import Control.Exception.Lifted as Lifted (catches, finally) | ||
43 | import Control.Monad | 45 | import Control.Monad |
44 | import Control.Monad.Logger | 46 | import Control.Monad.Logger |
45 | import Control.Monad.Reader | 47 | import Control.Monad.Reader |
@@ -288,9 +290,38 @@ query addr params = do | |||
288 | {----------------------------------------------------------------------- | 290 | {----------------------------------------------------------------------- |
289 | -- Handlers | 291 | -- Handlers |
290 | -----------------------------------------------------------------------} | 292 | -----------------------------------------------------------------------} |
293 | -- we already throw: | ||
294 | -- | ||
295 | -- * ErrorCode(MethodUnknown) in the 'dispatchHandler'; | ||
296 | -- | ||
297 | -- * ErrorCode(ServerError) in the 'runHandler'; (those can be | ||
298 | -- async exception too) | ||
299 | -- | ||
300 | -- * ErrorCode(GenericError) on | ||
301 | |||
302 | -- | Used to signal protocol errors. | ||
303 | data HandlerFailure | ||
304 | = BadAddress -- ^ for e.g.: node calls herself; | ||
305 | | InvalidParameter Text -- ^ for e.g.: bad session token. | ||
306 | deriving (Show, Eq, Typeable) | ||
307 | |||
308 | instance Exception HandlerFailure | ||
309 | |||
310 | prettyHF :: HandlerFailure -> BS.ByteString | ||
311 | prettyHF BadAddress = T.encodeUtf8 "bad address" | ||
312 | prettyHF (InvalidParameter reason) = T.encodeUtf8 $ | ||
313 | "invalid parameter: " <> reason | ||
314 | |||
315 | prettyQF :: QueryFailure -> BS.ByteString | ||
316 | prettyQF e = T.encodeUtf8 $ "handler fail while performing query: " | ||
317 | <> T.pack (show e) | ||
291 | 318 | ||
292 | -- | Make handler from handler function. Any thrown exception will be | 319 | -- | Make handler from handler function. Any thrown exception will be |
293 | -- supressed and send over the wire back to the querying node. | 320 | -- supressed and send over the wire back to the querying node. |
321 | -- | ||
322 | -- If the handler make some 'query' normally it /should/ handle | ||
323 | -- corresponding 'QueryFailure's. | ||
324 | -- | ||
294 | handler :: forall h a b. (KRPC a b, Monad h) | 325 | handler :: forall h a b. (KRPC a b, Monad h) |
295 | => (SockAddr -> a -> h b) -> Handler h | 326 | => (SockAddr -> a -> h b) -> Handler h |
296 | handler body = (name, wrapper) | 327 | handler body = (name, wrapper) |
@@ -305,7 +336,7 @@ handler body = (name, wrapper) | |||
305 | 336 | ||
306 | runHandler :: MonadKRPC h m | 337 | runHandler :: MonadKRPC h m |
307 | => HandlerBody h -> SockAddr -> KQuery -> m KResult | 338 | => HandlerBody h -> SockAddr -> KQuery -> m KResult |
308 | runHandler h addr KQuery {..} = wrapper `Lifted.catch` failback | 339 | runHandler h addr KQuery {..} = Lifted.catches wrapper failbacks |
309 | where | 340 | where |
310 | signature = querySignature queryMethod queryId addr | 341 | signature = querySignature queryMethod queryId addr |
311 | 342 | ||
@@ -315,22 +346,33 @@ runHandler h addr KQuery {..} = wrapper `Lifted.catch` failback | |||
315 | 346 | ||
316 | case result of | 347 | case result of |
317 | Left msg -> do | 348 | Left msg -> do |
318 | $(logDebugS) "handler.failed" $ signature <> " !" <> T.pack msg | 349 | $(logDebugS) "handler.bad_query" $ signature <> " !" <> T.pack msg |
319 | return $ Left $ decodeError msg queryId | 350 | return $ Left $ KError ProtocolError (BC.pack msg) queryId |
320 | 351 | ||
321 | Right a -> do | 352 | Right a -> do |
322 | $(logDebugS) "handler.success" signature | 353 | $(logDebugS) "handler.success" signature |
323 | return $ Right $ a `KResponse` queryId | 354 | return $ Right $ KResponse a queryId |
355 | |||
356 | failbacks = | ||
357 | [ E.Handler $ \ (e :: HandlerFailure) -> do | ||
358 | $(logDebugS) "handler.failed" signature | ||
359 | return $ Left $ KError ProtocolError (prettyHF e) queryId | ||
360 | |||
361 | -- may happen if handler makes query and fail | ||
362 | , E.Handler $ \ (e :: QueryFailure) -> do | ||
363 | return $ Left $ KError ServerError (prettyQF e) queryId | ||
324 | 364 | ||
325 | failback e = do | 365 | -- since handler thread exit after sendMessage we can safely |
326 | $(logDebugS) "handler.errored" signature | 366 | -- suppress async exception here |
327 | return $ Left $ serverError e queryId | 367 | , E.Handler $ \ (e :: SomeException) -> do |
368 | return $ Left $ KError GenericError (BC.pack (show e)) queryId | ||
369 | ] | ||
328 | 370 | ||
329 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult | 371 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult |
330 | dispatchHandler q @ KQuery {..} addr = do | 372 | dispatchHandler q @ KQuery {..} addr = do |
331 | Manager {..} <- getManager | 373 | Manager {..} <- getManager |
332 | case L.lookup queryMethod handlers of | 374 | case L.lookup queryMethod handlers of |
333 | Nothing -> return $ Left $ unknownMethod queryMethod queryId | 375 | Nothing -> return $ Left $ KError MethodUnknown queryMethod queryId |
334 | Just h -> runHandler h addr q | 376 | Just h -> runHandler h addr q |
335 | 377 | ||
336 | {----------------------------------------------------------------------- | 378 | {----------------------------------------------------------------------- |
diff --git a/src/Network/KRPC/Message.hs b/src/Network/KRPC/Message.hs index d6279f11..96945843 100644 --- a/src/Network/KRPC/Message.hs +++ b/src/Network/KRPC/Message.hs | |||
@@ -26,11 +26,8 @@ module Network.KRPC.Message | |||
26 | -- * Error | 26 | -- * Error |
27 | , ErrorCode (..) | 27 | , ErrorCode (..) |
28 | , KError(..) | 28 | , KError(..) |
29 | , serverError | ||
30 | , decodeError | 29 | , decodeError |
31 | , unknownMethod | ||
32 | , unknownMessage | 30 | , unknownMessage |
33 | , timeoutExpired | ||
34 | 31 | ||
35 | -- * Query | 32 | -- * Query |
36 | , KQuery(..) | 33 | , KQuery(..) |
@@ -143,29 +140,15 @@ instance BEncode KError where | |||
143 | 140 | ||
144 | instance Exception KError | 141 | instance Exception KError |
145 | 142 | ||
146 | -- | Happen when some query handler fail. | ||
147 | serverError :: SomeException -> TransactionId -> KError | ||
148 | serverError e = KError ServerError (BC.pack (show e)) | ||
149 | |||
150 | -- | Received 'queryArgs' or 'respVals' can not be decoded. | 143 | -- | Received 'queryArgs' or 'respVals' can not be decoded. |
151 | decodeError :: String -> TransactionId -> KError | 144 | decodeError :: String -> TransactionId -> KError |
152 | decodeError msg = KError ProtocolError (BC.pack msg) | 145 | decodeError msg = KError ProtocolError (BC.pack msg) |
153 | 146 | ||
154 | -- | If /remote/ node send query /this/ node doesn't know about then | ||
155 | -- this error message should be sent in response. | ||
156 | unknownMethod :: MethodName -> TransactionId -> KError | ||
157 | unknownMethod = KError MethodUnknown | ||
158 | |||
159 | -- | A remote node has send some 'KMessage' this node is unable to | 147 | -- | A remote node has send some 'KMessage' this node is unable to |
160 | -- decode. | 148 | -- decode. |
161 | unknownMessage :: String -> KError | 149 | unknownMessage :: String -> KError |
162 | unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction | 150 | unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction |
163 | 151 | ||
164 | -- | A /remote/ node is not responding to the /our/ request the for | ||
165 | -- specified period of time. | ||
166 | timeoutExpired :: TransactionId -> KError | ||
167 | timeoutExpired = KError GenericError "timeout expired" | ||
168 | |||
169 | {----------------------------------------------------------------------- | 152 | {----------------------------------------------------------------------- |
170 | -- Query messages | 153 | -- Query messages |
171 | -----------------------------------------------------------------------} | 154 | -----------------------------------------------------------------------} |