Skip to content
Snippets Groups Projects
Commit 5b8024ca authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[ivette/server] restore ZMQ client

Failing due to non-context aware native modules
parent 5e924053
No related branches found
No related tags found
No related merge requests found
...@@ -9,5 +9,3 @@ lib ...@@ -9,5 +9,3 @@ lib
# don't lint the generated API # don't lint the generated API
api api
# ZMQ Server is not working (yet)
src/frama-c/client_zmq.ts
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"@types/react": "^16", "@types/react": "^16",
"@types/react-dom": "^16", "@types/react-dom": "^16",
"@types/react-virtualized": "^9.21.0", "@types/react-virtualized": "^9.21.0",
"@types/zeromq": "^5.2.1",
"@typescript-eslint/eslint-plugin": "", "@typescript-eslint/eslint-plugin": "",
"@typescript-eslint/parser": "", "@typescript-eslint/parser": "",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
...@@ -77,6 +78,7 @@ ...@@ -77,6 +78,7 @@
"react-virtualized": "^9.22.3", "react-virtualized": "^9.22.3",
"react-window": "", "react-window": "",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"tippy.js": "" "tippy.js": "",
"zeromq": "^5.2.8"
} }
} }
...@@ -20,23 +20,20 @@ ...@@ -20,23 +20,20 @@
/* */ /* */
/* ************************************************************************ */ /* ************************************************************************ */
import Emitter from 'events'; import * as ZMQ from 'zeromq';
import { Request as ZmqRequest } from 'zeromq'; import { Debug } from 'dome';
import { json } from 'dome/data/json';
import { Client } from './client'; import { Client } from './client';
const pollingTimeout = 50; const D = new Debug('ZmqServer');
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- Frama-C Server API // --- Frama-C Server API
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
class ZmqClient implements Client { class ZmqClient extends Client {
events = new Emitter(); queue: string[] = [];
queueCmd: string[] = []; zmqSocket: ZMQ.Socket | undefined;
queueId: string[] = [];
zmqSocket: ZmqRequest | undefined;
zmqIsBusy = false; zmqIsBusy = false;
/** Server CLI */ /** Server CLI */
...@@ -46,18 +43,18 @@ class ZmqClient implements Client { ...@@ -46,18 +43,18 @@ class ZmqClient implements Client {
/** Connection */ /** Connection */
connect(sockaddr: string): void { connect(sockaddr: string): void {
if (!this.zmqSocket) { if (this.zmqSocket) {
this.zmqSocket.close(); this.zmqSocket.close();
} }
this.zmqSocket = new ZmqRequest(); this.zmqSocket = new ZMQ.Socket('req');
this.zmqIsBusy = false; this.zmqIsBusy = false;
this.zmqSocket.connect(sockaddr); this.zmqSocket.connect(`ipc://${sockaddr}`);
this.zmqSocket.on('message', (msg: string[]) => this._receive(msg));
} }
disconnect(): void { disconnect(): void {
this.zmqIsBusy = false; this.zmqIsBusy = false;
this.queueCmd = []; this.queue = [];
this.queueId = [];
if (this.zmqSocket) { if (this.zmqSocket) {
this.zmqSocket.close(); this.zmqSocket.close();
this.zmqSocket = undefined; this.zmqSocket = undefined;
...@@ -66,191 +63,137 @@ class ZmqClient implements Client { ...@@ -66,191 +63,137 @@ class ZmqClient implements Client {
/** Send Request */ /** Send Request */
send(kind: string, id: string, request: string, data: any): void { send(kind: string, id: string, request: string, data: any): void {
this.queueCmd.push(kind, id, request, data); if (this.zmqSocket) {
this.queueId.push(id); this.queue.push(kind, id, request, data);
this._flush(); this._flush();
}
} }
/** Signal ON */ /** Signal ON */
sigOn(id: string): void { this.queueCmd.push('SIGON', id); this._flush(); } sigOn(id: string): void {
if (this.zmqSocket) {
this.queue.push('SIGON', id);
this._flush();
}
}
/** Signal ON */ /** Signal ON */
sigOff(id: string): void { this.queueCmd.push('SIGOFF', id); this._flush(); } sigOff(id: string): void {
if (this.zmqSocket) {
this.queue.push('SIGOFF', id);
this._flush();
}
}
/** Kill Request */ /** Kill Request */
kill(id: string): void { kill(id: string): void {
if (this.zmqSocket) { if (this.zmqSocket) {
this.queueCmd.push('KILL', id); this.queue.push('KILL', id);
this._flush(); this._flush();
} }
} }
/** Polling */ /** Polling */
poll(): void { } poll(): void {
if (this.zmqSocket && this.queue.length == 0) {
/** Shutdown the server */ this.queue.push('POLL');
shutdown(): void { }
this._reset();
this._flush(); this._flush();
this.queueCmd.push('SHUTDOWN');
}
/** Request data callback */
onData(callback: (id: string, data: json) => void): void {
this.events.on('DATA', callback);
}
/** Rejected request callback */
onRejected(callback: (id: string, err: string) => void): void {
this.events.on('REJECT', callback);
}
/** Request error callback */
onError(callback: (msg: string) => void): void {
this.events.on('ERROR', callback);
}
/** Killed request callback */
onKilled(callback: (id: string) => void): void {
this.events.on('KILL', callback);
} }
/** Signal callback */ /** Shutdown the server */
onSignal(callback: (id: string) => void): void { shutdown(): void {
this.events.on('SIGNAL', callback); this.queue = [];
} if (this.zmqSocket) {
this.queue.push('SHUTDOWN');
/** Idle callback */ this._flush();
onIdle(callback: () => void): void { }
this.events.on('CALLBACK', callback);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- Low-Level Management // --- Low-Level Management
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
pollingTimer: NodeJS.Timeout | undefined;
flushingTimer: NodeJS.Immediate | undefined;
_reset() {
if (this.flushingTimer) {
clearImmediate(this.flushingTimer);
this.flushingTimer = undefined;
}
if (this.pollingTimer) {
clearTimeout(this.pollingTimer);
this.pollingTimer = undefined;
}
}
_flush() { _flush() {
if (!this.flushingTimer) { const socket = this.zmqSocket;
this.flushingTimer = setImmediate(() => { if (socket) {
this.flushingTimer = undefined; const cmds = this.queue;
this._send(); if (cmds && !this.zmqIsBusy) {
}); try {
} this.queue = [];
} socket.send(cmds);
this.zmqIsBusy = true;
_poll() { } catch (err) {
if (!this.pollingTimer) { D.error('ZmqSocket', err);
this.pollingTimer = setTimeout(() => { this.zmqIsBusy = false;
this.pollingTimer = undefined; }
this._send(); }
}, pollingTimeout); } else {
this.queue = [];
} }
} }
async _send() { _receive(resp: string[]) {
// when busy, will be eventually re-triggered try {
if (!this.zmqIsBusy) { this._decode(resp);
const cmds = this.queueCmd; } catch (err) {
if (!cmds.length) { D.error('ZmqSocket', err);
this.queueCmd.push('POLL'); } finally {
this.events.emit('IDLE');
}
this.zmqIsBusy = true;
const ids = this.queueId;
this.queueCmd = [];
this.queueId = [];
try {
await this.zmqSocket?.send(cmds);
const resp = await this.zmqSocket?.receive();
this._receive(resp);
} catch (error) {
this._error(`Error in send/receive on ZMQ socket. ${error.toString()}`);
const err = 'Canceled request';
ids.forEach((rid) => this._reject(rid, err));
}
this.zmqIsBusy = false; this.zmqIsBusy = false;
this.events.emit('IDLE'); setImmediate(() => this._flush());
} }
} }
_data(id: string, data: any) { /* eslint-disable @typescript-eslint/indent */
this.events.emit('DATA', id, data); _decode(resp: string[]) {
} const shift = () => resp.shift() ?? '';
while (resp.length) {
_reject(id: string, error: string) { const cmd = shift();
this.events.emit('REJECT', id, error); switch (cmd) {
} case 'NONE':
break;
_signal(id: string) { case 'DATA':
this.events.emit('SIGNAL', id); {
} const rid = shift();
const data = JSON.parse(shift());
_error(err: any) { this.emitData(rid, data);
this.events.emit('ERROR', err); }
} break;
case 'KILLED':
_receive(resp: any) { {
try { const rid = shift();
let rid; this.emitKilled(rid);
let data; }
let err; break;
let cmd; case 'ERROR':
const shift = () => resp.shift().toString(); {
let unknownResponse = false; const rid = shift();
while (resp.length && !unknownResponse) { const msg = shift();
cmd = shift(); this.emitError(rid, msg);
switch (cmd) { }
case 'NONE': break;
break; case 'REJECTED':
case 'DATA': {
rid = shift(); const rid = shift();
data = shift(); this.emitRejected(rid);
this._data(rid, data); }
break; break;
case 'KILLED': case 'SIGNAL':
rid = shift(); {
this._reject(rid, 'Killed'); const rid = shift();
break; this.emitSignal(rid);
case 'ERROR': }
rid = shift(); break;
err = shift(); case 'WRONG':
this._reject(rid, err); {
break; const err = shift();
case 'REJECTED': D.error(`ZMQ Protocol Error: ${err}`);
rid = shift(); }
this._reject(rid, 'Rejected'); break;
break; default:
case 'SIGNAL': D.error(`Unknown Response: ${cmd}`);
rid = shift(); return;
this._signal(rid);
break;
case 'WRONG':
err = shift();
this._error(`ZMQ Protocol Error: ${err}`);
break;
default:
this._error(`Unknown Response: ${cmd}`);
unknownResponse = true;
break;
}
} }
} finally {
if (this.queueCmd.length) this._flush();
else this._poll();
} }
} }
......
...@@ -38,6 +38,7 @@ import * as Json from 'dome/data/json'; ...@@ -38,6 +38,7 @@ import * as Json from 'dome/data/json';
import { RichTextBuffer } from 'dome/text/buffers'; import { RichTextBuffer } from 'dome/text/buffers';
import { ChildProcess } from 'child_process'; import { ChildProcess } from 'child_process';
import { client } from './client_socket'; import { client } from './client_socket';
//import { client } from './client_zmq';
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- Events // --- Events
......
...@@ -86,8 +86,7 @@ ...@@ -86,8 +86,7 @@
"node_modules", "node_modules",
"dist", "dist",
"src/dome/doc", "src/dome/doc",
"src/dome/template", "src/dome/template"
"src/frama-c/client_zmq.ts"
], ],
"typedocOptions": { "typedocOptions": {
"name": "Ivette Documentation", "name": "Ivette Documentation",
......
...@@ -1364,6 +1364,13 @@ ...@@ -1364,6 +1364,13 @@
dependencies: dependencies:
"@types/yargs-parser" "*" "@types/yargs-parser" "*"
"@types/zeromq@^5.2.1":
version "5.2.1"
resolved "https://registry.yarnpkg.com/@types/zeromq/-/zeromq-5.2.1.tgz#f4316166e90fbe01e25ec6a6efa84e9bc8f91314"
integrity sha512-B6fUT5ZanWEyKSmLLEA0K3zNPvVedrjL6LNZWAt1eOpNg0J2lw14ismPJeOrgPf3SzRuNhPReQWibHbnMrtRow==
dependencies:
"@types/node" "*"
"@typescript-eslint/eslint-plugin@": "@typescript-eslint/eslint-plugin@":
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz#efd8668b3d6627c46ce722c2afe813928fe120a0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz#efd8668b3d6627c46ce722c2afe813928fe120a0"
...@@ -6221,6 +6228,11 @@ multicast-dns@^6.0.1: ...@@ -6221,6 +6228,11 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1" dns-packet "^1.3.1"
thunky "^1.0.2" thunky "^1.0.2"
nan@2.14.2:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
nan@^2.12.1: nan@^2.12.1:
version "2.15.0" version "2.15.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
...@@ -6286,6 +6298,11 @@ node-forge@^0.10.0: ...@@ -6286,6 +6298,11 @@ node-forge@^0.10.0:
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
node-gyp-build@^4.2.3:
version "4.3.0"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
node-libs-browser@^2.2.1: node-libs-browser@^2.2.1:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
...@@ -9145,3 +9162,11 @@ yauzl@^2.10.0: ...@@ -9145,3 +9162,11 @@ yauzl@^2.10.0:
dependencies: dependencies:
buffer-crc32 "~0.2.3" buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0" fd-slicer "~1.1.0"
zeromq@^5.2.8:
version "5.2.8"
resolved "https://registry.yarnpkg.com/zeromq/-/zeromq-5.2.8.tgz#94b0b85e4152e98b8bb163f1db4a34280d44d9d0"
integrity sha512-bXzsk7KOmgLSv1tC0Ms1VXBy90+Rz27ZYf27cLuldRYbpqYpuWJfxxHFhO710t22zgWBnmdUP0m3SKFpLI0u5g==
dependencies:
nan "2.14.2"
node-gyp-build "^4.2.3"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment