on master help sign in
add example to README
7b27965AgentM
README.markdown+64−2
@@ -2,11 +2,73 @@
2
2
3Curryer (pun intended) is a fast, Haskell-exclusive RPC (remote procedure call) library. By using the latest Haskell serialization and streaming libraries, curryer aims to be the fastest and easiest means of communicating between Haskell-based processes.
3Curryer (pun intended) is a fast, Haskell-exclusive RPC (remote procedure call) library. By using the latest Haskell serialization and streaming libraries, curryer aims to be the fastest and easiest means of communicating between Haskell-based processes.
4
4
5−Curryer is inspired by the now unmaintained [distributed-process](https://hackage.haskell.org/package/distributed-process) library.
5+Curryer is inspired by the now unmaintained [distributed-process](https://hackage.haskell.org/package/distributed-process) library, but is lighter-weight and uses a higher-performance serialization package.
6
6
7## Features
7## Features
8
8
9* blocking and non-blocking remote function calls
9* blocking and non-blocking remote function calls
10* asynchronous server-to-client callbacks (for server-initiated notifications)
10* asynchronous server-to-client callbacks (for server-initiated notifications)
11* timeouts
11* timeouts
12−* utilizes versionable shared ADT for communication instead of shared function `StaticPtr`s
12+* leverages [winery](https://hackage.haskell.org/package/winery) for high-performance serialization
13+
14+## Code Example
15+
16+[Server](https://github.com/agentm/curryer/examples/SimpleKeyValueServer.hs):
17+
18+```haskell
19+data SetKey = SetKey String String
20+ deriving (Generic, Show)
21+ deriving Serialise via WineryVariant SetKey
22+
23+data GetKey = GetKey String
24+ deriving (Generic, Show)
25+ deriving Serialise via WineryVariant GetKey
26+
27+main :: IO ()
28+main = do
29+ kvmap <- M.newIO
30+ void $ serve kvRequestHandlers kvmap localHostAddr 8765 Nothing
31+
32+kvRequestHandlers :: RequestHandlers (M.Map String String)
33+kvRequestHandlers = [ RequestHandler $ \state (SetKey k v) ->
34+ atomically $ M.insert v k (connectionServerState state)
35+ , RequestHandler $ \state (GetKey k) ->
36+ atomically $ M.lookup k (connectionServerState state)
37+ ]
38+```
39+
40+[Client](https://github.com/agentm/curryer/examples/SimpleKeyValueClient.hs):
41+
42+```haskell
43+data SetKey = SetKey String String
44+ deriving (Generic, Show)
45+ deriving Serialise via WineryVariant SetKey
46+
47+data GetKey = GetKey String
48+ deriving (Generic, Show)
49+ deriving Serialise via WineryVariant GetKey
50+
51+data CommandOptions = Get {name :: String}
52+ | Set {name :: String, value :: String}
53+ deriving (Generic, Show)
54+
55+instance ParseRecord CommandOptions
56+
57+main :: IO ()
58+main = do
59+ opts <- getRecord "SimpleKeyValueClient"
60+ conn <- connect [] localHostAddr 8765
61+ case opts of
62+ Get k -> do
63+ eRet <- call conn (GetKey k)
64+ case eRet of
65+ Left err -> error (show err)
66+ Right (Just val) -> putStrLn val
67+ Right Nothing -> error "no such key"
68+ Set k v -> do
69+ eRet <- call conn (SetKey k v)
70+ case eRet of
71+ Left err -> error (show err)
72+ Right () -> pure ()
73+
74+```
examples/SimpleKeyValueClient.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE DerivingVia, DeriveGeneric, OverloadedStrings #-}
2+import GHC.Generics
3+import Network.RPC.Curryer.Client
4+import Network.RPC.Curryer.Server (localHostAddr)
5+import Options.Generic
6+import Codec.Winery
7+
8+data SetKey = SetKey String String
9+ deriving (Generic, Show)
10+ deriving Serialise via WineryVariant SetKey
11+
12+data GetKey = GetKey String
13+ deriving (Generic, Show)
14+ deriving Serialise via WineryVariant GetKey
15+
16+data CommandOptions = Get {name :: String}
17+ | Set {name :: String, value :: String}
18+ deriving (Generic, Show)
19+
20+instance ParseRecord CommandOptions
21+
22+main :: IO ()
23+main = do
24+ opts <- getRecord "SimpleKeyValueClient"
25+ -- connect to the remote server (in this case on the localhost address)
26+ conn <- connect [] localHostAddr 8765
27+ case opts of
28+ Get k -> do
29+ --call the remote function and validate the result
30+ eRet <- call conn (GetKey k)
31+ case eRet of
32+ Left err -> error (show err)
33+ Right (Just val) -> putStrLn val
34+ Right Nothing -> error "no such key"
35+ Set k v -> do
36+ eRet <- call conn (SetKey k v)
37+ case eRet of
38+ Left err -> error (show err)
39+ Right () -> pure ()
examples/SimpleKeyValueServer.hsnew file+30
@@ -0,0 +1,30 @@
1+{-# LANGUAGE DerivingVia, DeriveGeneric #-}
2+import Network.RPC.Curryer.Server
3+import Control.Concurrent.STM
4+import StmContainers.Map as M
5+import GHC.Generics
6+import Codec.Winery
7+import Data.Functor
8+
9+-- create data structures to represent remote function calls
10+data SetKey = SetKey String String
11+ deriving (Generic, Show)
12+ deriving Serialise via WineryVariant SetKey
13+
14+data GetKey = GetKey String
15+ deriving (Generic, Show)
16+ deriving Serialise via WineryVariant GetKey
17+
18+--call the `serve` function to handle incoming requests
19+main :: IO ()
20+main = do
21+ kvmap <- M.newIO
22+ void $ serve kvRequestHandlers kvmap localHostAddr 8765 Nothing
23+
24+-- setup incoming request handlers to operate on the server's state
25+kvRequestHandlers :: RequestHandlers (M.Map String String)
26+kvRequestHandlers = [ RequestHandler $ \state (SetKey k v) ->
27+ atomically $ M.insert v k (connectionServerState state)
28+ , RequestHandler $ \state (GetKey k) ->
29+ atomically $ M.lookup k (connectionServerState state)
30+ ]