]> matita.cs.unibo.it Git - helm.git/blob - helm/searchEngine/searchEngine.ml
minimal changes:
[helm.git] / helm / searchEngine / searchEngine.ml
1 (* Copyright (C) 2002, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 let debug = true;;
27 let debug_print s = if debug then prerr_endline s;;
28 Http_common.debug := true;;
29
30 open Printf;;
31
32 let daemon_name = "Search Engine";;
33 let default_port = 58085;;
34 let port_env_var = "SEARCH_ENGINE_PORT";;
35
36 let pages_dir = "html";; (* relative to searchEngine's document root *)
37 let interactive_user_uri_choice_TPL = pages_dir ^ "/templateambigpdq1.html";;
38 let interactive_interpretation_choice_TPL = pages_dir ^ "/templateambigpdq2.html";;
39 let final_results_TPL = pages_dir ^ "/templateambigpdq3.html";;
40
41 exception Chat_unfinished
42
43   (** chain application of Pcre substitutions *)
44 let rec apply_substs substs line =
45   match substs with
46   | [] -> line
47   | (rex, templ) :: rest -> apply_substs rest (Pcre.replace ~rex ~templ line)
48   (** fold like function on files *)
49 let fold_file f init fname =
50   let inchan = open_in fname in
51   let rec fold_lines' value =
52     try 
53       let line = input_line inchan in 
54       fold_lines' (f value line)
55     with End_of_file -> value
56   in
57   let res = (try fold_lines' init with e -> (close_in inchan; raise e)) in
58   close_in inchan;
59   res
60   (** iter like function on files *)
61 let iter_file f = fold_file (fun _ line -> f line) ()
62
63 let (title_tag_RE, choices_tag_RE, msg_tag_RE, id_to_uris_RE, id_RE,
64     interpretations_RE, interpretations_labels_RE, results_RE, new_aliases_RE) =
65   (Pcre.regexp "@TITLE@", Pcre.regexp "@CHOICES@", Pcre.regexp "@MSG@",
66   Pcre.regexp "@ID_TO_URIS@", Pcre.regexp "@ID@",
67   Pcre.regexp "@INTERPRETATIONS@", Pcre.regexp "@INTERPRETATIONS_LABELS@",
68   Pcre.regexp "@RESULTS@", Pcre.regexp "@NEW_ALIASES@")
69
70 let port =
71   try
72     int_of_string (Sys.getenv port_env_var)
73   with
74   | Not_found -> default_port
75   | Failure "int_of_string" ->
76       prerr_endline "Warning: invalid port, reverting to default";
77       default_port
78 in
79 let pp_result result =
80   let result_string = MQueryUtil.text_of_result result "\n" in
81   (sprintf "<html>\n<head>\n</head>\n<body>\n<pre>%s</pre>\n</body>\n</html>"
82     result_string)
83 in
84 let pp_error = sprintf "<html><body><h1>Error: %s</h1></body></html>" in
85 let bad_request body outchan =
86   Http_daemon.respond_error ~status:(`Client_error `Bad_request) ~body outchan
87 in
88 let contype = "Content-Type", "text/html" in
89
90 (* SEARCH ENGINE functions *)
91
92 let refine_constraints (x, y, z) = (x, y, z), (Some x, Some y, Some z) in
93
94 (* HTTP DAEMON CALLBACK *)
95
96 let callback (req: Http_types.request) outchan =
97   try
98     debug_print (sprintf "Received request: %s" req#path);
99     (match req#path with
100     | "/execute" ->
101         let query_string = req#param "query" in
102         let lexbuf = Lexing.from_string query_string in
103         let query = MQueryUtil.query_of_text lexbuf in
104         let result = MQueryGenerator.execute_query query in
105         let result_string = MQueryUtil.text_of_result result "\n" in
106         Http_daemon.respond
107           ~body:
108             (sprintf "<html><body><pre>%s</pre></body></html>" result_string)
109           ~headers:[contype] outchan
110     | "/locate" ->
111         let id = req#param "id" in
112         let result = MQueryGenerator.locate id in
113         Http_daemon.respond ~headers:[contype] ~body:(pp_result result) outchan
114     | "/getpage" ->
115         (* TODO implement "is_permitted" *)
116         (let is_permitted _ = true in
117         let remove_fragment uri = Pcre.replace ~pat:"#.*" uri in
118         let page = remove_fragment (req#param "url") in
119         match page with
120         | page when is_permitted page ->
121             Http_daemon.respond_file
122               ~fname:(sprintf "%s/%s" pages_dir page) outchan
123         | page -> Http_daemon.respond_forbidden ~url:page outchan)
124     | "/searchPattern" ->
125         let term_string = req#param "term" in
126         let lexbuf = Lexing.from_string term_string in
127         let (context, metasenv) = ([], []) in
128         let (dom, mk_metasenv_and_expr) =
129           CicTextualParserContext.main
130             ~context ~metasenv CicTextualLexer.token lexbuf
131         in
132         let id_to_uris_raw = req#param "aliases" in
133         let tokens = Pcre.split ~pat:"\\s" id_to_uris_raw in
134         let rec parse_tokens keys lookup = function (* TODO spostarla fuori *)
135           | [] -> keys, lookup
136           | "alias" :: key :: value :: rest ->
137               parse_tokens
138                 (key::keys)
139                 (fun id ->
140                   if id = key then
141                     Some (Disambiguate.cic_textual_parser_uri_of_string value)
142                   else lookup id)
143                 rest
144           | _ -> failwith "Can't parse aliases"
145         in
146         let parse_choices choices_raw =
147           let choices = Pcre.split ~pat:";" choices_raw in
148           List.fold_left
149             (fun f x ->
150               match Pcre.split ~pat:"\\s" x with
151               | ""::id::tail
152               | id::tail when id<>"" ->
153                   (fun id' ->
154                     if id = id' then
155                       Some (List.map (fun u -> Netencoding.Url.decode u) tail)
156                     else
157                       f id')
158               | _ -> failwith "Can't parse choices")
159             (fun _ -> None)
160             choices
161         in
162         let id_to_uris = parse_tokens [] (fun _ -> None) tokens in
163         let id_to_choices =
164           try
165             let choices_raw = req#param "choices" in
166             parse_choices choices_raw
167           with Http_types.Param_not_found _ -> (fun _ -> None)
168         in
169         let module Chat: Disambiguate.Callbacks =
170           struct
171
172             let output_html = prerr_endline
173
174             let interactive_user_uri_choice
175               ~selection_mode ?ok
176               ?enable_button_for_non_vars ~(title: string) ~(msg: string)
177               ~(id: string) (choices: string list)
178               =
179                 (match id_to_choices id with
180                 | Some choices -> choices
181                 | None ->
182                   let msg = Pcre.replace ~pat:"\"" ~templ:"\\\"" msg in
183                   (match selection_mode with
184                   | `SINGLE -> assert false
185                   | `EXTENDED ->
186                       iter_file
187                         (fun line ->
188                           let formatted_choices =
189                             String.concat ","
190                               (List.map (fun uri -> sprintf "\"%s\"" uri) choices)
191                           in
192                           let processed_line =
193                             apply_substs
194                               [title_tag_RE, title;
195                                choices_tag_RE, formatted_choices;
196                                msg_tag_RE, msg;
197                                id_to_uris_RE, id_to_uris_raw;
198                                id_RE, id]
199                               line
200                           in
201                           output_string outchan processed_line)
202                         interactive_user_uri_choice_TPL;
203                       raise Chat_unfinished))
204
205             let interactive_interpretation_choice interpretations =
206               let html_interpretations_labels =
207                 String.concat ", "
208                   (List.map
209                     (fun l ->
210                       "\"" ^
211                       (String.concat "<br />"
212                         (List.map
213                           (fun (id, value) ->
214                             (sprintf "alias %s %s" id value))
215                           l)) ^
216                       "\"")
217                   interpretations)
218               in
219               let html_interpretations =
220                 String.concat ", "
221                   (List.map
222                     (fun l ->
223                       "\"" ^
224                       (String.concat " "
225                         (List.map
226                           (fun (id, value) ->
227                             (sprintf "alias %s %s"
228                               id
229                               (Disambiguate.wrong_xpointer_format_from_wrong_xpointer_format'
230                                 value)))
231                           l)) ^
232                       "\"")
233                     interpretations)
234               in
235               iter_file
236                 (fun line ->
237                   let processed_line =
238                     apply_substs
239                       [interpretations_RE, html_interpretations;
240                        interpretations_labels_RE, html_interpretations_labels]
241                       line
242                   in
243                   output_string outchan processed_line)
244                 interactive_interpretation_choice_TPL;
245               raise Chat_unfinished
246
247             let input_or_locate_uri ~title =
248               UriManager.uri_of_string "cic:/Coq/Init/DataTypes/nat_ind.con"
249
250           end
251         in
252         let module Disambiguate' = Disambiguate.Make (Chat) in
253         let (id_to_uris', metasenv', term') =
254           Disambiguate'.disambiguate_input
255             context metasenv dom mk_metasenv_and_expr id_to_uris
256         in
257         (match metasenv' with
258         | [] ->
259             let must = MQueryLevels2.get_constraints term' in
260             let must',only = refine_constraints must in
261             let results = MQueryGenerator.searchPattern must' only in 
262             iter_file
263               (fun line ->
264                 let new_aliases =
265                   match id_to_uris' with
266                   | (domain, f) ->
267                       String.concat ", "
268                         (List.map
269                           (fun name ->
270                             sprintf "\"alias %s cic:%s\""
271                               name
272                               (match f name with
273                               | None -> assert false
274                               | Some t ->
275                                   Disambiguate.string_of_cic_textual_parser_uri
276                                     t))
277                           domain)
278                 in
279                 let processed_line =
280                   apply_substs
281                     [results_RE, MQueryUtil.text_of_result results "\n";
282                      new_aliases_RE, new_aliases]
283                     line
284                 in
285                 output_string outchan processed_line)
286               final_results_TPL
287         | _ -> (* unable to instantiate some implicit variable *)
288             Http_daemon.respond
289               ~headers:[contype]
290               ~body:"some implicit variables are still unistantiated :-("
291               outchan)
292
293     | invalid_request ->
294         Http_daemon.respond_error ~status:(`Client_error `Bad_request) outchan);
295     debug_print (sprintf "%s done!" req#path)
296   with
297   | Chat_unfinished -> prerr_endline "Chat unfinished, Try again!"
298   | Http_types.Param_not_found attr_name ->
299       bad_request (sprintf "Parameter '%s' is missing" attr_name) outchan
300   | exc ->
301       Http_daemon.respond
302         ~body:(pp_error ("Uncaught exception: " ^ (Printexc.to_string exc)))
303         outchan
304 in
305 printf "%s started and listening on port %d\n" daemon_name port;
306 printf "current directory is %s\n" (Sys.getcwd ());
307 flush stdout;
308 Unix.putenv "http_proxy" "";
309 Mqint.set_database Mqint.postgres_db;
310 Mqint.init "host=mowgli.cs.unibo.it dbname=helm_mowgli_new_schema user=helm";
311 Http_daemon.start' ~port callback;
312 Mqint.close ();
313 printf "%s is terminating, bye!\n" daemon_name
314