diff options
-rw-r--r-- | krpc.cabal | 1 | ||||
-rw-r--r-- | src/Network/KRPC.hs | 14 | ||||
-rw-r--r-- | src/Network/KRPC/Manager.hs | 105 |
3 files changed, 74 insertions, 46 deletions
@@ -45,6 +45,7 @@ library | |||
45 | , bytestring >= 0.10 | 45 | , bytestring >= 0.10 |
46 | , lifted-base >= 0.1.1 | 46 | , lifted-base >= 0.1.1 |
47 | , transformers >= 0.2 | 47 | , transformers >= 0.2 |
48 | , mtl | ||
48 | , monad-control >= 0.3 | 49 | , monad-control >= 0.3 |
49 | , bencoding >= 0.4.3 | 50 | , bencoding >= 0.4.3 |
50 | , network >= 2.3 | 51 | , network >= 2.3 |
diff --git a/src/Network/KRPC.hs b/src/Network/KRPC.hs index 09d1c5b2..6809a330 100644 --- a/src/Network/KRPC.hs +++ b/src/Network/KRPC.hs | |||
@@ -86,16 +86,6 @@ | |||
86 | -- | 86 | -- |
87 | -- For protocol details see 'Remote.KRPC.Protocol' module. | 87 | -- For protocol details see 'Remote.KRPC.Protocol' module. |
88 | -- | 88 | -- |
89 | {-# LANGUAGE OverloadedStrings #-} | ||
90 | {-# LANGUAGE ViewPatterns #-} | ||
91 | {-# LANGUAGE FlexibleContexts #-} | ||
92 | {-# LANGUAGE DeriveDataTypeable #-} | ||
93 | {-# LANGUAGE ExplicitForAll #-} | ||
94 | {-# LANGUAGE KindSignatures #-} | ||
95 | {-# LANGUAGE ScopedTypeVariables #-} | ||
96 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
97 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
98 | {-# LANGUAGE FunctionalDependencies #-} | ||
99 | module Network.KRPC | 89 | module Network.KRPC |
100 | ( -- * Methods | 90 | ( -- * Methods |
101 | Method | 91 | Method |
@@ -103,10 +93,12 @@ module Network.KRPC | |||
103 | 93 | ||
104 | -- * RPC | 94 | -- * RPC |
105 | , handler | 95 | , handler |
96 | , listen | ||
106 | , query | 97 | , query |
107 | 98 | ||
108 | -- * Manager | 99 | -- * Manager |
109 | , MonadKRPC (..) | 100 | , MonadKRPC (..) |
101 | , Manager | ||
110 | , newManager | 102 | , newManager |
111 | -- , closeManager | 103 | -- , closeManager |
112 | 104 | ||
@@ -116,4 +108,4 @@ module Network.KRPC | |||
116 | 108 | ||
117 | import Network.KRPC.Message | 109 | import Network.KRPC.Message |
118 | import Network.KRPC.Method | 110 | import Network.KRPC.Method |
119 | import Network.KRPC.Manager \ No newline at end of file | 111 | import Network.KRPC.Manager |
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs index 9aa1bea7..64b0dd62 100644 --- a/src/Network/KRPC/Manager.hs +++ b/src/Network/KRPC/Manager.hs | |||
@@ -1,29 +1,40 @@ | |||
1 | {-# LANGUAGE FlexibleContexts #-} | 1 | {-# LANGUAGE FlexibleContexts #-} |
2 | {-# LANGUAGE ScopedTypeVariables #-} | 2 | {-# LANGUAGE ScopedTypeVariables #-} |
3 | {-# LANGUAGE DefaultSignatures #-} | ||
4 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
5 | {-# LANGUAGE FunctionalDependencies #-} | ||
6 | {-# LANGUAGE FlexibleInstances #-} | ||
3 | module Network.KRPC.Manager | 7 | module Network.KRPC.Manager |
4 | ( MonadKRPC (..) | 8 | ( MonadKRPC (..) |
9 | , Manager | ||
5 | , newManager | 10 | , newManager |
11 | , closeManager | ||
6 | , query | 12 | , query |
13 | |||
7 | , handler | 14 | , handler |
15 | , listener | ||
16 | , listen | ||
8 | ) where | 17 | ) where |
9 | 18 | ||
10 | import Control.Applicative | 19 | import Control.Applicative |
11 | import Control.Arrow | 20 | import Control.Arrow |
12 | import Control.Concurrent | 21 | import Control.Concurrent |
13 | --import Control.Exception hiding (Handler) | 22 | import Control.Concurrent.Lifted (fork) |
14 | import Control.Exception.Lifted as Lifted hiding (Handler) | 23 | import Control.Exception hiding (Handler) |
24 | import Control.Exception.Lifted as Lifted (catch) | ||
15 | import Control.Monad | 25 | import Control.Monad |
26 | import Control.Monad.Reader | ||
16 | import Control.Monad.Trans.Control | 27 | import Control.Monad.Trans.Control |
17 | import Control.Monad.IO.Class | ||
18 | import Data.BEncode as BE | 28 | import Data.BEncode as BE |
19 | import Data.ByteString.Char8 as BC | 29 | import Data.ByteString.Char8 as BC |
20 | import Data.ByteString.Lazy as BL | 30 | import Data.ByteString.Lazy as BL |
21 | import Data.IORef | 31 | import Data.IORef |
22 | import Data.List as L | 32 | import Data.List as L |
23 | import Data.Map as M | 33 | import Data.Map as M |
34 | import Data.Tuple | ||
24 | import Network.KRPC.Message | 35 | import Network.KRPC.Message |
25 | import Network.KRPC.Method | 36 | import Network.KRPC.Method |
26 | import Network.Socket | 37 | import Network.Socket hiding (listen) |
27 | import Network.Socket.ByteString as BS | 38 | import Network.Socket.ByteString as BS |
28 | 39 | ||
29 | 40 | ||
@@ -34,18 +45,27 @@ type CallId = (TransactionId, SockAddr) | |||
34 | type CallRes = MVar KResult | 45 | type CallRes = MVar KResult |
35 | type PendingCalls = IORef (Map CallId CallRes) | 46 | type PendingCalls = IORef (Map CallId CallRes) |
36 | 47 | ||
37 | type HandlerBody m = SockAddr -> BValue -> m (BE.Result BValue) | 48 | type HandlerBody h = SockAddr -> BValue -> h (BE.Result BValue) |
38 | type Handler m = (MethodName, HandlerBody m) | 49 | type Handler h = (MethodName, HandlerBody h) |
39 | 50 | ||
40 | data Manager m = Manager | 51 | data Manager h = Manager |
41 | { sock :: !Socket | 52 | { sock :: !Socket |
42 | , transactionCounter :: {-# UNPACK #-} !TransactionCounter | 53 | , transactionCounter :: {-# UNPACK #-} !TransactionCounter |
43 | , pendingCalls :: {-# UNPACK #-} !PendingCalls | 54 | , pendingCalls :: {-# UNPACK #-} !PendingCalls |
44 | , handlers :: [Handler m] | 55 | , handlers :: [Handler h] |
45 | } | 56 | } |
46 | 57 | ||
47 | class (MonadBaseControl IO m, MonadIO m) => MonadKRPC m where | 58 | class (MonadBaseControl IO m, MonadIO m) => MonadKRPC h m | m -> h where |
48 | getManager :: m (Manager a) | 59 | getManager :: m (Manager h) |
60 | |||
61 | default getManager :: MonadReader (Manager h) m => m (Manager h) | ||
62 | getManager = ask | ||
63 | |||
64 | liftHandler :: h a -> m a | ||
65 | |||
66 | instance (MonadBaseControl IO h, MonadIO h) | ||
67 | => MonadKRPC h (ReaderT (Manager h) h) where | ||
68 | liftHandler = lift | ||
49 | 69 | ||
50 | sockAddrFamily :: SockAddr -> Family | 70 | sockAddrFamily :: SockAddr -> Family |
51 | sockAddrFamily (SockAddrInet _ _ ) = AF_INET | 71 | sockAddrFamily (SockAddrInet _ _ ) = AF_INET |
@@ -55,12 +75,12 @@ sockAddrFamily (SockAddrUnix _ ) = AF_UNIX | |||
55 | seedTransaction :: Int | 75 | seedTransaction :: Int |
56 | seedTransaction = 0 | 76 | seedTransaction = 0 |
57 | 77 | ||
58 | newManager :: SockAddr -> IO (Manager a) | 78 | newManager :: SockAddr -> [Handler h] -> IO (Manager h) |
59 | newManager servAddr = do | 79 | newManager servAddr handlers = do |
60 | sock <- bindServ | 80 | sock <- bindServ |
61 | tran <- newIORef seedTransaction | 81 | tran <- newIORef seedTransaction |
62 | calls <- newIORef M.empty | 82 | calls <- newIORef M.empty |
63 | return $ Manager sock tran calls [] | 83 | return $ Manager sock tran calls handlers |
64 | where | 84 | where |
65 | bindServ = do | 85 | bindServ = do |
66 | let family = sockAddrFamily servAddr | 86 | let family = sockAddrFamily servAddr |
@@ -70,8 +90,14 @@ newManager servAddr = do | |||
70 | bindSocket sock servAddr | 90 | bindSocket sock servAddr |
71 | return sock | 91 | return sock |
72 | 92 | ||
93 | -- | Unblock all pending calls and close socket. | ||
94 | closeManager :: Manager m -> IO () | ||
95 | closeManager Manager {..} = do | ||
96 | -- TODO unblock calls | ||
97 | close sock | ||
98 | |||
73 | sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m () | 99 | sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m () |
74 | sendMessage sock addr a = | 100 | sendMessage sock addr a = do |
75 | liftIO $ sendManyTo sock (BL.toChunks (BE.encode a)) addr | 101 | liftIO $ sendManyTo sock (BL.toChunks (BE.encode a)) addr |
76 | 102 | ||
77 | {----------------------------------------------------------------------- | 103 | {----------------------------------------------------------------------- |
@@ -89,9 +115,10 @@ registerQuery cid ref = do | |||
89 | atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ()) | 115 | atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ()) |
90 | return ares | 116 | return ares |
91 | 117 | ||
92 | unregisterQuery :: CallId -> PendingCalls -> IO () | 118 | unregisterQuery :: CallId -> PendingCalls -> IO (Maybe CallRes) |
93 | unregisterQuery cid ref = do | 119 | unregisterQuery cid ref = do |
94 | atomicModifyIORef' ref $ \ m -> (M.delete cid m, ()) | 120 | atomicModifyIORef' ref $ swap . |
121 | M.updateLookupWithKey (const (const Nothing)) cid | ||
95 | 122 | ||
96 | queryResponse :: BEncode a => CallRes -> IO a | 123 | queryResponse :: BEncode a => CallRes -> IO a |
97 | queryResponse ares = do | 124 | queryResponse ares = do |
@@ -103,7 +130,7 @@ queryResponse ares = do | |||
103 | Left e -> throwIO (KError ProtocolError (BC.pack e) respId) | 130 | Left e -> throwIO (KError ProtocolError (BC.pack e) respId) |
104 | Right a -> return a | 131 | Right a -> return a |
105 | 132 | ||
106 | query :: forall m a b. (MonadKRPC m, KRPC a b) => SockAddr -> a -> m b | 133 | query :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m b |
107 | query addr params = do | 134 | query addr params = do |
108 | Manager {..} <- getManager | 135 | Manager {..} <- getManager |
109 | liftIO $ do | 136 | liftIO $ do |
@@ -113,55 +140,60 @@ query addr params = do | |||
113 | ares <- registerQuery (tid, addr) pendingCalls | 140 | ares <- registerQuery (tid, addr) pendingCalls |
114 | sendMessage sock addr q | 141 | sendMessage sock addr q |
115 | `onException` unregisterQuery (tid, addr) pendingCalls | 142 | `onException` unregisterQuery (tid, addr) pendingCalls |
116 | queryResponse ares | 143 | res <- queryResponse ares |
144 | return res | ||
117 | 145 | ||
118 | {----------------------------------------------------------------------- | 146 | {----------------------------------------------------------------------- |
119 | -- Handlers | 147 | -- Handlers |
120 | -----------------------------------------------------------------------} | 148 | -----------------------------------------------------------------------} |
121 | 149 | ||
122 | handler :: forall m a b. (KRPC a b, MonadKRPC m) | 150 | handler :: forall h a b. (KRPC a b, Monad h) |
123 | => (SockAddr -> a -> m b) -> Handler m | 151 | => (SockAddr -> a -> h b) -> Handler h |
124 | handler body = (name, wrapper) | 152 | handler body = (name, wrapper) |
125 | where | 153 | where |
126 | Method name = method :: Method a b | 154 | Method name = method :: Method a b |
127 | wrapper addr args = | 155 | wrapper addr args = |
128 | case fromBEncode args of | 156 | case fromBEncode args of |
129 | Left e -> return $ Left e | 157 | Left e -> return $ Left e |
130 | Right a -> (Right . toBEncode) <$> body addr a | 158 | Right a -> do |
159 | r <- body addr a | ||
160 | return $ Right $ toBEncode r | ||
131 | 161 | ||
132 | runHandler :: MonadKRPC m => HandlerBody m -> SockAddr -> KQuery -> m KResult | 162 | runHandler :: MonadKRPC h m => HandlerBody h -> SockAddr -> KQuery -> m KResult |
133 | runHandler handler addr KQuery {..} = wrapper `Lifted.catch` failback | 163 | runHandler h addr KQuery {..} = wrapper `Lifted.catch` failback |
134 | where | 164 | where |
135 | wrapper = ((`decodeError` queryId) +++ (`KResponse` queryId)) | 165 | wrapper = ((`decodeError` queryId) +++ (`KResponse` queryId)) |
136 | <$> handler addr queryArgs | 166 | <$> liftHandler (h addr queryArgs) |
137 | failback e = return $ Left $ serverError e queryId | 167 | failback e = return $ Left $ serverError e queryId |
138 | 168 | ||
139 | dispatchHandler :: MonadKRPC m => KQuery -> SockAddr -> m KResult | 169 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult |
140 | dispatchHandler q @ KQuery {..} addr = do | 170 | dispatchHandler q @ KQuery {..} addr = do |
141 | Manager {..} <- getManager | 171 | Manager {..} <- getManager |
142 | case L.lookup queryMethod handlers of | 172 | case L.lookup queryMethod handlers of |
143 | Nothing -> return $ Left $ unknownMethod queryMethod queryId | 173 | Nothing -> return $ Left $ unknownMethod queryMethod queryId |
144 | Just handler -> runHandler handler addr q | 174 | Just h -> runHandler h addr q |
145 | 175 | ||
146 | {----------------------------------------------------------------------- | 176 | {----------------------------------------------------------------------- |
147 | -- Listener | 177 | -- Listener |
148 | -----------------------------------------------------------------------} | 178 | -----------------------------------------------------------------------} |
149 | 179 | ||
150 | handleQuery :: MonadKRPC m => KQuery -> SockAddr -> m () | 180 | handleQuery :: MonadKRPC h m => KQuery -> SockAddr -> m () |
151 | handleQuery q addr = do | 181 | handleQuery q addr = do |
152 | Manager {..} <- getManager | 182 | Manager {..} <- getManager |
153 | res <- dispatchHandler q addr | 183 | res <- dispatchHandler q addr |
154 | sendMessage sock addr $ either toBEncode toBEncode res | 184 | sendMessage sock addr $ either toBEncode toBEncode res |
155 | 185 | ||
156 | handleResponse :: MonadKRPC m => KResult -> SockAddr -> m () | 186 | handleResponse :: MonadKRPC h m => KResult -> SockAddr -> m () |
157 | handleResponse result addr = do | 187 | handleResponse result addr = do |
158 | Manager {..} <- getManager | 188 | Manager {..} <- getManager |
159 | mcall <- undefined (addr, respId) pendingCalls | 189 | liftIO $ do |
160 | case mcall of | 190 | let resultId = either errorId respId result |
161 | Nothing -> return () | 191 | mcall <- unregisterQuery (resultId, addr) pendingCalls |
162 | Just ares -> liftIO $ putMVar ares result | 192 | case mcall of |
193 | Nothing -> return () | ||
194 | Just ares -> putMVar ares result | ||
163 | 195 | ||
164 | handleMessage :: MonadKRPC m => KMessage -> SockAddr -> m () | 196 | handleMessage :: MonadKRPC h m => KMessage -> SockAddr -> m () |
165 | handleMessage (Q q) = handleQuery q | 197 | handleMessage (Q q) = handleQuery q |
166 | handleMessage (R r) = handleResponse (Right r) | 198 | handleMessage (R r) = handleResponse (Right r) |
167 | handleMessage (E e) = handleResponse (Left e) | 199 | handleMessage (E e) = handleResponse (Left e) |
@@ -169,7 +201,7 @@ handleMessage (E e) = handleResponse (Left e) | |||
169 | maxMsgSize :: Int | 201 | maxMsgSize :: Int |
170 | maxMsgSize = 64 * 1024 | 202 | maxMsgSize = 64 * 1024 |
171 | 203 | ||
172 | listener :: MonadKRPC m => m () | 204 | listener :: MonadKRPC h m => m () |
173 | listener = do | 205 | listener = do |
174 | Manager {..} <- getManager | 206 | Manager {..} <- getManager |
175 | forever $ do | 207 | forever $ do |
@@ -177,3 +209,6 @@ listener = do | |||
177 | case BE.decode bs of | 209 | case BE.decode bs of |
178 | Left e -> liftIO $ sendMessage sock addr $ unknownMessage e | 210 | Left e -> liftIO $ sendMessage sock addr $ unknownMessage e |
179 | Right m -> handleMessage m addr | 211 | Right m -> handleMessage m addr |
212 | |||
213 | listen :: MonadKRPC h m => m ThreadId | ||
214 | listen = fork $ listener | ||