-
Notifications
You must be signed in to change notification settings - Fork 0
/
KVS5Fig17.hs
92 lines (80 loc) · 3.21 KB
/
KVS5Fig17.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-
This is an implementation of the choreogrpahy shown in fig17 of We Know I Know You Know.
-}
module KVS5Fig17 where
import Choreography
import Choreography.Network.Http
import CLI
import Data (TestArgs, reference)
import Data.List (sort)
import Data.Maybe (fromMaybe)
import System.Environment
import Test.QuickCheck (Arbitrary, arbitrary, elements)
$(mkLoc "client")
$(mkLoc "primary")
$(mkLoc "backup")
type Servers = ["primary", "backup"]
type Participants = "client" ': Servers
servers :: Subset Servers Participants
servers = primary @@ backup @@ nobody
data Request = Put String String | Get String deriving (Eq, Show, Read)
instance Arbitrary Request where
arbitrary = (\case
Nothing -> Get
Just s -> Put s) <$> arbitrary <*> arbitrary
type Response = String
data Args = Args{ request :: Request
, handler :: String
} deriving (Eq, Show, Read)
instance TestArgs Args Response where
reference Args{request, handler} =
let f = fromMaybe defaultHandler $ handler `lookup` handlers
in handleRequest f request
instance Arbitrary Args where
arbitrary = Args <$> arbitrary
<*> elements (fst <$> handlers)
handlers :: [(String, String -> String)]
handlers = [ ("reverse", reverse)
, ("alphabetize", sort)
]
defaultHandler :: String -> String
defaultHandler = const "No Handler"
-- | `handleRequest` handle a request. Since we don't have a way of locking paralell state, this is a mock.
handleRequest :: (String -> Response) -> Request -> Response
handleRequest handler request = case request of
Put key value -> show key ++ " saved as " ++ show value ++ "."
Get key -> handler key
setup :: Choreo Servers (CLI m) (Located Servers (Request -> Response))
setup = do handlerName <- (primary, getstr "How should we mock `Get` Requests? (reverse or alphabetize)")
-~> primary @@ backup @@ nobody
primary @@ backup @@ nobody `congruently` \un -> handleRequest (fromMaybe defaultHandler $ un refl handlerName `lookup` handlers)
-- | `kvs` is a choreography that processes a single request located at the client and returns the response.
-- If the request is a `PUT`, it will forward the request to the backup node.
kvs :: Choreo Participants (CLI m) ()
kvs = do
handler <- enclaveToAll servers setup
request <- (client, getInput "Enter the `read`able Request:") -~> primary @@ backup @@ nobody
response <- primary @@ backup @@ nobody `congruently` \un -> un refl handler $ un refl request
response' <- (primary, response) ~> client @@ nobody
client `locally_` \un -> putOutput "Recieved:" $ un client response'
main :: IO ()
main = do
[loc] <- getArgs
case loc of
"client" -> runCLIIO $ runChoreography config kvs "client"
"primary" -> runCLIIO $ runChoreography config kvs "primary"
"backup" -> runCLIIO $ runChoreography config kvs "backup"
_ -> error "unknown party"
return ()
where
config =
mkHttpConfig
[ ("client", ("localhost", 3000)),
("primary", ("localhost", 4000)),
("backup", ("localhost", 5000))
]