-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathclient.ml
230 lines (207 loc) · 7.55 KB
/
client.ml
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
open Grpc_eio
open Routeguide.Route_guide.Routeguide
open Ocaml_protoc_plugin
(* $MDX part-begin=client-h2 *)
let client ~sw host port network =
let inet, port =
Eio_unix.run_in_systhread (fun () ->
Unix.getaddrinfo host port [ Unix.(AI_FAMILY PF_INET) ])
|> List.filter_map (fun (addr : Unix.addr_info) ->
match addr.ai_addr with
| Unix.ADDR_UNIX _ -> None
| ADDR_INET (addr, port) -> Some (addr, port))
|> List.hd
in
let addr = `Tcp (Eio_unix.Net.Ipaddr.of_unix inet, port) in
let socket = Eio.Net.connect ~sw network addr in
H2_eio.Client.create_connection ~sw ~error_handler:ignore socket
(* $MDX part-end *)
(* $MDX part-begin=client-get-feature *)
let call_get_feature connection point =
let encode, decode = Service.make_client_functions RouteGuide.getFeature in
let response =
Client.call ~service:"routeguide.RouteGuide" ~rpc:"GetFeature"
~do_request:(H2_eio.Client.request connection ~error_handler:ignore)
~handler:
(Client.Rpc.unary
(encode point |> Writer.contents)
~f:(fun response ->
match response with
| Some response -> (
Reader.create response |> decode |> function
| Ok feature -> feature
| Error e ->
failwith
(Printf.sprintf "Could not decode request: %s"
(Result.show_error e)))
| None -> Feature.make ()))
()
in
match response with
| Ok (res, _ok) -> Printf.printf "RESPONSE = {%s}" (Feature.show res)
| Error _ -> Printf.printf "an error occurred"
(* $MDX part-end *)
(* $MDX part-begin=client-list-features *)
let print_features connection =
let rectangle =
Rectangle.make
~lo:(Point.make ~latitude:400000000 ~longitude:(-750000000) ())
~hi:(Point.make ~latitude:420000000 ~longitude:(-730000000) ())
()
in
let encode, decode = Service.make_client_functions RouteGuide.listFeatures in
let stream =
Client.call ~service:"routeguide.RouteGuide" ~rpc:"ListFeatures"
~do_request:(H2_eio.Client.request connection ~error_handler:ignore)
~handler:
(Client.Rpc.server_streaming
(encode rectangle |> Writer.contents)
~f:(fun responses ->
let stream =
Seq.map
(fun str ->
Reader.create str |> decode |> function
| Ok feature -> feature
| Error e ->
failwith
(Printf.sprintf "Could not decode request: %s"
(Result.show_error e)))
responses
in
stream))
()
in
match stream with
| Ok (results, _ok) ->
Seq.iter
(fun f -> Printf.printf "RESPONSE = {%s}" (Feature.show f))
results
| Error e ->
failwith (Printf.sprintf "HTTP2 error: %s" (H2.Status.to_string e))
(* $MDX part-end *)
(* $MDX part-begin=client-random-point *)
let random_point () : Point.t =
let latitude = (Random.int 180 - 90) * 10000000 in
let longitude = (Random.int 360 - 180) * 10000000 in
Point.make ~latitude ~longitude ()
(* $MDX part-end *)
(* $MDX part-begin=client-record-route *)
let run_record_route connection =
let points =
Random.int 100
|> Seq.unfold (function 0 -> None | x -> Some (random_point (), x - 1))
in
let encode, decode = Service.make_client_functions RouteGuide.recordRoute in
let response =
Client.call ~service:"routeguide.RouteGuide" ~rpc:"RecordRoute"
~do_request:(H2_eio.Client.request connection ~error_handler:ignore)
~handler:
(Client.Rpc.client_streaming ~f:(fun f response ->
(* Stream points to server. *)
Seq.iter
(fun point ->
encode point |> Writer.contents |> fun x -> Seq.write f x)
points;
(* Signal we have finished sending points. *)
Seq.close_writer f;
(* Decode RouteSummary responses. *)
Eio.Promise.await response |> function
| Some str -> (
Reader.create str |> decode |> function
| Ok feature -> feature
| Error err ->
failwith
(Printf.sprintf "Could not decode request: %s"
(Result.show_error err)))
| None -> failwith (Printf.sprintf "No RouteSummary received.")))
()
in
match response with
| Ok (result, _ok) ->
Printf.printf "SUMMARY = {%s}" (RouteSummary.show result)
| Error e ->
failwith (Printf.sprintf "HTTP2 error: %s" (H2.Status.to_string e))
(* $MDX part-end *)
(* $MDX part-begin=client-route-chat-1 *)
let run_route_chat clock connection =
(* Generate locations. *)
let location_count = 5 in
Printf.printf "Generating %i locations\n" location_count;
let route_notes =
location_count
|> Seq.unfold (function
| 0 -> None
| x ->
Some
( RouteNote.make ~location:(random_point ())
~message:(Printf.sprintf "Random Message %i" x)
(),
x - 1 ))
in
(* $MDX part-end *)
(* $MDX part-begin=client-route-chat-2 *)
let encode, decode = Service.make_client_functions RouteGuide.routeChat in
let rec go writer reader notes =
match Seq.uncons notes with
| None ->
Seq.close_writer writer (* Signal no more notes from the client. *)
| Some (route_note, xs) -> (
encode route_note |> Writer.contents |> fun x ->
Seq.write writer x;
(* Yield and sleep, waiting for server reply. *)
Eio.Time.sleep clock 1.0;
Eio.Fiber.yield ();
match Seq.uncons reader with
| None -> failwith "Expecting response"
| Some (response, reader') ->
let route_note =
Reader.create response |> decode |> function
| Ok route_note -> route_note
| Error e ->
failwith
(Printf.sprintf "Could not decode request: %s"
(Result.show_error e))
in
Printf.printf "NOTE = {%s}\n" (RouteNote.show route_note);
go writer reader' xs)
in
let result =
Client.call ~service:"routeguide.RouteGuide" ~rpc:"RouteChat"
~do_request:(H2_eio.Client.request connection ~error_handler:ignore)
~handler:
(Client.Rpc.bidirectional_streaming ~f:(fun writer reader ->
go writer reader route_notes))
()
in
match result with
| Ok ((), _ok) -> ()
| Error e ->
failwith (Printf.sprintf "HTTP2 error: %s" (H2.Status.to_string e))
(* $MDX part-end *)
(* $MDX part-begin=client-main *)
let main env =
let port = "8080" in
let host = "localhost" in
let clock = Eio.Stdenv.clock env in
let network = Eio.Stdenv.net env in
let () = Random.self_init () in
let run sw =
let connection = client ~sw host port network in
Printf.printf "*** SIMPLE RPC ***\n";
let request =
RouteGuide.GetFeature.Request.make ~latitude:409146138
~longitude:(-746188906) ()
in
let result = call_get_feature connection request in
Printf.printf "\n*** SERVER STREAMING ***\n";
print_features connection;
Printf.printf "\n*** CLIENT STREAMING ***\n";
run_record_route connection;
Printf.printf "\n*** BIDIRECTIONAL STREAMING ***\n";
run_route_chat clock connection;
Eio.Promise.await (H2_eio.Client.shutdown connection);
result
in
Eio.Switch.run run
let () = Eio_main.run main
(* $MDX part-end *)