3 * Stefano Zacchiroli <zack@cs.unibo.it>
4 * for the HELM Team http://helm.cs.unibo.it/
6 * This file is part of HELM, an Hypertextual, Electronic
7 * Library of Mathematics, developed at the Computer Science
8 * Department, University of Bologna, Italy.
10 * HELM is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * HELM is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with HELM; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * For details, see the HELM World-Wide-Web page,
26 * http://helm.cs.unibo.it/
32 let broker_url = "localhost:49081/act";;
33 let dump_environment_on_exit = false;;
35 let init_tutor = Hbugs_id_generator.new_tutor_id;;
37 (** register a tutor to broker *)
38 let register_to_broker id url hint_type dsc =
41 Hbugs_messages.submit_req
42 ~url:broker_url (Register_tutor (id, url, hint_type, dsc))
45 | Tutor_registered id ->
46 prerr_endline (sprintf "Tutor registered, broker id: %s" id);
49 raise (Hbugs_messages.Unexpected_message unexpected_msg))
51 failwith (sprintf "Can't register tutor to broker: uncaught exception: %s"
52 (Printexc.to_string e))
54 (** unregister a tutor from the broker *)
55 let unregister_from_broker id =
56 let res = Hbugs_messages.submit_req ~url:broker_url (Unregister_tutor id) in
58 | Tutor_unregistered _ -> prerr_endline "Tutor unregistered!"
61 (sprintf "Can't unregister from broker, received unexpected msg: %s"
62 (Hbugs_messages.string_of_msg unexpected_msg))
65 (* typecheck a loaded proof *)
66 (* TODO this is a cut and paste from gTopLevel.ml *)
67 let typecheck_loaded_proof metasenv bo ty =
68 let module T = CicTypeChecker in
71 (fun metasenv ((_,context,ty) as conj) ->
72 ignore (T.type_of_aux' metasenv context ty) ;
75 ignore (T.type_of_aux' metasenv [] ty) ;
76 ignore (T.type_of_aux' metasenv [] bo)
79 type xml_kind = Body | Type;;
80 let mk_dtdname ~ask_dtd_to_the_getter dtd =
81 if ask_dtd_to_the_getter then
82 Configuration.getter_url ^ "getdtd?uri=" ^ dtd
84 "http://mowgli.cs.unibo.it/dtd/" ^ dtd
86 (** this function must be the inverse function of GTopLevel.strip_xml_headings
88 let add_xml_headings ~kind s =
89 let dtdname = mk_dtdname ~ask_dtd_to_the_getter:true "cic.dtd" in
92 | Body -> "CurrentProof"
93 | Type -> "ConstantType"
95 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\n" ^
96 "<!DOCTYPE " ^ root ^ " SYSTEM \""^ dtdname ^ "\">\n\n" ^
100 let load_state (type_string, body_string, goal) =
102 let ((tmp1, oc1), (tmp2, oc2)) =
103 (Filename.open_temp_file "" "", Filename.open_temp_file "" "")
106 output_string oc1 (add_xml_headings ~kind:Type type_string);
107 output_string oc2 (add_xml_headings ~kind:Body body_string);
108 close_out oc1; close_out oc2;
109 prerr_endline (sprintf "Proof Type available in %s" tmp1);
110 prerr_endline (sprintf "Proof Body available in %s" tmp2);
113 (match CicParser.obj_of_xml tmp1 (Some tmp2) with
114 | Cic.CurrentProof (_,metasenv,bo,ty,_) -> (* TODO il primo argomento e' una URI valida o e' casuale? *)
116 let uri = UriManager.uri_of_string "cic:/foo.con" in
118 typecheck_loaded_proof metasenv bo ty;
120 ((uri, metasenv, bo, ty), goal)
124 Sys.remove tmp1; Sys.remove tmp2;
127 (* tutors creation stuff from now on *)
129 module type HbugsTutor =
131 val start: unit -> unit
134 module type HbugsTutorDescription =
138 val tactic: ProofEngineTypes.tactic
140 val hint_type: hint_type
141 val description: string
142 val environment_file: string
145 module BuildTutor (Dsc: HbugsTutorDescription) : HbugsTutor =
147 let broker_id = ref None
148 let my_own_id = init_tutor ()
149 let my_own_addr, my_own_port = Dsc.addr, Dsc.port
150 let my_own_url = sprintf "%s:%d" my_own_addr my_own_port
152 let is_authenticated id =
153 match !broker_id with
155 | Some broker_id -> id = broker_id
157 (* thread who do the dirty work *)
158 let slave (state, musing_id) =
159 prerr_endline (sprintf "Hi, I'm the slave for musing %s" musing_id);
160 let (proof, goal) = load_state state in
163 ignore (Dsc.tactic (proof, goal));
169 (my_own_id, musing_id, (if success then Eureka Dsc.hint else Sorry))
171 ignore (Hbugs_messages.submit_req ~url:broker_url answer);
173 (sprintf "Bye, I've completed my duties (success = %b)" success)
176 (* hashtbl mapping musings ids to PID of threads doing the related (dirty)
178 let slaves = Hashtbl.create 17 in
180 prerr_endline "ignoring request from unauthorized broker";
181 Exception ("forbidden", "")
183 function (* _the_ callback *)
184 | Start_musing (broker_id, state) ->
185 if is_authenticated broker_id then begin
186 prerr_endline "received Start_musing";
187 let new_musing_id = Hbugs_id_generator.new_musing_id () in
189 (sprintf "starting a new musing (id = %s)" new_musing_id);
190 (* let slave_thread = Thread.create slave (state, new_musing_id) in *)
192 Hbugs_deity.create slave (state, new_musing_id)
194 Hashtbl.add slaves new_musing_id slave_thread;
195 Musing_started (my_own_id, new_musing_id)
196 end else (* broker unauthorized *)
198 | Abort_musing (broker_id, musing_id) ->
199 if is_authenticated broker_id then begin
200 (try (* kill thread responsible for "musing_id" *)
201 let slave_thread = Hashtbl.find slaves musing_id in
202 Hbugs_deity.kill slave_thread;
203 Hashtbl.remove slaves musing_id
205 | Hbugs_deity.Can_t_kill (pid, reason) ->
206 prerr_endline (sprintf "Unable to kill slave %d: %s" pid reason)
208 prerr_endline (sprintf
209 "Can't find slave corresponding to musing %s, can't kill it"
211 Musing_aborted (my_own_id, musing_id)
212 end else (* broker unauthorized *)
215 Exception ("unexpected_msg",
216 Hbugs_messages.string_of_msg unexpected_msg)
218 let callback (req: Http_types.request) outchan =
220 let req_msg = Hbugs_messages.msg_of_string req#body in
221 let answer = hbugs_callback req_msg in
222 Http_daemon.respond ~body:(Hbugs_messages.string_of_msg answer) outchan
223 with Hbugs_messages.Parse_error (subj, reason) ->
225 ~body:(Hbugs_messages.string_of_msg
226 (Exception ("parse_error", reason)))
229 let restore_environment () =
230 let ic = open_in Dsc.environment_file in
231 prerr_endline "Restoring environment ...";
232 CicEnvironment.restore_from_channel
233 ~callback:(fun uri -> prerr_endline uri) ic;
234 prerr_endline "... done!";
237 let dump_environment () =
238 let oc = open_out Dsc.environment_file in
239 prerr_endline "Dumping environment ...";
240 CicEnvironment.dump_to_channel
241 ~callback:(fun uri -> prerr_endline uri) oc;
242 prerr_endline "... done!";
247 Sys.catch_break true;
249 if dump_environment_on_exit then
251 unregister_from_broker my_own_id);
253 Some (register_to_broker
254 my_own_id my_own_url Dsc.hint_type Dsc.description);
255 if Sys.file_exists Dsc.environment_file then
256 restore_environment ();
258 ~addr:my_own_addr ~port:my_own_port ~mode:`Thread callback
259 with Sys.Break -> () (* exit nicely, invoking at_exit functions *)