Plasma GitLab Archive
Projects Blog Knowledge

(* $Id: webdav_client_ha.ml 9 2015-01-12 20:00:52Z gerd $ *)

open Webdav_client
open Webdav_compat

exception Service_unavailable of string


let configure_pipeline p host ip tmo retry =
  let opts = p # get_options in
  let opts' =
    { opts with
	Http_client.maximum_connection_failures = retry;
	maximum_message_errors = retry;
	connection_timeout = tmo;
	resolver = (fun _esys h p -> 
		      if h=host then
			p (Some ip)
		      else
			opts.Http_client.resolver _esys h p);
    } in
  p # set_options opts';
  ()


let pre_resolve base_urls =
  (* Returns list (base_url, host, ip) for the input list *)
  List.flatten
    (List.map
       (fun u ->
	  try
	    let h =
	      Neturl.url_host
		(Neturl.parse_url
		   ~base_syntax:Neturl.ip_url_syntax
		   ~accept_8bits:true
		   (Neturl.fixup_url_string 
		      u)) in
	    let ip_opt =
	      try Some(Unix.inet_addr_of_string h)
	      with _ -> None in
	    match ip_opt with
	      | Some ip ->
		  [ u, h, ip ]
	      | None ->
		  let he = Unix.gethostbyname h in
		  Array.to_list
		    (Array.map
		       (fun ip -> ( u, h, ip ))
		       he.Unix.h_addr_list
		    )
	  with
	    | _ -> []
       )
       base_urls)


let select_endpoint base_urls tmo =
  let l = pre_resolve base_urls in
  if l=[] then
    raise(Service_unavailable "Hostname resolution error");
  let esys = Unixqueue.create_unix_event_system() in
  let r = List.map (fun _ -> ref None) l in
  let t0 = Unix.gettimeofday() in
  List.iter2
    (fun (u, h, ip) d_opt ->
       let p = new Http_client.pipeline in
       configure_pipeline p h ip tmo 0;
       p # set_event_system esys;
       let m = new Http_client.options u in
       p # add_with_callback
	 m
	 (fun _ ->
	    let t1 = Unix.gettimeofday() in
	    let ok =
	      match m#status with
		| `Successful | `Redirection | `Client_error -> true
		| _ -> false in
	    if ok then
	      d_opt := Some (t1 -. t0)
	 )
    )
    l
    r;
  Unixqueue.run esys;
  let best = ref None in
  List.iter2
    (fun (u, h, ip) d_opt ->
       match !d_opt with
	 | None -> ()
	 | Some d ->
	     ( match !best with
		 | None ->
		     best := Some(u, h, ip, d)
		 | Some (_,_,_,d1) ->
		     if d < 2. *. d1 then
		       best := Some(u, h, ip, d)
	     )
    )
    l
    r;
  match !best with
    | None ->
	raise(Service_unavailable "No endpoint ready for service")
    | Some(u,h,ip,_) ->
	(u, ip)


let webdav_client ?pipeline (url, ip) =
  let wc = new Webdav_client.webdav_client ?pipeline url in
  let h =
    Neturl.url_host
      (Neturl.parse_url
	 ~base_syntax:Neturl.ip_url_syntax
	 ~accept_8bits:true
	 (Neturl.fixup_url_string 
	    url)) in
  configure_pipeline wc#pipeline h ip 300.0 2;
  wc

  


This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml