From 29485e412cf255f3f20b07a91813bda49e0b3b4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Mon, 27 Jan 2020 11:48:34 +0100
Subject: [PATCH] [server] launch gui

---
 bin/frama-c-zmq                  |  2 +
 src/plugins/server/main.ml       | 10 +++-
 src/plugins/server/server_zmq.ml | 88 ++++++++++++++++++++++++--------
 3 files changed, 76 insertions(+), 24 deletions(-)
 create mode 100755 bin/frama-c-zmq

diff --git a/bin/frama-c-zmq b/bin/frama-c-zmq
new file mode 100755
index 00000000000..a3a8d7179e4
--- /dev/null
+++ b/bin/frama-c-zmq
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "ZMQ Client *@"
diff --git a/src/plugins/server/main.ml b/src/plugins/server/main.ml
index 0a829101064..7528d3552ae 100644
--- a/src/plugins/server/main.ml
+++ b/src/plugins/server/main.ml
@@ -330,13 +330,19 @@ let run server =
         let idle_s = float_of_int idle_ms /. 1000.0 in
         while not server.shutdown do
           let activity = process server in
-          if not activity then Unix.sleepf idle_s ;
+          if not activity then
+            begin
+              Unix.sleepf idle_s ;
+              !Db.progress () ;
+            end
         done ;
       with Sys.Break -> () (* Ctr+C, just leave the loop normally *)
     end;
     Senv.feedback "Server shutdown." ;
     signal false ;
-  with exn ->
+  with
+  | Killed -> ()
+  | exn ->
     Senv.feedback "Server interruped (fatal error)." ;
     signal false ;
     raise exn
diff --git a/src/plugins/server/server_zmq.ml b/src/plugins/server/server_zmq.ml
index cb940de721d..b428bc39021 100644
--- a/src/plugins/server/server_zmq.ml
+++ b/src/plugins/server/server_zmq.ml
@@ -47,6 +47,12 @@ module Run = Senv.Action
       let help = "Launch the ZeroMQ server (until shutdown)."
     end)
 
+module Gui = Senv.Action
+    (struct
+      let option_name = "-server-gui"
+      let help = "Launch the external GUI."
+    end)
+
 let _ = Doc.page `Protocol ~title:"ZeroMQ Protocol" ~filename:"server_zmq.md"
 
 (* -------------------------------------------------------------------------- *)
@@ -60,7 +66,7 @@ let zmq_context =
     | Some ctxt -> ctxt
     | None ->
       let major,minor,patch = Zmq.version () in
-      Senv.feedback "ZeroMQ [v%d.%d.%d]" major minor patch ;
+      Senv.debug "ZeroMQ [v%d.%d.%d]" major minor patch ;
       let ctxt = Zmq.Context.create () in
       at_exit (fun () -> Zmq.Context.terminate ctxt) ;
       zmq := Some ctxt ; ctxt
@@ -125,32 +131,70 @@ let fetch socket () =
 (* -------------------------------------------------------------------------- *)
 
 let pretty = Format.pp_print_string
-let background = ref None
+let server = ref None
+let client = ref None
+
+let ping () =
+  match !client with None -> None | Some process ->
+  try Some (process ())
+  with Unix.Unix_error _ -> None
+
+let temp_url () =
+  let socket = Filename.temp_file "frama-c.socket" ".io" in
+  Extlib.safe_at_exit (fun () -> Extlib.safe_remove socket) ;
+  "ipc://" ^ socket
+
+let launch_client url server =
+  match !client with
+  | Some _ -> ()
+  | None ->
+    begin
+      let cmd = Filename.dirname Sys.argv.(0) ^ "/frama-c-zmq" in
+      let process = Command.command_async cmd [| "--connect" ; url |] in
+      Senv.debug "%s --connect %s@." cmd url ;
+      Senv.feedback "Client launched." ;
+      client := Some process ;
+      Extlib.safe_at_exit
+        begin fun () ->
+          match ping () with
+          | Some (Not_ready kill) ->
+            Senv.feedback "Client interrupted." ;
+            kill ()
+          | _ -> ()
+        end ;
+      Main.start server ;
+      Cmdline.at_normal_exit (fun () -> Main.run server);
+    end
+
+let establish url =
+  let context = zmq_context () in
+  let socket = Zmq.Socket.(create context rep) in
+  try
+    Zmq.Socket.bind socket url ;
+    Senv.debug "ZeroMQ [%s]" url ;
+    let srv = Main.create ~pretty ~fetch:(fetch socket) () in
+    server := Some(url,srv) ;
+    Extlib.safe_at_exit begin fun () ->
+      Main.stop srv ;
+      Zmq.Socket.close socket ;
+      server := None ;
+    end ;
+    if Gui.get () then launch_client url srv else
+    if Run.get () then Main.run srv else Main.start srv ;
+  with exn ->
+    Zmq.Socket.close socket ;
+    raise exn
 
 let cmdline () =
   begin
-    match !background with
-    | Some server ->
-      if Run.get () then Main.run server
+    match !server with
+    | Some(url,srv) ->
+      if Gui.get () then launch_client url srv else
+      if Run.get () then Main.run srv
     | None ->
       let url = Socket.get () in
-      if url <> "" then
-        let context = zmq_context () in
-        let socket = Zmq.Socket.(create context rep) in
-        try
-          Zmq.Socket.bind socket url ;
-          Senv.feedback "ZeroMQ [%s]" url ;
-          let server = Main.create ~pretty ~fetch:(fetch socket) () in
-          background := Some server ;
-          at_exit begin fun () ->
-            Main.stop server ;
-            Zmq.Socket.close socket ;
-            background := None ;
-          end ;
-          if Run.get () then Main.run server else Main.start server ;
-        with exn ->
-          Zmq.Socket.close socket ;
-          raise exn
+      if url <> "" then establish url else
+      if Gui.get () then establish (temp_url())
   end
 
 let () = Db.Main.extend cmdline
-- 
GitLab