Skip to content

Commit

Permalink
Merge pull request Superalgos#5175 from MarkTradeink/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Awhiteweb authored Nov 19, 2024
2 parents 36469b2 + 31e5b79 commit f167e76
Show file tree
Hide file tree
Showing 46 changed files with 1,438 additions and 298 deletions.
2 changes: 1 addition & 1 deletion DashboardsRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async function runRoot() {
/*
Version Management
*/
SA.version = "Alpha 1"
SA.version = "Alpha 1.1"

let mode
for (let i = 0; i < process.argv.length; i++) {
Expand Down
1 change: 1 addition & 0 deletions Platform/Client/Http-Routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ exports.newHttpRoutes = function newHttpRoutes() {
require('./icons').newIconsRoute(),
require('./images').newImagesRoute(),
require('./legacy-plotter').newLegacyPlotterRoute(),
require('./launch-dashboards').newLaunchDashboardsRoute(),
require('./list-function-libraries').newListFunctionLibrariesRoute(),
require('./list-global-files').newListGlobalFilesRoute(),
require('./list-node-action-functions').newListNodeActionFunctionsRoute(),
Expand Down
48 changes: 48 additions & 0 deletions Platform/Client/Http-Routes/launch-dashboards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
exports.newLaunchDashboardsRoute = function newLaunchDashboardsRoute() {
const thisObject = {
endpoint: 'Launch-Dashboards',
command: command
};

return thisObject;

function command(httpRequest, httpResponse) {
const child_process = require('child_process');

// Execute the dashboards app
try {
child_process.exec('node dashboards minMemo', (error, stdout, stderr) => {
if (error) {
console.error(`[ERROR] Failed to execute the command: ${error.message}`);
respondWithError(httpResponse, `[ERROR] ${error.message}`);
return;
}
if (stderr) {
console.error(`[ERROR] Command error output: ${stderr}`);
respondWithError(httpResponse, `[ERROR] ${stderr}`);
return;
}

console.log(`[INFO] Command executed successfully: ${stdout}`);
respondWithSuccess(httpResponse, `[INFO] Dashboards launched successfully.`);
});
} catch (err) {
console.error('[ERROR] Launch Dashboards:', err);
respondWithError(httpResponse, 'Failed to launch Dashboards');
}
}

function respondWithError(httpResponse, message) {
SA.projects.foundations.utilities.httpResponses.respondWithContent(
JSON.stringify({ result: 'Fail', message }),
httpResponse
);
}

function respondWithSuccess(httpResponse, message) {
SA.projects.foundations.utilities.httpResponses.respondWithContent(
JSON.stringify({ result: 'Success', message }),
httpResponse
);
}
};
184 changes: 115 additions & 69 deletions Platform/Client/dashboardsInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
/* This file holds the interface that aggregates metrics and any other system data
and then sends it over websocket to the Dashboards App */

// todo: refactor eventserver client to it's own file
// todo: events server dashboard
// todo: tasks manager dashboard
// todo: create generic dashboard reporter function that can be drop into any place within the platform
// todo: make dashboard reporter function able to be interval or event based
// todo: connect dashboard interface when dashboard app is started second
// todo: set up dashboards project to hold function libraries
// todo: add platform menu to launch dashboards app
// todo: create dashboards reporter node to allow control of dashboard reporting from platform UI
// todo: refactor eventserver client to it's own file (in progress)
// todo: events server dashboard (in progress)
// todo: tasks manager dashboard (in progress)
// todo: create generic dashboard reporter function that can be drop into any place within the platform (in progress)
// todo: make dashboard reporter function able to be interval or event based (in progress) (Added to Schemas; Report Timer and Report Conditions/Formula)
// todo: connect dashboard interface when dashboard app is started second (in progress)
// todo: set up dashboards project to hold function libraries (in progress)
// todo: add platform menu to launch dashboards app (done via API)
// todo: create dashboards reporter node to allow control of dashboard reporting from platform UI (in progress)

// Marktradeink NOTES: Created Dashboards Project > Dashboards Manager Bot (here you can add Dashboards Bots as many as you want), Each Bot will send a report to Dashboards App. So you can individually reference Report Nodes to the Dashboards Bot you want.
// Example: Strategy #1 will send a Report via Dashboards Bot #1


let thisObject = {
Expand All @@ -19,14 +22,14 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
run: run
}

const WEB_SOCKET = SA.nodeModules.ws
let socketClient
let port = global.env.DASHBOARDS_WEB_SOCKETS_INTERFACE_PORT
let url = 'ws://localhost:'+ port
let eventsServerClient = PL.servers.TASK_MANAGER_SERVER.newEventsServerClient()
const WEB_SOCKET = SA.nodeModules.ws;
let socketClient;
let port = global.env.DASHBOARDS_WEB_SOCKETS_INTERFACE_PORT;
let url = 'ws://localhost:'+ port;
let eventsServerClient = PL.servers.TASK_MANAGER_SERVER.newEventsServerClient();
let messageQueue = [];
//const path = require('path');


return thisObject

function initialize () {
Expand All @@ -41,6 +44,7 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
setUpWebSocketClient(url)

} else if (response.event.isRunning === false) {
SA.logger.warn('[WARN] Dashboards App is not running.');
//Skip websocket client initalization
//SA.logger.info('')
//SA.logger.info(response.event.message)
Expand Down Expand Up @@ -101,76 +105,111 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
}

function finalize() {
socketClient = undefined
if (socketClient) {
socketClient.terminate(); // Termina cualquier conexión existente
socketClient = undefined;
}
}

async function run() {

checkDashboardAppStatus(port, statusResponse)
// Verifica el estado del Dashboard cada 10 segundos hasta que esté corriendo
const interval = setInterval(() => {
checkDashboardAppStatus(port, statusResponse);
}, 10000); // Reintentar cada 10 segundos

function statusResponse(status, message) {
let event = {
isRunning: status,
message: message
}
eventsServerClient.raiseEvent("Dashboard Manager", 'Dashboard App Status', event)
if (status) {
clearInterval(interval); // Detiene los intentos cuando el Dashboard está corriendo
let event = {
isRunning: status,
message: message
};
eventsServerClient.raiseEvent("Dashboard Manager", 'Dashboard App Status', event);
setUpWebSocketClient(url);
} else {
SA.logger.warn(`[WARN] ${message}`);
}
}
}

async function checkDashboardAppStatus(port, callbackFunc) {
var net = require('net')
var tester = net.createServer()
.once('error', function (err) {
if (err.code != 'EADDRINUSE') {
callbackFunc(err)
} else {
callbackFunc(true, 'Dashboard App Interface is Running!')
}
})
.once('listening', function() {
tester.once('close', function() {
callbackFunc(false, 'Dashboard App is not Running... Pausing Interface.')
const net = require('net');
const tester = net.createServer()
.once('error', function (err) {
if (err.code !== 'EADDRINUSE') {
callbackFunc(false, '[ERROR] Unexpected error checking Dashboard status.');
} else {
callbackFunc(true, '[INFO] Dashboard App Interface is Running!');
}
})
.close()
})
.listen(port)
.once('listening', function () {
tester.once('close', function () {
// callbackFunc(false, '[WARN] Dashboard App is not Running... Pausing Interface.');
}).close();
})
.listen(port);
}


function setUpWebSocketClient(url) {
socketClient = new WEB_SOCKET.WebSocket(url)

socketClient.on('open', function (open) {
socketClient.on('open', function () {
SA.logger.info('[INFO] WebSocket connection established.');
let message = (new Date()).toISOString() + '|*|Platform|*|Info|*|Platform Dashboards Client has been Opened'
socketClient.send(message)

//sendExample()
//sendGlobals()
// Resend every 10 minutes
//setInterval(sendGlobals, 6000)
//sendGovernance()

sendSimulationData();
sendCandlesData();
//sendOutputData();
setInterval(sendSimulationData, 60000);
setInterval(sendCandlesData, 60000);
// setInterval(sendOutputData, 60000);
});

socketClient.on('close', function (close) {
SA.logger.info('[INFO] Dashboard App has been disconnected.')
})
while (messageQueue.length > 0) {
const message = messageQueue.shift();
socketClient.send(message);
}

startSendingData();
});

socketClient.on('close', function () {
SA.logger.warn('[WARN] WebSocket connection closed. Attempting to reconnect...');
retryConnection();
});

socketClient.on('error', function (error) {
SA.logger.error('[ERROR] Dashboards Client error: ', error.message, error.stack)
SA.logger.error(`[ERROR] Dashboards Client error: ${error.message}`);
retryConnection();
});

socketClient.on('message', function (message) {
SA.logger.info('This is a message coming from the Dashboards App', message)
});
}

async function sendSimulationData() {
function retryConnection() {
if (socketClient) {
socketClient.terminate(); // Asegura que la conexión previa esté cerrada
}

setTimeout(() => {
SA.logger.info(`[INFO] Attempting to reconnect to Dashboards App...`);
setUpWebSocketClient(url);
}, 5000); // Reintenta cada 5 segundos
}

function startSendingData() {
// Enviar datos periódicamente solo después de que la conexión esté abierta
//sendExample()
//sendGlobals()
// Resend every 10 minutes
//setInterval(sendGlobals, 6000)
//sendGovernance()

sendSimulationData();
sendCandlesData();
//sendOutputData();
setInterval(sendSimulationData, 60000);
setInterval(sendCandlesData, 60000);
// setInterval(sendOutputData, 60000);
}

async function sendSimulationData() {
const fs = require('fs').promises;
const path = require('path');

Expand Down Expand Up @@ -206,18 +245,16 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
}

jsonData.reportPath = reportPath; // Agrega el path del reporte

//SA.logger.info('Data to send (before stringifying):', jsonData);

// Serializar jsonData a una cadena JSON
const jsonDataString = JSON.stringify(jsonData);

// Construir el mensaje a enviar
const messageToSend = `${new Date().toISOString()}|*|Platform|*|Data|*|SimulationResult|*|${jsonDataString}`;

//SA.logger.info('Message send from:', JSON.stringify(reportPath));

socketClient.send(messageToSend);

if (socketClient.readyState === WEB_SOCKET.OPEN) {
socketClient.send(messageToSend);
} else {
// Si la conexión aún no está abierta, almacena el mensaje en la cola
messageQueue.push(messageToSend);
SA.logger.warn('[WARN] WebSocket is not open. Message queued.');
}
}
} catch (error) {
console.error('Error processing simulation data:', error);
Expand Down Expand Up @@ -319,8 +356,17 @@ exports.newDashboardsInterface = function newDashboardsInterface() {
exchangePair,
candleData,
};

let messageToSend = `${new Date().toISOString()}|*|Platform|*|Data|*|CandlesData|*|${JSON.stringify(filteredData)}`;
socketClient.send(messageToSend);

if (socketClient.readyState === WEB_SOCKET.OPEN) {
socketClient.send(messageToSend);
} else {
// Si la conexión aún no está abierta, almacena el mensaje en la cola
messageQueue.push(messageToSend);
SA.logger.warn('[WARN] WebSocket is not open. Message queued.');
}

//SA.logger.info(`Candles data sent from SA to Dashboard for ${exchangePair}`);
//SA.logger.info(`Candles data sent from SA to Dashboard for ${messageToSend}`);
}
Expand Down
5 changes: 5 additions & 0 deletions Platform/WebServer/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,12 @@
"slackBot": "Add Slack Bot",
"discordBot": "Add Discord Bot",
"telegramBot": "Add Telegram Bot",
"dashboardsBot": "Add Dashboards Bot",
"dashboardsBotManager": "Add Dashboards Bot Manager",
"announcementCondition": "Add Announcement Condition",
"announcementFormula": "Add Announcement Formula",
"reportCondition": "Add Report Condition",
"reportFormula": "Add Report Formula",
"portfolioBot": "Add Portfolio Bot",
"projectPortfolioProducts": "Add Project Portfolio Products",
"allPortfolioMineProducts": "Add All Portfolio Mine Products",
Expand Down Expand Up @@ -425,6 +429,7 @@
"projectDashboards": "Add Project Dashboards",
"point": "Add Point",
"announcement": "Add Announcement",
"report": "Add Report",
"situation": "Add Situation",
"askPortfolioManager": "Add Ask Portfolio Manager",
"procedureInitialization": "Add Procedure Initialization",
Expand Down
Loading

0 comments on commit f167e76

Please sign in to comment.