Raw File
kasa_client.ml
(******************************************************************************)
(*  _  __ * The Kappa Language                                                *)
(* | |/ / * Copyright 2010-2019 CNRS - Harvard Medical School - INRIA - IRIF  *)
(* | ' /  *********************************************************************)
(* | . \  * This file is distributed under the terms of the                   *)
(* |_|\_\ * GNU Lesser General Public License Version 3                       *)
(******************************************************************************)

type mailbox =
  (int,
   (Yojson.Basic.t,
    Exception_without_parameter.method_handler) Result.result Lwt.u)
    Hashtbl.t

let reply_of_string x =
  match Yojson.Basic.from_string x with
  | `Assoc [ "id", ` Int id; "code", `String "ERROR"; "data", err ] ->
    Some id,Result.Error (Exception_without_parameter.of_json err)
  | `Assoc [ "id", ` Int id; "code", `String "SUCCESS"; "data", data ] ->
    Some id,Result.Ok data
  | x ->
    None, Result.Error
      (Exception_without_parameter.add_uncaught_error
         (Exception_without_parameter.build_uncaught_exception
            ~file_name:"kasa_client"
            ~message:("Invalid response from KaSa: "^Yojson.Basic.to_string x)
            Exit)
         Exception_without_parameter.empty_error_handler)

let receive mailbox x =
  match reply_of_string x with
  | Some id, out ->
    let thread = Hashtbl.find mailbox id in
    let () = Hashtbl.remove mailbox id in
    Lwt.wakeup thread out
  | None, _ -> ()

let new_mailbox () = Hashtbl.create 2

let is_computing mailbox = Hashtbl.length mailbox <> 0

class virtual new_client ~post (mailbox : mailbox) :
  Api.manager_static_analysis =
  object(self)
    val mutable id = 0
    method virtual is_running : bool

    method private raw_message post request =
      if self#is_running then
        let result,feeder = Lwt.task () in
        let outbuf = Bi_outbuf.create 1024 in
        let () = Bi_outbuf.add_string outbuf "{id:" in
        let () = Bi_outbuf.add_string outbuf (string_of_int id) in
        let () = Bi_outbuf.add_string outbuf ",data:" in
        let () = request outbuf in
        let () = Bi_outbuf.add_string outbuf "}" in
        let () = post (Bi_outbuf.contents outbuf) in
        let () = Hashtbl.replace mailbox id feeder in
        let () = id <- id+1 in
        result
      else
        Lwt.return_error
          (Exception_without_parameter.add_uncaught_error
             (Exception_without_parameter.build_uncaught_exception
                ~file_name:"kasa_client"
                ~message:"KaSa agent is dead"
                Exit)
             Exception_without_parameter.empty_error_handler)
    method private message request =
      self#raw_message post (fun outb -> Yojson.Basic.to_outbuf outb request)

    method init_static_analyser_raw compil =
      let request outbuf =
        let () = Bi_outbuf.add_string outbuf "[ \"INIT\", " in
        let () = Bi_outbuf.add_string outbuf compil in
        Bi_outbuf.add_string outbuf "]" in
      Lwt_result.bind_result
        (self#raw_message post request)
        (function
          | `Null -> Result.Ok ()
          | x -> Result.Error
                   (Exception_without_parameter.add_uncaught_error
                      (Exception_without_parameter.build_uncaught_exception
                         ~file_name:"kasa_client"
                         ~message:("Not a KaSa INIT response: "^
                                   Yojson.Basic.to_string x)
                         Exit)
                      Exception_without_parameter.empty_error_handler))
    method init_static_analyser compil =
      self#init_static_analyser_raw
        (Yojson.Basic.to_string (Ast.compil_to_json compil))

    method get_contact_map accuracy =
      let request =
        `List ( `String "CONTACT_MAP" :: match accuracy with
          | None -> []
          | Some a -> [Public_data.accuracy_to_json a]) in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok x)
    method get_influence_map_raw accuracy =
      let request =
        `List ( `String "INFLUENCE_MAP" :: match accuracy with
          | None -> []
          | Some a -> [Public_data.accuracy_to_json a]) in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Yojson.Basic.to_string x))
    method get_local_influence_map accuracy ?fwd ?bwd ?origin ~total =
          let request =
            `List ( `String "INFLUENCE_MAP" :: (
                (fun accuracy l ->
                 match accuracy with
                 | None -> l
                 | Some a -> (Public_data.accuracy_to_json a)::l)
                  accuracy
                  [JsonUtil.of_option JsonUtil.of_int fwd;
                   JsonUtil.of_option JsonUtil.of_int bwd;
                   JsonUtil.of_int total;
                   JsonUtil.of_option Public_data.short_influence_node_to_json origin]
              ))
                 in
          Lwt_result.bind_result
            (self#message request)
            (fun x ->
               let o = Public_data.local_influence_map_of_json x in
               Result.Ok o)
    method get_initial_node =
      let request =
        `List [`String "INFLUENCE_MAP_ORIGINAL_NODE"]
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x ->
           let o = JsonUtil.to_option
               Public_data.refined_influence_node_of_json x in
           Result.Ok o)
    method get_next_node json =
      let request =
        `List [`String "INFLUENCE_MAP_NEXT_NODE";
               JsonUtil.of_option Public_data.short_influence_node_to_json json]
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x ->
           let o = JsonUtil.to_option
               Public_data.refined_influence_node_of_json x in
           Result.Ok o)

    method get_previous_node json =
      let request =
        `List [`String "INFLUENCE_MAP_PREVIOUS_NODE";
               JsonUtil.of_option Public_data.short_influence_node_to_json json]
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x ->
           let o = JsonUtil.to_option
               Public_data.refined_influence_node_of_json x in
           Result.Ok o)
    method get_nodes_of_influence_map accuracy =
      let request = `List ( `String "INFLUENCE_MAP_ALL_NODES"  ::
                            (match accuracy with
                             | None -> []
                             | Some a -> [Public_data.accuracy_to_json a]))
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.nodes_of_influence_map_of_json x))
    method get_dead_rules =
      let request = `List [ `String "DEAD_RULES" ] in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.dead_rules_of_json x))
    method get_dead_agents =
      let request = `List [ `String "DEAD_AGENTS" ] in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.json_to_dead_agents x))
    method get_non_weakly_reversible_transitions =
      let request =
        `List [ `String "NON_WEAKLY_REVERSIBLE_TRANSITIONS" ]
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.separating_transitions_of_json x))
    method get_constraints_list =
      let request = `List [ `String "CONSTRAINTS" ] in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.lemmas_list_of_json x))
    method get_potential_polymers accuracy_cm accuracy_scc =
      let request = `List ( `String "POLYMERS" ::   (
         match accuracy_cm, accuracy_scc with
           | None,None -> []
           | Some a,None  -> [Public_data.accuracy_to_json a]
           | Some a, Some b ->
             [
               Public_data.accuracy_to_json a;
               Public_data.accuracy_to_json b
             ]
           | None, Some b ->
             [
               Public_data.accuracy_to_json Public_data.Low ;
               Public_data.accuracy_to_json b
             ] ))
      in
      Lwt_result.bind_result
        (self#message request)
        (fun x -> Result.Ok (Public_data.scc_of_json x))
  end
back to top