3import Control.ST.ImplicitCall
9{- A random number server.
11This receives requests from a client, as a number, and sends a reply
12which is a random number within the requested bound.
14There are two states: one for the server, and one for a connected session.
15The server repeatedly listens for requests and creats a session for each
19-- States of a connected session
20data SessionState = Waiting -- waiting for the client to send
21 | Processing -- calculating a response to send back
22 | Done -- received message and replied to it
24interface RandomSession (m : Type -> Type) where
25 -- A connected session
26 Connection : SessionState -> Type
27 -- A server listening for connections
30 -- Receive a request on a Waiting connection. If there is a request
31 -- available, move to the Processing state
32 recvReq : (conn : Var) ->
34 [conn ::: Connection Waiting :->
35 \res => Connection (case res of
37 Just _ => Processing)]
38 -- Send a reply, and move the connection to the Done state
39 sendResp : (conn : Var) -> Integer ->
40 ST m () [conn ::: Connection Processing :-> Connection Done]
43 start : ST m (Maybe Var) [addIfJust Server]
45 quit : (srv : Var) -> ST m () [Remove srv Server]
46 -- Finish a connection
47 done : (conn : Var) -> ST m () [Remove conn (Connection Done)]
49 -- Listen for an incoming connection. If there is one, create a session
50 -- with a connection in the Waiting state
51 accept : (srv : Var) ->
53 [srv ::: Server, addIfJust (Connection Waiting)]
55interface Sleep (m : Type -> Type) where
56 usleep : (i : Int) -> { auto prf : So (i >= 0 && i <= 1000000) } ->
57 STrans m () xs (const xs)
60 usleep x = lift (System.usleep x)
63using (Sleep io, ConsoleIO io, RandomSession io, Conc io)
64 rndSession : (conn : Var) ->
65 ST io () [Remove conn (Connection {m=io} Waiting)]
67 do Just bound <- call (recvReq conn)
68 | Nothing => do putStr "Nothing received\n"
70 putStr "Calculating reply...\n"
72 sendResp conn bound -- (seed `mod` (bound + 1))
75 rndLoop : (srv : Var) -> ST io () [srv ::: Server {m=io}]
77 = do Just conn <- accept srv
78 | Nothing => putStr "accept failed\n"
79 putStr "Connection received\n"
80 fork (rndSession conn)
83 rndServer : ST io () []
85 = do Just srv <- start
86 | Nothing => putStr "Can't start server\n"
90implementation (ConsoleIO io, Sockets io) => RandomSession io where
92 -- Connections and servers are composite states, so to implement things
93 -- in terms of them we need to 'split' at the state and 'combine' at the
94 -- end, in every method
95 Connection Waiting = Composite [State Integer, Sock {m=io} Open]
96 Connection Processing = Composite [State Integer, Sock {m=io} Open]
97 Connection Done = Composite [State Integer, Sock {m=io} Closed]
99 Server = Composite [State Integer, Sock {m=io} Listening]
101 recvReq rec = do [seed, conn] <- split rec
102 Right msg <- recv conn
103 | Left err => do combine rec [seed, conn]
105 putStr ("Incoming " ++ show msg ++ "\n")
106 combine rec [seed, conn]
107 pure (Just (cast msg))
109 sendResp rec val = do [seed, conn] <- split rec
110 Right () <- send conn (cast (!(read seed) `mod` val) ++ "\n")
111 | Left err => do combine rec [seed, conn]
114 combine rec [seed, conn]
116 start = do srv <- new ()
117 Right sock <- socket Stream
118 | Left err => do delete srv; pure Nothing
119 Right () <- bind sock Nothing 9442
120 | Left err => do call (remove sock)
123 Right () <- listen sock
124 | Left err => do call (remove sock)
127 putStr "Started server\n"
129 combine srv [seed, sock]
132 quit srv = do [seed, sock] <- split srv -- need to delete everything
133 close sock; remove sock; delete seed; delete srv
134 done conn = do [seed, sock] <- split conn -- need to delete connection data
135 remove sock; delete seed; delete conn
137 accept srv = do [seed, sock] <- split srv
139 write seed ((1664525 * seedVal + 1013904223)
140 `prim__sremBigInt` (pow 2 32))
141 Right conn <- accept sock
142 | Left err => do combine srv [seed, sock]
143 pure Nothing -- no incoming message
144 -- We're sending the seed to the child process and keeping
145 -- a copy ourselves, so we need to explicitly make a new
149 combine rec [seed', conn]
150 combine srv [seed, sock]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list