summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/Client.hs7
-rw-r--r--examples/Server.hs8
-rw-r--r--examples/Shared.hs19
-rw-r--r--src/Remote/KRPC.hs48
-rw-r--r--src/Remote/KRPC/Method.hs30
5 files changed, 54 insertions, 58 deletions
diff --git a/examples/Client.hs b/examples/Client.hs
index 1d925c7a..cd340a03 100644
--- a/examples/Client.hs
+++ b/examples/Client.hs
@@ -10,7 +10,12 @@ addr :: RemoteAddr
10addr = (0, 6000) 10addr = (0, 6000)
11 11
12main :: IO () 12main :: IO ()
13main = print =<< call addr swapM (1, 2) 13main = do
14 print =<< call addr unitM ()
15 print =<< call addr echoM 0
16 call addr reverseM [1..1000]
17 print =<< call addr swapM (0, 1)
18 print =<< call addr shiftR ((), 1, [2..10])
14 19
15{- 20{-
16 forM_ [1..] $ const $ do 21 forM_ [1..] $ const $ do
diff --git a/examples/Server.hs b/examples/Server.hs
index 3760b2ab..0407c304 100644
--- a/examples/Server.hs
+++ b/examples/Server.hs
@@ -6,4 +6,10 @@ import Shared
6 6
7 7
8main :: IO () 8main :: IO ()
9main = server 6000 [swapM ==> \(a, b) -> return (b, a)] 9main = server 6000
10 [ unitM ==> return
11 , echoM ==> return
12 , swapM ==> \(a, b) -> return (b, a)
13 , reverseM ==> return . reverse
14 , shiftR ==> \(a, b, c) -> return (c, a, b)
15 ]
diff --git a/examples/Shared.hs b/examples/Shared.hs
index 49cef490..2d5b9cbb 100644
--- a/examples/Shared.hs
+++ b/examples/Shared.hs
@@ -1,14 +1,27 @@
1{-# LANGUAGE OverloadedStrings #-} 1{-# LANGUAGE OverloadedStrings #-}
2module Shared (echoInt, swapM) where 2module Shared
3 (echoM, unitM, swapM, reverseM, shiftR
4 ) where
3 5
4import Remote.KRPC 6import Remote.KRPC
5 7
6echoInt :: Method Int Int 8unitM :: Method () ()
7echoInt = idM 9unitM = method "unit" [] []
10
11echoM :: Method Int Int
12echoM = method "echo" ["x"] ["x"]
13
14reverseM :: Method [Int] [Int]
15reverseM = method "reverse" ["xs"] ["ys"]
8 16
9swapM :: Method (Int, Int) (Int, Int) 17swapM :: Method (Int, Int) (Int, Int)
10swapM = method "swap" ["x", "y"] ["b", "a"] 18swapM = method "swap" ["x", "y"] ["b", "a"]
11 19
20shiftR :: Method ((), Int, [Int]) ([Int], (), Int)
21shiftR = method "shiftR" ["x", "y", "z"] ["a", "b", "c"]
22
23
24
12{- 25{-
13type NodeId = Int 26type NodeId = Int
14type InfoHashe = Int 27type InfoHashe = Int
diff --git a/src/Remote/KRPC.hs b/src/Remote/KRPC.hs
index a542f0b4..5c1aadd6 100644
--- a/src/Remote/KRPC.hs
+++ b/src/Remote/KRPC.hs
@@ -21,6 +21,7 @@ module Remote.KRPC
21 , (==>), server 21 , (==>), server
22 ) where 22 ) where
23 23
24import Control.Applicative
24import Control.Exception 25import Control.Exception
25import Control.Monad.Trans.Control 26import Control.Monad.Trans.Control
26import Control.Monad.IO.Class 27import Control.Monad.IO.Class
@@ -39,31 +40,39 @@ data RPCException = RPCException KError
39 deriving (Show, Eq, Typeable) 40 deriving (Show, Eq, Typeable)
40 41
41instance Exception RPCException 42instance Exception RPCException
43type RemoteAddr = KRemoteAddr
42 44
45extractArgs :: BEncodable arg
46 => [ParamName] -> Map ParamName BEncode -> Result arg
47extractArgs as d = fromBEncode =<<
48 case as of
49 [] -> Right (BList [])
50 [x] -> f x
51 xs -> BList <$> mapM f xs
52 where
53 f x = maybe (Left ("not found key " ++ BC.unpack x)) Right
54 (M.lookup x d)
55{-# INLINE extractArgs #-}
43 56
44type RemoteAddr = KRemoteAddr 57injectVals :: BEncodable arg => [ParamName] -> arg -> [(ParamName, BEncode)]
58injectVals [] (toBEncode -> BList []) = []
59injectVals [p] (toBEncode -> arg) = [(p, arg)]
60injectVals ps (toBEncode -> BList as) = L.zip ps as
61injectVals _ _ = error "KRPC.injectVals: impossible"
62{-# INLINE injectVals #-}
45 63
46 64
47queryCall :: BEncodable param 65queryCall :: BEncodable param
48 => Extractable param
49 => KRemote -> KRemoteAddr 66 => KRemote -> KRemoteAddr
50 -> Method param result -> param -> IO () 67 -> Method param result -> param -> IO ()
51queryCall sock addr m arg = sendMessage q addr sock 68queryCall sock addr m arg = sendMessage q addr sock
52 where 69 where
53 q = kquery (methodName m) (mkVals (methodParams m) (injector arg)) 70 q = kquery (methodName m) (injectVals (methodParams m) arg)
54 mkVals = L.zip
55 71
56 72
57extractArgs :: [ParamName] -> Map ParamName BEncode -> Result [BEncode]
58extractArgs as d = mapM f as
59 where
60 f x | Just y <- M.lookup x d = return y
61 | otherwise = Left ("not found key " ++ BC.unpack x)
62{-# INLINE extractArgs #-}
63 73
64-- TODO check scheme 74-- TODO check scheme
65getResult :: BEncodable result 75getResult :: BEncodable result
66 => Extractable result
67 => KRemote -> KRemoteAddr 76 => KRemote -> KRemoteAddr
68 -> Method param result -> IO result 77 -> Method param result -> IO result
69getResult sock addr m = do 78getResult sock addr m = do
@@ -71,7 +80,7 @@ getResult sock addr m = do
71 case resp of 80 case resp of
72 Left e -> throw (RPCException e) 81 Left e -> throw (RPCException e)
73 Right (respVals -> dict) -> do 82 Right (respVals -> dict) -> do
74 case extractArgs (methodVals m) dict >>= extractor of 83 case extractArgs (methodVals m) dict of
75 Right vals -> return vals 84 Right vals -> return vals
76 Left e -> throw (RPCException (ProtocolError (BC.pack e))) 85 Left e -> throw (RPCException (ProtocolError (BC.pack e)))
77 86
@@ -81,7 +90,6 @@ getResult sock addr m = do
81-- 90--
82call :: (MonadBaseControl IO host, MonadIO host) 91call :: (MonadBaseControl IO host, MonadIO host)
83 => (BEncodable param, BEncodable result) 92 => (BEncodable param, BEncodable result)
84 => (Extractable param, Extractable result)
85 => RemoteAddr 93 => RemoteAddr
86 -> Method param result 94 -> Method param result
87 -> param 95 -> param
@@ -96,7 +104,6 @@ newtype Async result = Async { waitResult :: IO result }
96-- TODO document errorneous usage 104-- TODO document errorneous usage
97async :: MonadIO host 105async :: MonadIO host
98 => (BEncodable param, BEncodable result) 106 => (BEncodable param, BEncodable result)
99 => (Extractable param, Extractable result)
100 => RemoteAddr 107 => RemoteAddr
101 -> Method param result 108 -> Method param result
102 -> param 109 -> param
@@ -119,8 +126,7 @@ type MethodHandler remote = (MethodName, HandlerBody remote)
119 126
120-- we can safely erase types in (==>) 127-- we can safely erase types in (==>)
121(==>) :: forall (remote :: * -> *) (param :: *) (result :: *). 128(==>) :: forall (remote :: * -> *) (param :: *) (result :: *).
122-- (BEncodable param, BEncodable result) 129 (BEncodable param, BEncodable result)
123 (Extractable param, Extractable result)
124 => Monad remote 130 => Monad remote
125 => Method param result 131 => Method param result
126 -> (param -> remote result) 132 -> (param -> remote result)
@@ -130,14 +136,13 @@ m ==> body = (methodName m, newbody)
130 where 136 where
131 {-# INLINE newbody #-} 137 {-# INLINE newbody #-}
132 newbody q = 138 newbody q =
133 case extractArgs (methodParams m) (queryArgs q) >>= extractor of 139 case extractArgs (methodParams m) (queryArgs q) of
134 Left e -> return (Left (ProtocolError (BC.pack e))) 140 Left e -> return (Left (ProtocolError (BC.pack e)))
135 Right a -> do 141 Right a -> do
136 r <- body a 142 r <- body a
137 return (Right (kresponse (mkVals (methodVals m) (injector r)))) 143 return (Right (kresponse (injectVals (methodVals m) r)))
138 144
139 mkVals :: [ValName] -> [BEncode] -> [(ValName, BEncode)] 145infix 1 ==>
140 mkVals = L.zip
141 146
142-- TODO: allow forkIO 147-- TODO: allow forkIO
143server :: (MonadBaseControl IO remote, MonadIO remote) 148server :: (MonadBaseControl IO remote, MonadIO remote)
@@ -153,6 +158,3 @@ server servport handlers = do
153 handlerMap = M.fromList handlers 158 handlerMap = M.fromList handlers
154 dispatch s = M.lookup s handlerMap 159 dispatch s = M.lookup s handlerMap
155 invoke m q = m q 160 invoke m q = m q
156
157 bimap f _ (Left x) = Left (f x)
158 bimap _ g (Right x) = Right (g x) \ No newline at end of file
diff --git a/src/Remote/KRPC/Method.hs b/src/Remote/KRPC/Method.hs
index d0c8e89a..4283256b 100644
--- a/src/Remote/KRPC/Method.hs
+++ b/src/Remote/KRPC/Method.hs
@@ -16,9 +16,6 @@ module Remote.KRPC.Method
16 16
17 -- * Predefined methods 17 -- * Predefined methods
18 , idM 18 , idM
19
20 -- * Internal
21 , Extractable(..)
22 ) where 19 ) where
23 20
24import Control.Applicative 21import Control.Applicative
@@ -69,30 +66,3 @@ idM = method "id" ["x"] ["y"]
69method :: MethodName -> [ParamName] -> [ValName] -> Method param result 66method :: MethodName -> [ParamName] -> [ValName] -> Method param result
70method = Method 67method = Method
71{-# INLINE method #-} 68{-# INLINE method #-}
72
73
74
75class Extractable a where
76 injector :: a -> [BEncode]
77 extractor :: [BEncode] -> Result a
78
79instance (BEncodable a, BEncodable b) => Extractable (a, b) where
80 {- SPECIALIZE instance (BEncodable a, BEncodable b) => Extractable (a, b) -}
81 injector (a, b) = [toBEncode a, toBEncode b]
82 {-# INLINE injector #-}
83
84 extractor [a, b] = (,) <$> fromBEncode a <*> fromBEncode b
85 extractor _ = decodingError "unable to match pair"
86 {-# INLINE extractor #-}
87
88{-
89instance BEncodable a => Extractable a where
90 {-# SPECIALIZE instance BEncodable a => Extractable a #-}
91
92 injector x = [toBEncode x]
93 {-# INLINE injector #-}
94
95 extractor [x] = fromBEncode x
96 extractor _ = decodingError "unable to match single value"
97 {-# INLINE extractor #-}
98-} \ No newline at end of file