proxy_server_main_run.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.com> *)
(* *)
(* Permission is hereby granted, free of charge, to any person obtaining a *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
(* and/or sell copies of the Software, and to permit persons to whom the *)
(* Software is furnished to do so, subject to the following conditions: *)
(* *)
(* The above copyright notice and this permission notice shall be included *)
(* in all copies or substantial portions of the Software. *)
(* *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
(* DEALINGS IN THE SOFTWARE. *)
(* *)
(*****************************************************************************)
module Events = Proxy_server_run_events
type error += Proxy_server_RPC_Port_already_in_use of P2p_point.Id.t list
type args = {
address : P2p_addr.t;
port : int;
tls_cert_and_key : (string * string) option;
forwarding_endpoint : Uri.t;
}
let () =
register_error_kind
`Permanent
~id:"main.run.port_already_in_use"
~title:"Cannot start proxy server: RPC port already in use"
~description:"Another process is running on the same RPC port."
~pp:(fun ppf addrlist ->
Format.fprintf
ppf
"Another process is probably running on one of these addresses (%a). \
Please choose another RPC port."
(Format.pp_print_list P2p_point.Id.pp)
addrlist)
Data_encoding.(obj1 (req "addrlist" (list P2p_point.Id.encoding)))
(function
| Proxy_server_RPC_Port_already_in_use addrlist -> Some addrlist
| _ -> None)
(fun addrlist -> Proxy_server_RPC_Port_already_in_use addrlist)
let launch_rpc_server dir {address; port; tls_cert_and_key; forwarding_endpoint}
=
let open Lwt_result_syntax in
let host = Ipaddr.V6.to_string address in
let mode =
match tls_cert_and_key with
| None -> `TCP (`Port port)
| Some (cert, key) ->
`TLS (`Crt_file_path cert, `Key_file_path key, `No_password, `Port port)
in
let server =
Tezos_rpc_http_server.RPC_server.init_server
dir
~media_types:Tezos_rpc_http.Media_type.all_media_types
in
let middleware =
Tezos_rpc_http_server.RPC_middleware.proxy_server_query_forwarder
forwarding_endpoint
in
let callback =
Tezos_rpc_http_server.RPC_server.resto_callback server |> middleware
in
Lwt.catch
(fun () ->
let*! () =
Tezos_rpc_http_server.RPC_server.launch ~host server ~callback mode
in
Lwt.return_ok server)
(function
| Unix.Unix_error (EADDRINUSE, "bind", "") ->
tzfail (Proxy_server_RPC_Port_already_in_use [(address, port)])
| exn -> fail_with_exn exn)
let run dir ({address; port; _} as args) =
let open Lwt_result_syntax in
let*! () = Tezos_base_unix.Internal_event_unix.init () in
let node_downer =
Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ ->
Events.(emit shutting_down_proxy_server) ())
in
let* rpc = launch_rpc_server dir args in
let rpc_downer =
Lwt_exit.register_clean_up_callback
~loc:__LOC__
~after:[node_downer]
(fun _ ->
let*! () = Events.(emit shutting_down_rpc_server) () in
Tezos_rpc_http_server.RPC_server.shutdown rpc)
in
let*! () =
Events.(emit starting_rpc_server) (P2p_addr.to_string address, port)
in
let _ =
Lwt_exit.register_clean_up_callback
~loc:__LOC__
~after:[rpc_downer]
(fun _exit_status -> Tezos_base_unix.Internal_event_unix.close ())
in
Lwt_utils.never_ending ()