From 315b412079b1a251bfa4791a31f2028020ceef47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Thu, 16 Dec 2021 19:48:03 +0100
Subject: [PATCH] [ivette/server] socket client functional

---
 ivette/src/frama-c/client_socket.ts | 16 ++++++++--------
 ivette/src/frama-c/server.ts        | 17 -----------------
 ivette/src/frama-c/states.ts        | 19 +++++++++++++------
 src/plugins/server/server_socket.ml |  2 --
 4 files changed, 21 insertions(+), 33 deletions(-)

diff --git a/ivette/src/frama-c/client_socket.ts b/ivette/src/frama-c/client_socket.ts
index 07ecc231026..c1f87b9e1ed 100644
--- a/ivette/src/frama-c/client_socket.ts
+++ b/ivette/src/frama-c/client_socket.ts
@@ -159,31 +159,31 @@ class SocketClient extends Client {
             'W' + padding.substring(hex.length, 15);
       s.write(Buffer.from(header + hex));
       s.write(data);
-      console.log('SENT', header + hex + data.toString('utf8'), data.length);
     }
   }
 
   _fetch(): undefined | string {
     const msg = this.buffer;
     const len = msg.length;
-    this.buffer = msg;
     if (len < 1) return;
     const hd = msg.readInt8(0);
     // 'S': 83, 'L': 76, 'W': 87
-    const nhex = hd == 83 ? 3 : hd == 76 ? 7 : 15;
-    if (len < 1 + nhex) return;
-    const size = Number.parseInt(msg.slice(1, nhex).toString('ascii'), 16);
-    const offset = 1 + nhex + size;
+    const phex = hd == 83 ? 4 : hd == 76 ? 8 : 16;
+    if (len < phex) return;
+    const size = Number.parseInt(msg.slice(1, phex).toString('ascii'), 16);
+    const offset = phex + size;
     if (len < offset) return;
     this.buffer = msg.slice(offset);
-    return msg.slice(1 + nhex, offset).toString('utf8');
+    return msg.slice(phex, offset).toString('utf8');
   }
 
   _receive(chunk: Buffer) {
     this.buffer = Buffer.concat([this.buffer, chunk]);
     while (true) {
+      const n0 = this.buffer.length;
       const data = this._fetch();
-      if (data === undefined) break;
+      const n1 = this.buffer.length;
+      if (data === undefined || n0 <= n1) break;
       try {
         const cmd: any = JSON.parse(data);
         if (cmd !== null && typeof (cmd) === 'object') {
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index 5386ff3dcb5..bfad8423662 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -39,12 +39,6 @@ import { RichTextBuffer } from 'dome/text/buffers';
 import { ChildProcess } from 'child_process';
 import { client } from './client_socket';
 
-// --------------------------------------------------------------------------
-// --- Pretty Printing (Browser Console)
-// --------------------------------------------------------------------------
-
-const D = new Dome.Debug('Server');
-
 // --------------------------------------------------------------------------
 // --- Events
 // --------------------------------------------------------------------------
@@ -189,7 +183,6 @@ export function onShutdown(callback: () => void) { SHUTDOWN.on(callback); }
 
 function _status(newStatus: Status) {
   if (newStatus !== status) {
-    D.log('Server', newStatus);
     const oldStatus = status;
     status = newStatus;
     STATUS.emit(newStatus);
@@ -439,8 +432,6 @@ async function _launch() {
   process?.stdout?.on('data', logger);
   process?.stderr?.on('data', logger);
   process?.on('exit', (code: number | null, signal: string | null) => {
-    D.log('Process exited');
-
     if (signal) {
       // [signal] is non-null.
       buffer.log('[frama-c]', signal);
@@ -479,13 +470,11 @@ function _clear() {
 }
 
 function _kill() {
-  D.log('Hard kill');
   client.disconnect();
   if (process) process.kill();
 }
 
 async function _shutdown() {
-  D.log('Shutdown');
   _clear();
   client.shutdown();
   const killingPromise = new Promise((resolve) => {
@@ -731,12 +720,8 @@ function _resolved(id: string) {
 
 client.onConnect((err?: Error) => {
   if (err) {
-    if (Dome.DEVEL)
-      buffer.log('[client]', err.toString());
     _status(Status.FAILURE);
   } else {
-    if (Dome.DEVEL)
-      buffer.log('[client] Connected.');
     _status(Status.ON);
   }
 });
@@ -758,7 +743,6 @@ client.onKilled((id: string) => {
 });
 
 client.onRejected((id: string) => {
-  D.log('Rejected', id);
   const p = pending.get(id);
   if (p) {
     p.reject();
@@ -767,7 +751,6 @@ client.onRejected((id: string) => {
 });
 
 client.onError((id: string, msg: string) => {
-  D.log('Request error', id, msg);
   const p = pending.get(id);
   if (p) {
     p.reject();
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index a3c5081f648..02dc57a079e 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -308,8 +308,11 @@ class SyncState<A> {
   async update() {
     try {
       this.upToDate = true;
-      const v = await Server.send(this.handler.getter, null);
-      this.value = v;
+      this.value = undefined;
+      if (Server.isRunning()) {
+        const v = await Server.send(this.handler.getter, null);
+        this.value = v;
+      }
       this.UPDATE.emit();
     } catch (error) {
       D.error(
@@ -761,6 +764,7 @@ const emptySelection = {
 
 export const MetaSelection = new Dome.Event<Location>('frama-c-meta-selection');
 export const GlobalSelection = new GlobalState<Selection>(emptySelection);
+
 Server.onShutdown(() => GlobalSelection.setValue(emptySelection));
 
 export function setSelection(location: Location, meta = false) {
@@ -778,12 +782,15 @@ export function useSelection(): [Selection, (a: SelectionActions) => void] {
 /** Resets the selected locations. */
 export async function resetSelection() {
   GlobalSelection.setValue(emptySelection);
-  const main = await Server.send(Ast.getMainFunction, {});
-  // If the selection has already been modified, do not change it.
-  if (main && GlobalSelection.getValue() === emptySelection) {
-    GlobalSelection.setValue({ ...emptySelection, current: { fct: main } });
+  if (Server.isRunning()) {
+    const main = await Server.send(Ast.getMainFunction, {});
+    // If the selection has already been modified, do not change it.
+    if (main && GlobalSelection.getValue() === emptySelection) {
+      GlobalSelection.setValue({ ...emptySelection, current: { fct: main } });
+    }
   }
 }
+
 /* Select the main function when the current project changes and the selection
    is still empty (which happens at the start of the GUI). */
 PROJECT.on(async () => {
diff --git a/src/plugins/server/server_socket.ml b/src/plugins/server/server_socket.ml
index 83a8d616373..ab7fac70a0f 100644
--- a/src/plugins/server/server_socket.ml
+++ b/src/plugins/server/server_socket.ml
@@ -63,7 +63,6 @@ let feed_bytes ch =
   if not ch.eof then
     try
       let n = input ch.inc ch.tmp 0 buffer_size in
-      if n > 0 then Format.eprintf "READ %d bytes@." n ;
       Buffer.add_subbytes ch.buffer ch.tmp 0 n ;
     with
     | Sys_blocked_io -> ()
@@ -71,7 +70,6 @@ let feed_bytes ch =
 
 let read_data ch =
   try
-    Format.eprintf "DATA %S@." (Buffer.contents ch.buffer) ;
     let h = match Buffer.nth ch.buffer 0 with
       | 'S' -> 3
       | 'L' -> 7
-- 
GitLab