Skip to content

Commit

Permalink
Refactor gRPC eio packages to improve modularity
Browse files Browse the repository at this point in the history
  • Loading branch information
wokalski committed Apr 15, 2024
1 parent 26b1ce3 commit def0f74
Show file tree
Hide file tree
Showing 78 changed files with 1,678 additions and 788 deletions.
2 changes: 1 addition & 1 deletion .ocamlformat
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=0.26.1
# version=0.26.1
ocaml-version=4.08
3 changes: 3 additions & 0 deletions dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(dirs bench examples lib)

(vendored_dirs ocaml-h2 gluten)
79 changes: 71 additions & 8 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,54 @@
(name grpc)
(synopsis "A modular gRPC library")
(description
"This library builds some of the signatures and implementations of gRPC functionality. This is used in the more specialised package `grpc-lwt` which has more machinery, however this library can also be used to do some bits yourself.")
"This library contains the implementation of (de)serialization of gRPC messages and statuses.")
(tags
(network rpc serialisation))
(depends
(ocaml
(>= 4.08))
(bigstringaf
(>= 0.9.1))
(h2
(>= 0.9.0))
ppx_deriving
(uri
(>= 4.0.0))))

(package
(name grpc-server)
(synopsis "Reusable logic for server side gRPC")
(description
"All modules are networking-layer and concurrency-layer agnostic.")
(tags
(network rpc serialisation))
(depends
(ocaml
(>= 4.08))
(grpc (= :version))))

(package
(name grpc-client)
(synopsis "Reusable logic for client side gRPC")
(description
"All modules are networking-layer and concurrency-layer agnostic.")
(tags
(network rpc serialisation))
(depends
(ocaml
(>= 4.08))
(grpc (= :version))))

(package
(name grpc-core-eio)
(synopsis "Shared logic for gRPC clients and servers based on eio.")
(description
"All modules are networking-layer agnostic.")
(tags
(network rpc serialisation))
(depends
(eio
(>= 0.12))
(grpc (= :version))))

(package
(name grpc-lwt)
(synopsis "An Lwt implementation of gRPC")
Expand All @@ -50,7 +84,7 @@
(tags
(network rpc serialisation))
(depends
(grpc
(grpc-server
(= :version))
(h2
(>= 0.9.0))
Expand All @@ -70,7 +104,7 @@
(>= 4.11))
(async
(>= v0.16))
(grpc
(grpc-server
(= :version))
(h2
(>= 0.9.0))
Expand All @@ -79,19 +113,48 @@
stringext))

(package
(name grpc-eio)
(synopsis "An Eio implementation of gRPC")
(name grpc-server-eio)
(deprecated_package_names grpc-eio)
(synopsis "An Eio implementation of gRPC server")
(description
"Functionality for building gRPC services and rpcs with `eio`.")
(depends
(eio
(>= 0.12))
(grpc
(grpc-server
(= :version))
stringext))

(package
(name grpc-eio-net-server-h2)
(synopsis "An h2 implementation of gRPC networking layer for eio based servers.")
(depends
(grpc-server-eio
(= :version))
(h2
(>= 0.9.0))
stringext))

(package
(name grpc-client-eio)
(synopsis "An Eio implementation of gRPC client")
(description
"Functionality for building gRPC services and rpcs with `eio`.")
(depends
(eio
(>= 0.12))
(grpc-client
(= :version))))

(package
(name grpc-eio-net-client-h2)
(synopsis "An h2 implementation of gRPC networking layer for eio based clients.")
(depends
(grpc-client-eio
(= :version))
(h2
(>= 0.9.0))))

(package
(name grpc-examples)
(synopsis "Various gRPC examples")
Expand Down
2 changes: 1 addition & 1 deletion examples/greeter-client-eio/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(executable
(name greeter_client_eio)
(libraries grpc grpc-eio ocaml-protoc-plugin eio_main greeter h2 h2-eio))
(libraries grpc-client-eio ocaml-protoc-plugin eio_main greeter grpc-eio-net-client-h2))
59 changes: 18 additions & 41 deletions examples/greeter-client-eio/greeter_client_eio.ml
Original file line number Diff line number Diff line change
@@ -1,56 +1,33 @@
let main env =
let name = if Array.length Sys.argv > 1 then Sys.argv.(1) else "anonymous" in
let host = "localhost" in
let port = "8080" in
let network = Eio.Stdenv.net env in
let run sw =
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
let connection =
H2_eio.Client.create_connection ~sw ~error_handler:ignore socket
in

let open Ocaml_protoc_plugin in
let open Greeter.Mypackage in
let encode, decode = Service.make_client_functions Greeter.sayHello in
let encoded_request =
HelloRequest.make ~name () |> encode |> Writer.contents
in

let f decoder =
match decoder with
| Some decoder -> (
Reader.create decoder |> decode |> function
| Ok v -> v
| Error e ->
failwith
(Printf.sprintf "Could not decode request: %s"
(Result.show_error e)))
| None -> Greeter.SayHello.Response.make ()
let net =
Grpc_eio_net_client_h2.create_client ~sw ~net:network
"http://localhost:8080"
in

let result =
Grpc_eio.Client.call ~service:"mypackage.Greeter" ~rpc:"SayHello"
~do_request:(H2_eio.Client.request connection ~error_handler:ignore)
~handler:(Grpc_eio.Client.Rpc.unary encoded_request ~f)
()
Grpc_client_eio.Client.unary ~sw ~net ~service:"mypackage.Greeter"
~method_name:"SayHello"
~encode:(fun x -> x |> encode |> Writer.contents)
~decode:(fun x -> Reader.create x |> decode)
~headers:(Grpc_client.make_request_headers `Proto)
(HelloRequest.make ~name ())
in
Eio.Promise.await (H2_eio.Client.shutdown connection);
result
match result with
| Ok message -> Eio.traceln "%s" message
| Error (`Rpc (response, status)) ->
Eio.traceln "Error: %a, %a" H2.Status.pp_hum response.status
Grpc.Status.pp status
| Error (`Connection _err) -> Eio.traceln "Connection error"
| Error (`Decoding err) ->
Eio.traceln "Decoding error: %a" Ocaml_protoc_plugin.Result.pp_error err
in
Eio.Switch.run run

let () =
match Eio_main.run main with
| Ok (message, status) ->
Eio.traceln "%s: %s" (Grpc.Status.show status) message
| Error err -> Eio.traceln "Error: %a" H2.Status.pp_hum err
let () = Eio_main.run main
2 changes: 1 addition & 1 deletion examples/greeter-server-eio/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(executable
(name greeter_server_eio)
(libraries grpc grpc-eio ocaml-protoc-plugin eio_main greeter h2 h2-eio))
(libraries eio grpc-server-eio ocaml-protoc-plugin eio_main greeter grpc-eio-net-server-h2))
67 changes: 24 additions & 43 deletions examples/greeter-server-eio/greeter_server_eio.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
open Grpc_eio
module Server = Grpc_server_eio
module Net = Grpc_eio_net_server_h2

let say_hello buffer =
let say_hello env buffer =
let open Ocaml_protoc_plugin in
let open Greeter.Mypackage in
let decode, encode = Service.make_service_functions Greeter.sayHello in
Expand All @@ -16,55 +17,35 @@ let say_hello buffer =
else Format.sprintf "Hello, %s!" request
in
let reply = Greeter.SayHello.Response.make ~message () in
(Grpc.Status.(v OK), Some (encode reply |> Writer.contents))

let connection_handler server sw =
let error_handler client_address ?request:_ _error start_response =
Eio.traceln "Error in request from:%a" Eio.Net.Sockaddr.pp client_address;
let response_body = start_response H2.Headers.empty in
H2.Body.Writer.write_string response_body
"There was an error handling your request.\n";
H2.Body.Writer.close response_body
in
let request_handler client_address request_descriptor =
Eio.traceln "Handling a request from:%a" Eio.Net.Sockaddr.pp client_address;
Eio.Fiber.fork ~sw (fun () ->
Grpc_eio.Server.handle_request server request_descriptor)
in
fun socket addr ->
H2_eio.Server.create_connection_handler ?config:None ~request_handler
~error_handler addr ~sw socket
Eio.Time.sleep env#clock 10.0;
(Grpc_server.trailers_with_code OK, Some (encode reply |> Writer.contents))

let serve server env =
let port = 8080 in
let net = Eio.Stdenv.net env in
let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, port) in
Eio.Switch.run @@ fun sw ->
let handler = connection_handler server sw in
let server_socket =
Eio.Net.listen net ~sw ~reuse_addr:true ~backlog:10 addr
in
let rec listen () =
Eio.Net.accept_fork ~sw server_socket
~on_error:(fun exn -> Eio.traceln "%s" (Printexc.to_string exn))
handler;
listen ()
let connection_handler client_addr socket =
Eio.Switch.run (fun sw ->
Net.connection_handler ~sw server client_addr socket)
in
Printf.printf "Listening on port %i for grpc requests\n" port;
print_endline "";
print_endline "Try running:";
print_endline "";
print_endline
{| dune exec -- examples/greeter-client-eio/greeter_client_eio.exe <your_name> |};
listen ()
Eio.Net.run_server
~on_error:(fun exn -> Eio.traceln "%s" (Printexc.to_string exn))
server_socket connection_handler

let () =
let greeter_service =
Server.Service.(
v () |> add_rpc ~name:"SayHello" ~rpc:(Unary say_hello) |> handle_request)
in
let server =
Server.(
v () |> add_service ~name:"mypackage.Greeter" ~service:greeter_service)
in
Eio_main.run (serve server)
let mk_handler f =
{ Grpc_server_eio.Rpc.headers = (fun _ -> Grpc_server.headers `Proto); f }

let server env =
let add_rpc = Server.Service.add_rpc in
let open Server.Rpc in
let service =
Server.Service.v ()
|> add_rpc ~name:"SayHello" ~rpc:(mk_handler (unary (say_hello env)))
in
Server.(make () |> add_service ~name:"mypackage.Greeter" ~service)

let () = Eio_main.run (fun env -> serve (server env) env)
Loading

0 comments on commit def0f74

Please sign in to comment.