Skip to content

Commit

Permalink
test(connector-sawtooth-socketio): add functional test, bug fix
Browse files Browse the repository at this point in the history
- Add functional test of all functions from sawtooth-socketio validator.
- Refactor sawtooth validator to allow importing as a module, to simplify the functional test.
- Add stopMonitor to terminate tests easily.
- Allow multiple clients to monitor for blocks.
- Fix parsing of URL from config so that it doesn't depend on trailing slash anymore.

Closes: hyperledger-cacti#2107

Depends on: hyperledger-cacti#2109
Depends on: hyperledger-cacti#2110
Depends on: hyperledger-cacti#2047

Signed-off-by: Michal Bajer <michal.bajer@fujitsu.com>
  • Loading branch information
outSH authored and petermetz committed Nov 23, 2022
1 parent 4c41218 commit 246a971
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio",
"version": "1.1.2",
"license": "Apache-2.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"start": "cd ./dist && node common/core/bin/www.js",
"debug": "nodemon --inspect ./dist/common/core/bin/www.js",
Expand All @@ -28,6 +31,9 @@
"xmlhttprequest": "1.8.0"
},
"devDependencies": {
"@hyperledger/cactus-test-tooling": "1.1.2",
"@hyperledger/cactus-common": "1.1.2",
"@hyperledger/cactus-api-client": "1.1.2",
"@types/config": "0.0.41"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

/*
* Copyright 2021 Hyperledger Cactus Contributors
* Copyright 2022 Hyperledger Cactus Contributors
* SPDX-License-Identifier: Apache-2.0
*
* www.js
Expand All @@ -16,7 +16,6 @@
*/

import app from "../app";
const debug = require("debug")("connector:server");
import https = require("https");

// Overwrite config read path
Expand All @@ -37,42 +36,8 @@ logger.level = configRead('logLevel', 'info');

// destination dependency (MONITOR) implementation class
import { ServerMonitorPlugin } from "../../../connector/ServerMonitorPlugin";
const Smonitor = new ServerMonitorPlugin();

/**
* Get port from environment and store in Express.
*/

const sslport = normalizePort(process.env.PORT || configRead('sslParam.port'));
app.set("port", sslport);

// Specify private key and certificate
const sslParam = {
key: fs.readFileSync(configRead('sslParam.key')),
cert: fs.readFileSync(configRead('sslParam.cert')),
};

/**
* Create HTTPS server.
*/

const server = https.createServer(sslParam, app); // Start as an https server.
const io = new Server(server);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(sslport, function () {
console.log("listening on *:" + sslport);
});
server.on("error", onError);
server.on("listening", onListening);

/**
* Normalize a port into a number, string, or false.
*/

// Normalize a port into a number, string, or false.
function normalizePort(val: string) {
const port = parseInt(val, 10);

Expand All @@ -89,65 +54,108 @@ function normalizePort(val: string) {
return false;
}

/**
* Event listener for HTTPS server "error" event.
*/

function onError(error: any) {
if (error.syscall !== "listen") {
throw error;
export async function startSawtoothSocketIOConnector() {
const Smonitor = new ServerMonitorPlugin();

// Get port from environment and store in Express.
const sslport = normalizePort(process.env.PORT || configRead('sslParam.port'));
app.set("port", sslport);

// Specify private key and certificate
let keyString: string;
let certString: string;
try {
keyString = configRead<string>('sslParam.keyValue');
certString = configRead<string>('sslParam.certValue');
} catch {
keyString = fs.readFileSync(configRead('sslParam.key'), "ascii");
certString = fs.readFileSync(configRead('sslParam.cert'), "ascii");
}

const bind =
typeof sslport === "string" ? "Pipe " + sslport : "Port " + sslport;
// Create HTTPS server.
const server = https.createServer({
key: keyString,
cert: certString,
}, app); // Start as an https server.
const io = new Server(server);

// handle specific listen errors with friendly messages
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges");
process.exit(1);
break;
case "EADDRINUSE":
console.error(bind + " is already in use");
process.exit(1);
break;
default:
// Event listener for HTTPS server "error" event.
server.on("error", (error: any) => {
if (error.syscall !== "listen") {
throw error;
}
}
}

const bind =
typeof sslport === "string" ? "Pipe " + sslport : "Port " + sslport;

// handle specific listen errors with friendly messages
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges");
process.exit(1);
case "EADDRINUSE":
console.error(bind + " is already in use");
process.exit(1);
default:
throw error;
}
});

/**
* Event listener for HTTPS server "listening" event.
*/
io.on("connection", function (client) {
logger.info("Client " + client.id + " connected.");

function onListening() {
const addr = server.address();
// startMonitor: starting block generation event monitoring
client.on("startMonitor", function (data) {

if (!addr) {
logger.error("Could not get running server address - exit.");
process.exit(1);
}
if (!data || !data.filterKey) {
client.emit("error", {
status: 400,
errorDetail: "filterKey is required for startMonitor on sawtooth ledger",
});
}

const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
debug("Listening on " + bind);
}
Smonitor.startMonitor(client.id, data.filterKey, (callbackData) => {
let emitType = "";
if (callbackData.status == 200) {
emitType = "eventReceived";
logger.info("event data callbacked.");
} else {
emitType = "monitor_error";
}
client.emit(emitType, callbackData);
});
});

io.on("connection", function (client) {
logger.info("Client " + client.id + " connected.");

/**
* startMonitor: starting block generation event monitoring
**/
client.on("startMonitor", function (data) {
Smonitor.startMonitor(client.id, data.filterKey, (callbackData) => {
let emitType = "";
if (callbackData.status == 200) {
emitType = "eventReceived";
logger.info("event data callbacked.");
} else {
emitType = "monitor_error";
}
client.emit(emitType, callbackData);

client.on("stopMonitor", function () {
Smonitor.stopMonitor(client.id);
});

client.on("disconnect", function (reason) {
logger.info("Client " + client.id + " disconnected.");
logger.info("Reason :" + reason);
// Stop monitoring if disconnected client is for event monitoring
Smonitor.stopMonitor(client.id);
});
});

// Listen on provided port, on all network interfaces.
return new Promise<https.Server>((resolve) => server.listen(sslport, () => resolve(server)));
}

if (require.main === module) {
// When this file executed as a script, not loaded as module - run the connector
startSawtoothSocketIOConnector().then((server) => {
const addr = server.address();

if (!addr) {
logger.error("Could not get running server address - exit.");
process.exit(1);
}

const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
logger.debug("Listening on " + bind);
}).catch((err) => {
logger.error("Could not start sawtooth-socketio connector:", err);
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,8 @@ export type MonitorCallback = (callback: {
* Class definitions of server monitoring
*/
export class ServerMonitorPlugin {
currentBlockNumber: number;

/*
* constructors
*/
constructor() {
// Define dependent specific settings
this.currentBlockNumber = -1;
}
currentBlockNumber = -1;
runningMonitors = new Map<string, ReturnType<typeof setInterval>>();

/*
* startMonitor
Expand All @@ -62,12 +55,20 @@ export class ServerMonitorPlugin {
logger.debug(`responseObj = ${JSON.stringify(responseObj)}`);
logger.debug(`currentBlockNumber = ${that.currentBlockNumber}`);
that.periodicMonitoring(clientId, filterKey, cb);
};
}

const method = configRead<string>("blockMonitor.request.method");
const latestBlockURL = new URL(
configRead<string>("blockMonitor.request.getLatestBlockNumberCommand"),
configRead<string>("blockMonitor.request.host"))
.toString();
logger.debug("latestBlockURL:", latestBlockURL);

httpReq.open(
configRead<string>("blockMonitor.request.method"),
configRead<string>("blockMonitor.request.host") +
configRead<string>("blockMonitor.request.getLatestBlockNumberCommand"),
method,
latestBlockURL,
);

httpReq.send();
}

Expand Down Expand Up @@ -135,7 +136,12 @@ export class ServerMonitorPlugin {
status: 200,
blockData: signedTransactionDataArray,
};
cb(retObj);

if (that.runningMonitors.has(clientId)) {
cb(retObj);
} else {
logger.info("Monitoring seems to be stopped - don't send the response! ClientID:", clientId);
}
}
}

Expand All @@ -144,15 +150,36 @@ export class ServerMonitorPlugin {
}
logger.debug(`currentBlockNumber = ${that.currentBlockNumber}`);
};

const timerBlockMonitoring = setInterval(function () {
const callURL =
configRead<string>("blockMonitor.request.host") +
const newBlocksPath =
configRead<string>("blockMonitor.request.periodicMonitoringCommand1") +
SplugUtil.convertBlockNumber(that.currentBlockNumber) +
configRead<string>("blockMonitor.request.periodicMonitoringCommand2");
logger.debug(`call URL = ${callURL}`);
httpReq.open(configRead<string>("blockMonitor.request.method"), callURL);
const newBlocksUrl = new URL(
newBlocksPath,
configRead<string>("blockMonitor.request.host"))
.toString();
logger.debug(`newBlocksUrl = ${newBlocksUrl}`);

httpReq.open(configRead<string>("blockMonitor.request.method"), newBlocksUrl);
httpReq.send();
}, configRead("blockMonitor.pollingInterval"));

this.runningMonitors.set(clientId, timerBlockMonitoring);
}

/**
* Stop monitor for given client.
*
* @param {string} clientId: Client ID from which monitoring stop request was made
*/
stopMonitor(clientId: string) {
let monitorInterval = this.runningMonitors.get(clientId);
if (monitorInterval) {
logger.info("stop watching and remove interval.");
clearInterval(monitorInterval);
this.runningMonitors.delete(clientId);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./public-api";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { startSawtoothSocketIOConnector } from "./common/core/bin/www"
Loading

0 comments on commit 246a971

Please sign in to comment.